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