xref: /aosp_15_r20/external/libkmsxx/kms++/src/dmabufframebuffer.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1 
2 #include <cstring>
3 #include <cerrno>
4 
5 #include <stdexcept>
6 #include <sys/mman.h>
7 #include <sys/ioctl.h>
8 #include <xf86drm.h>
9 #include <xf86drmMode.h>
10 #include <linux/dma-buf.h>
11 
12 #include <kms++/kms++.h>
13 
14 using namespace std;
15 
16 namespace kms
17 {
DmabufFramebuffer(Card & card,uint32_t width,uint32_t height,const string & format,vector<int> fds,vector<uint32_t> pitches,vector<uint32_t> offsets,vector<uint64_t> modifiers)18 DmabufFramebuffer::DmabufFramebuffer(Card& card, uint32_t width, uint32_t height, const string& format,
19 				     vector<int> fds, vector<uint32_t> pitches, vector<uint32_t> offsets, vector<uint64_t> modifiers)
20 	: DmabufFramebuffer(card, width, height, FourCCToPixelFormat(format), fds, pitches, offsets, modifiers)
21 {
22 }
23 
DmabufFramebuffer(Card & card,uint32_t width,uint32_t height,PixelFormat format,vector<int> fds,vector<uint32_t> pitches,vector<uint32_t> offsets,vector<uint64_t> modifiers)24 DmabufFramebuffer::DmabufFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format,
25 				     vector<int> fds, vector<uint32_t> pitches, vector<uint32_t> offsets, vector<uint64_t> modifiers)
26 	: Framebuffer(card, width, height)
27 {
28 	int r;
29 
30 	m_format = format;
31 
32 	const PixelFormatInfo& format_info = get_pixel_format_info(format);
33 
34 	m_num_planes = format_info.num_planes;
35 
36 	if (fds.size() != m_num_planes || pitches.size() != m_num_planes || offsets.size() != m_num_planes)
37 		throw std::invalid_argument("the size of fds, pitches and offsets has to match number of planes");
38 
39 	for (int i = 0; i < format_info.num_planes; ++i) {
40 		FramebufferPlane& plane = m_planes.at(i);
41 
42 		plane.prime_fd = fds[i];
43 
44 		r = drmPrimeFDToHandle(card.fd(), fds[i], &plane.handle);
45 		if (r)
46 			throw invalid_argument(string("drmPrimeFDToHandle: ") + strerror(errno));
47 
48 		plane.stride = pitches[i];
49 		plane.offset = offsets[i];
50 		plane.modifier = modifiers.empty() ? 0 : modifiers[i];
51 		plane.size = plane.stride * height;
52 		plane.map = 0;
53 	}
54 
55 	uint32_t id;
56 	uint32_t bo_handles[4] = { m_planes[0].handle, m_planes[1].handle, m_planes[2].handle, m_planes[3].handle };
57 	pitches.resize(4);
58 	offsets.resize(4);
59 
60 	if (modifiers.empty()) {
61 		r = drmModeAddFB2(card.fd(), width, height, (uint32_t)format,
62 				  bo_handles, pitches.data(), offsets.data(), &id, 0);
63 		if (r)
64 			throw invalid_argument(string("drmModeAddFB2 failed: ") + strerror(errno));
65 	} else {
66 		modifiers.resize(4);
67 		r = drmModeAddFB2WithModifiers(card.fd(), width, height, (uint32_t)format,
68 					       bo_handles, pitches.data(), offsets.data(), modifiers.data(), &id, DRM_MODE_FB_MODIFIERS);
69 		if (r)
70 			throw invalid_argument(string("drmModeAddFB2WithModifiers failed: ") + strerror(errno));
71 	}
72 
73 	set_id(id);
74 }
75 
~DmabufFramebuffer()76 DmabufFramebuffer::~DmabufFramebuffer()
77 {
78 	drmModeRmFB(card().fd(), id());
79 }
80 
map(unsigned plane)81 uint8_t* DmabufFramebuffer::map(unsigned plane)
82 {
83 	FramebufferPlane& p = m_planes.at(plane);
84 
85 	if (p.map)
86 		return p.map;
87 
88 	p.map = (uint8_t*)mmap(0, p.size, PROT_READ | PROT_WRITE, MAP_SHARED,
89 			       p.prime_fd, 0);
90 	if (p.map == MAP_FAILED)
91 		throw invalid_argument(string("mmap failed: ") + strerror(errno));
92 
93 	return p.map;
94 }
95 
prime_fd(unsigned plane)96 int DmabufFramebuffer::prime_fd(unsigned plane)
97 {
98 	FramebufferPlane& p = m_planes.at(plane);
99 
100 	return p.prime_fd;
101 }
102 
begin_cpu_access(CpuAccess access)103 void DmabufFramebuffer::begin_cpu_access(CpuAccess access)
104 {
105 	if (m_sync_flags != 0)
106 		throw runtime_error("begin_cpu sync already started");
107 
108 	switch (access) {
109 	case CpuAccess::Read:
110 		m_sync_flags = DMA_BUF_SYNC_READ;
111 		break;
112 	case CpuAccess::Write:
113 		m_sync_flags = DMA_BUF_SYNC_WRITE;
114 		break;
115 	case CpuAccess::ReadWrite:
116 		m_sync_flags = DMA_BUF_SYNC_RW;
117 		break;
118 	}
119 
120 	dma_buf_sync dbs{
121 		.flags = DMA_BUF_SYNC_START | m_sync_flags
122 	};
123 
124 	for (uint32_t p = 0; p < m_num_planes; ++p) {
125 		int r = ioctl(prime_fd(p), DMA_BUF_IOCTL_SYNC, &dbs);
126 		if (r)
127 			throw runtime_error("DMA_BUF_IOCTL_SYNC failed");
128 	}
129 }
130 
end_cpu_access()131 void DmabufFramebuffer::end_cpu_access()
132 {
133 	if (m_sync_flags == 0)
134 		throw runtime_error("begin_cpu sync not started");
135 
136 	dma_buf_sync dbs{
137 		.flags = DMA_BUF_SYNC_END | m_sync_flags
138 	};
139 
140 	for (uint32_t p = 0; p < m_num_planes; ++p) {
141 		int r = ioctl(prime_fd(p), DMA_BUF_IOCTL_SYNC, &dbs);
142 		if (r)
143 			throw runtime_error("DMA_BUF_IOCTL_SYNC failed");
144 	}
145 
146 	m_sync_flags = 0;
147 }
148 
149 } // namespace kms
150