1 #define DMABUF_PLANES_LIMIT 4
2 
helper_bo_dmabuf(struct agp_fenv * agp_fenv,struct egl_env * agp_eglenv,struct gbm_device * dev,EGLDisplay dpy,size_t w,size_t h,int fmt,struct gbm_bo * bo,struct shmifext_buffer_plane * planes,size_t * n_planes)3 static bool helper_bo_dmabuf(
4 	struct agp_fenv* agp_fenv,
5 	struct egl_env* agp_eglenv,
6 	struct gbm_device* dev,
7 	EGLDisplay dpy,
8 	size_t w, size_t h, int fmt,
9 	struct gbm_bo* bo,
10 	struct shmifext_buffer_plane* planes, size_t* n_planes)
11 {
12 /* sooo - in order to convert the bo to an eglimage so that we can import it
13  * into GL we first extract planes / strides / meta-data then re-package as
14  * the corresponding EGL bits */
15 
16 	size_t np = gbm_bo_get_plane_count(bo);
17 	if (np > DMABUF_PLANES_LIMIT)
18 		return NULL;
19 
20 	uint64_t mod = gbm_bo_get_modifier(bo);
21 	planes[0].w = w;
22 	planes[0].h = h;
23 
24 	uint32_t mod_hi = mod >> 32;
25 	uint32_t mod_lo = mod & 0xffffffff;
26 
27 	for (size_t i = 0; i < np; i++){
28 		union gbm_bo_handle h = gbm_bo_get_handle_for_plane(bo, i);
29 		struct drm_prime_handle prime =
30 			{.handle = h.u32, .flags = DRM_RDWR | DRM_CLOEXEC};
31 
32 /* mighty curious what happens if you say - authenticate to a card-node via
33  * wl_drm and just sweep all possible GEM values .. */
34 		if (-1 == ioctl(gbm_device_get_fd(dev), DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime))
35 			goto cleanup;
36 
37 		planes[i].gbm.stride = gbm_bo_get_stride_for_plane(bo, i);
38 		planes[i].gbm.offset = gbm_bo_get_offset(bo, i);
39 		planes[i].gbm.format = fmt;
40 		planes[i].fd = prime.fd;
41 		planes[i].gbm.mod_hi = mod_hi;
42 		planes[i].gbm.mod_lo = mod_lo;
43 	}
44 
45 	*n_planes = np;
46 	return true;
47 
48 cleanup:
49 	for (size_t i = 0; i < np; i++)
50 		if (-1 != planes[i].fd)
51 			close(planes[i].fd);
52 	return false;
53 }
54 
55 static int dma_fd_constants[] = {
56 	EGL_DMA_BUF_PLANE0_FD_EXT,
57 	EGL_DMA_BUF_PLANE1_FD_EXT,
58 	EGL_DMA_BUF_PLANE2_FD_EXT,
59 	EGL_DMA_BUF_PLANE3_FD_EXT
60 };
61 
62 static int dma_offset_constants[] = {
63 	EGL_DMA_BUF_PLANE0_OFFSET_EXT,
64 	EGL_DMA_BUF_PLANE1_OFFSET_EXT,
65 	EGL_DMA_BUF_PLANE2_OFFSET_EXT,
66 	EGL_DMA_BUF_PLANE3_OFFSET_EXT
67 };
68 
69 static int dma_pitch_constants[] = {
70 	EGL_DMA_BUF_PLANE0_PITCH_EXT,
71 	EGL_DMA_BUF_PLANE1_PITCH_EXT,
72 	EGL_DMA_BUF_PLANE2_PITCH_EXT,
73 	EGL_DMA_BUF_PLANE3_PITCH_EXT
74 };
75 
76 static int dma_mod_constants[] = {
77 	EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
78 	EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
79 	EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
80 	EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
81 	EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
82 	EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
83 	EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
84 	EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
85 };
86 
helper_dmabuf_eglimage(struct agp_fenv * agp,struct egl_env * egl,EGLDisplay dpy,struct shmifext_buffer_plane * planes,size_t n_planes)87 static EGLImage helper_dmabuf_eglimage(
88 	struct agp_fenv* agp, struct egl_env* egl,
89 	EGLDisplay dpy,
90 	struct shmifext_buffer_plane* planes, size_t n_planes)
91 {
92 	size_t n_attr = 0;
93 	EGLint attrs[64] = {};
94 
95 #define ADD_ATTR(X, Y) { attrs[n_attr++] = (X); attrs[n_attr++] = (Y); }
96 	ADD_ATTR(EGL_WIDTH, planes[0].w);
97 	ADD_ATTR(EGL_HEIGHT, planes[0].h);
98 	ADD_ATTR(EGL_LINUX_DRM_FOURCC_EXT, planes[0].gbm.format);
99 
100 	uint64_t mod =
101 		((uint64_t)planes[0].gbm.mod_hi << (uint64_t)32) |
102 		(uint64_t)(planes[0].gbm.mod_lo);
103 
104 	for (size_t i = 0; i < n_planes; i++){
105 		ADD_ATTR(dma_fd_constants[i], planes[i].fd);
106 		ADD_ATTR(dma_offset_constants[i], planes[i].gbm.offset);
107 		ADD_ATTR(dma_pitch_constants[i], planes[i].gbm.stride);
108 
109 		if (mod != DRM_FORMAT_MOD_INVALID && mod != DRM_FORMAT_MOD_LINEAR){
110 			ADD_ATTR(dma_mod_constants[i*2+0], planes[i].gbm.mod_hi);
111 			ADD_ATTR(dma_mod_constants[i*2+1], planes[i].gbm.mod_lo);
112 		}
113 	}
114 
115 	ADD_ATTR(EGL_NONE, EGL_NONE);
116 #undef ADD_ATTR
117 
118 	EGLImage img =
119 		egl->create_image(dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs);
120 
121 /* egl dups internally, otherwise the handles are useless anyhow */
122 	for (size_t i = 0; i < n_planes; i++)
123 		close(planes[i].fd);
124 
125 	return img;
126 }
127 
helper_eglimage_color(struct agp_fenv * agp,struct egl_env * egl,EGLImage img,unsigned * id)128 static void helper_eglimage_color(
129 	struct agp_fenv* agp, struct egl_env* egl, EGLImage img, unsigned* id)
130 {
131 	if (!(*id)){
132 		agp->gen_textures(1, id);
133 		agp->active_texture(GL_TEXTURE0);
134 		agp->bind_texture(GL_TEXTURE_2D, *id);
135 		agp->tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
136 		agp->tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137 		agp->tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
138 		agp->tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
139 	}
140 	else {
141 		agp->bind_texture(GL_TEXTURE_2D, *id);
142 	}
143 
144 	egl->image_target_texture2D(GL_TEXTURE_2D, img);
145 	agp->bind_texture(GL_TEXTURE_2D, 0);
146 }
147 
helper_alloc_color(struct agp_fenv * agp,struct egl_env * egl,struct gbm_device * dev,EGLDisplay dpy,struct shmifext_color_buffer * out,size_t buf_w,size_t buf_h,int fmt,int hints,size_t n_modifiers,uint64_t * modifiers)148 static bool helper_alloc_color(
149 	struct agp_fenv* agp, struct egl_env* egl,
150 	struct gbm_device* dev, EGLDisplay dpy,
151 	struct shmifext_color_buffer* out,
152 	size_t buf_w, size_t buf_h, int fmt, int hints,
153 	size_t n_modifiers, uint64_t* modifiers)
154 {
155 /* this should really be picked from the shmif-flags though, if proto for VR is
156  * set, we go FP16, if it is for DEEP go 101010, if we are embedded constrained
157  * go 565 - this includes picking right alpha format */
158 
159 	struct gbm_bo* bo;
160 	if (n_modifiers)
161 		bo = gbm_bo_create_with_modifiers(dev, buf_w, buf_h, fmt, modifiers, n_modifiers);
162 	else {
163 		int use_hint = GBM_BO_USE_RENDERING;
164 		if (hints == 4)
165 			use_hint |= GBM_BO_USE_SCANOUT;
166 
167 		bo = gbm_bo_create(dev, buf_w, buf_h, fmt, use_hint);
168 	}
169 
170 /* got a buffer object that matches the desired display properties, repack */
171 	out->alloc_tags[0] = bo;
172 	if (!bo)
173 		return false;
174 
175 	struct shmifext_buffer_plane planes[DMABUF_PLANES_LIMIT];
176 	size_t n_planes = DMABUF_PLANES_LIMIT;
177 
178 	if (!helper_bo_dmabuf(agp, egl,
179 		dev, dpy, buf_w, buf_h, fmt, bo, planes, &n_planes)){
180 		gbm_bo_destroy(bo);
181 		return false;
182 	}
183 
184 /* we now have a dma-buf in planes, into EGL we go - plane fds are closed */
185 	EGLImage img =
186 		helper_dmabuf_eglimage(agp, egl, dpy, planes, n_planes);
187 	if (!img){
188 		gbm_bo_destroy(bo);
189 		return false;
190 	}
191 
192 /* remember egl image for destruction later */
193 	out->alloc_tags[1] = img;
194 
195 /* last stage- build a color attachment that uses our new fresh img */
196 	helper_eglimage_color(agp, egl, img, &out->id.gl);
197 	return true;
198 }
199