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