1 #include "e_linux_dmabuf_intern.h"
2 #include "e_comp_screen_intern.h"
3 #include "e_comp_intern.h"
7 #include <libds/linux_dmabuf_v1.h>
9 #include <EGL/eglext.h>
10 #include <drm_fourcc.h>
11 #include <libds/util/addon.h>
12 #include <libds/types/ds_buffer.h>
14 #ifndef EGL_EXT_image_dma_buf_import_modifiers
15 #define EGL_EXT_image_dma_buf_import_modifiers 1
16 #define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
17 #define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
18 #define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
19 #define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
20 #define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
21 #define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
22 #define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
23 #define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
24 #define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
25 #define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
26 #define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
27 typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
28 typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
29 #ifdef EGL_EGLEXT_PROTOTYPES
30 EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
31 EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
33 #endif /* EGL_EXT_image_dma_buf_import_modifiers */
35 typedef struct _E_Linux_Dmabuf E_Linux_Dmabuf;
36 typedef struct _E_Linux_Dmabuf_Buffer E_Linux_Dmabuf_Buffer;
38 static E_Linux_Dmabuf *_dmabuf = NULL;
40 struct _E_Linux_Dmabuf
42 struct ds_linux_dmabuf_v1 *ds_dmabuf;
45 struct wl_listener display_destroy;
48 EGLDisplay egl_display;
49 PFNEGLQUERYDMABUFFORMATSEXTPROC query_dmabuf_formats;
51 struct ds_linux_dmabuf_v1_format *supported_formats;
55 struct _E_Linux_Dmabuf_Buffer
57 struct ds_buffer *ds_buffer;
58 struct ds_addon ds_buffer_addon;
60 tbm_surface_h tsurface;
64 _e_linux_dmabuf_cb_display_destroy(struct wl_listener *listener, void *data)
66 E_Linux_Dmabuf *dmabuf;
68 dmabuf = wl_container_of(listener, dmabuf, listener.display_destroy);
69 wl_list_remove(&dmabuf->listener.display_destroy.link);
70 free(dmabuf->supported_formats);
75 _e_linux_dmabuf_extension_check(const char *extensions, const char *extension)
77 size_t extlen = strlen(extension);
78 const char *end = extensions + strlen(extensions);
80 while (extensions < end)
84 /* Skip whitespaces, if any */
85 if (*extensions == ' ')
91 n = strcspn(extensions, " ");
94 if (n == extlen && strncmp(extension, extensions, n) == 0)
104 _e_linux_dmabuf_egl_format_get(E_Linux_Dmabuf *dmabuf, size_t *num_formats)
109 if (!dmabuf->query_dmabuf_formats(dmabuf->egl_display, 0, NULL, &num))
111 ERR("fail to eglQueryDmaBufFormatsEXT");
115 formats = E_NEW(int, num);
116 EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL);
118 if (!dmabuf->query_dmabuf_formats(dmabuf->egl_display, num, formats, &num))
120 ERR("fail to eglQueryDmaBufFormatsEXT");
131 _e_linux_dmabuf_egl_format_init(E_Linux_Dmabuf *dmabuf)
133 const char *extensions = NULL;
135 if (!e_comp_gl_get()) return EINA_FALSE;
137 dmabuf->egl_display = eglGetCurrentDisplay();
138 if (!dmabuf->egl_display) return EINA_FALSE;
140 extensions = (const char *)eglQueryString(dmabuf->egl_display, EGL_EXTENSIONS);
141 if (!extensions) return EINA_FALSE;
143 if (!_e_linux_dmabuf_extension_check(extensions, "EGL_EXT_image_dma_buf_import_modifiers"))
146 dmabuf->query_dmabuf_formats = (void *)eglGetProcAddress("eglQueryDmaBufFormatsEXT");
147 if (!dmabuf->query_dmabuf_formats) return EINA_FALSE;
152 static struct ds_linux_dmabuf_v1_format *
153 _e_linux_dmabuf_supported_format_get(E_Linux_Dmabuf *dmabuf, int *num_formats)
155 struct ds_linux_dmabuf_v1_format *formats;
156 static int fallback_formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
157 static uint64_t fallback_modifier = DRM_FORMAT_MOD_LINEAR;
162 if (!_e_linux_dmabuf_egl_format_init(dmabuf))
163 goto fallback_formats;
165 egl_formats = _e_linux_dmabuf_egl_format_get(dmabuf, &num);
166 if (!egl_formats) goto fallback_formats;
168 formats = calloc(num, sizeof *formats);
169 EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL);
171 for (i = 0; i < num; i++)
173 formats[i].format = egl_formats[i];
174 /* Currently, modifier is not supported */
175 formats[i].modifiers = &fallback_modifier;
176 formats[i].num_modifiers = 1;
184 num = sizeof(fallback_formats) / sizeof(fallback_formats[0]);
186 formats = calloc(num, sizeof *formats);
187 EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL);
189 for (i = 0; i < num; i++)
191 formats[i].format = fallback_formats[0];
192 formats[i].modifiers = &fallback_modifier;
193 formats[i].num_modifiers = 1;
202 e_linux_dmabuf_init(struct wl_display *display)
204 E_Linux_Dmabuf *dmabuf;
206 if (_dmabuf) return EINA_TRUE;
208 dmabuf = E_NEW(E_Linux_Dmabuf, 1);
212 dmabuf->supported_formats = _e_linux_dmabuf_supported_format_get(dmabuf,
213 &dmabuf->num_formats);
214 if (!dmabuf->supported_formats)
216 ERR("fail to _e_linux_dmabuf_supported_format_get");
220 dmabuf->ds_dmabuf = ds_linux_dmabuf_v1_create(display,
221 dmabuf->supported_formats, dmabuf->num_formats);
222 if (!dmabuf->ds_dmabuf)
224 ERR("Could not create ds_linux_dmabuf_v1");
229 dmabuf->listener.display_destroy.notify = _e_linux_dmabuf_cb_display_destroy;
230 wl_display_add_destroy_listener(display, &dmabuf->listener.display_destroy);
238 _e_linux_dmabuf_buffer_cb_ds_buffer_destroy(struct ds_addon *addon)
240 E_Linux_Dmabuf_Buffer *dmabuf_buffer;
242 dmabuf_buffer = wl_container_of(addon, dmabuf_buffer, ds_buffer_addon);
244 ds_addon_finish(&dmabuf_buffer->ds_buffer_addon);
246 tbm_surface_internal_unref(dmabuf_buffer->tsurface);
250 static struct ds_addon_interface _e_linux_dmabuf_buffer_addon_impl = {
251 .name = "e_linux_dmabuf_buffer",
252 .destroy = _e_linux_dmabuf_buffer_cb_ds_buffer_destroy,
255 static E_Linux_Dmabuf_Buffer *
256 _e_linux_dmabuf_buffer_get_from_ds_buffer(struct ds_buffer *ds_buffer)
258 struct ds_addon *addon;
259 E_Linux_Dmabuf_Buffer *dmabuf_buffer;
261 addon = ds_addon_find(&ds_buffer->addons, _dmabuf,
262 &_e_linux_dmabuf_buffer_addon_impl);
263 if (!addon) return NULL;
265 dmabuf_buffer = wl_container_of(addon, dmabuf_buffer, ds_buffer_addon);
267 return dmabuf_buffer;
270 EINTERN tbm_surface_h
271 e_linux_dmabuf_tbm_surface_get_from_buffer(struct ds_buffer *ds_buffer)
273 E_Linux_Dmabuf_Buffer *dmabuf_buffer;
274 struct ds_linux_dmabuf_v1_buffer *ds_dmabuf_buffer;
275 const struct ds_linux_dmabuf_v1_attributes *ds_attributes;
276 tbm_surface_h tsurface = NULL;
277 tbm_surface_info_s info = {0, };
278 tbm_bo bos[LINUX_DMABUF_MAX_PLANES] = {0, };
279 off_t bos_size[LINUX_DMABUF_MAX_PLANES] = {0, };
282 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
283 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
284 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen->bufmgr, NULL);
286 if (!_dmabuf) return NULL;
288 ds_dmabuf_buffer = ds_linux_dmabuf_v1_buffer_from_buffer(ds_buffer);
289 if (!ds_dmabuf_buffer)
292 dmabuf_buffer = _e_linux_dmabuf_buffer_get_from_ds_buffer(ds_buffer);
294 return dmabuf_buffer->tsurface;
296 ds_attributes = ds_linux_dmabuf_v1_buffer_get_attributes(ds_dmabuf_buffer);
297 EINA_SAFETY_ON_NULL_RETURN_VAL(ds_attributes, NULL);
299 info.width = ds_attributes->width;
300 info.height = ds_attributes->height;
301 info.format = ds_attributes->format;
302 info.num_planes = ds_attributes->num_planes;
304 for (i = 0; i < info.num_planes; i++)
306 info.planes[i].stride = ds_attributes->stride[i];
307 info.planes[i].offset = ds_attributes->offset[i];
309 bos[i] = tbm_bo_import_fd(e_comp->e_comp_screen->bufmgr, ds_attributes->fd[i]);
310 EINA_SAFETY_ON_NULL_GOTO(bos[i], failed);
312 bos_size[i] = lseek(ds_attributes->fd[i], 0, SEEK_END);
313 EINA_SAFETY_ON_TRUE_GOTO(bos_size[i] == -1, failed);
316 for (i = 0; i < info.num_planes; i++)
318 if ((i + 1 == info.num_planes) || (bos[i] != bos[i + 1]))
319 info.planes[i].size = bos_size[i] - info.planes[i].offset;
321 info.planes[i].size = info.planes[i + 1].offset - info.planes[i].offset;
323 info.size += info.planes[i].size;
326 tsurface = tbm_surface_internal_create_with_bos(&info, bos, info.num_planes);
327 EINA_SAFETY_ON_NULL_GOTO(tsurface, failed);
329 for (i = 0; i < info.num_planes; i++)
332 tbm_bo_unref(bos[i]);
335 dmabuf_buffer = E_NEW(E_Linux_Dmabuf_Buffer, 1);
336 EINA_SAFETY_ON_NULL_GOTO(dmabuf_buffer, failed);
338 dmabuf_buffer->tsurface = tsurface;
340 ds_addon_init(&dmabuf_buffer->ds_buffer_addon, &ds_buffer->addons,
341 _dmabuf, &_e_linux_dmabuf_buffer_addon_impl);
342 dmabuf_buffer->ds_buffer = ds_buffer;
347 for (i = 0; i < info.num_planes; i++)
350 tbm_bo_unref(bos[i]);
354 tbm_surface_destroy(tsurface);