2 * Copyright © 2015 Boyan Ding
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
30 #include <xcb/present.h>
33 #include "util/macros.h"
36 #include "egl_dri2_fallbacks.h"
37 #include "platform_x11_dri3.h"
40 #include "loader_dri3_helper.h"
42 static struct dri3_egl_surface
*
43 loader_drawable_to_egl_surface(struct loader_dri3_drawable
*draw
) {
44 size_t offset
= offsetof(struct dri3_egl_surface
, loader_drawable
);
45 return (struct dri3_egl_surface
*)(((void*) draw
) - offset
);
49 egl_dri3_get_swap_interval(struct loader_dri3_drawable
*draw
)
51 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
53 return dri3_surf
->base
.SwapInterval
;
57 egl_dri3_clamp_swap_interval(struct loader_dri3_drawable
*draw
, int interval
)
59 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
61 if (interval
> dri3_surf
->base
.Config
->MaxSwapInterval
)
62 interval
= dri3_surf
->base
.Config
->MaxSwapInterval
;
63 else if (interval
< dri3_surf
->base
.Config
->MinSwapInterval
)
64 interval
= dri3_surf
->base
.Config
->MinSwapInterval
;
70 egl_dri3_set_swap_interval(struct loader_dri3_drawable
*draw
, int interval
)
72 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
74 dri3_surf
->base
.SwapInterval
= interval
;
78 egl_dri3_set_drawable_size(struct loader_dri3_drawable
*draw
,
79 int width
, int height
)
81 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
83 dri3_surf
->base
.Width
= width
;
84 dri3_surf
->base
.Height
= height
;
88 egl_dri3_in_current_context(struct loader_dri3_drawable
*draw
)
90 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
91 _EGLContext
*ctx
= _eglGetCurrentContext();
93 return ctx
->Resource
.Display
== dri3_surf
->base
.Resource
.Display
;
97 egl_dri3_get_dri_context(struct loader_dri3_drawable
*draw
)
99 _EGLContext
*ctx
= _eglGetCurrentContext();
100 struct dri2_egl_context
*dri2_ctx
;
103 dri2_ctx
= dri2_egl_context(ctx
);
104 return dri2_ctx
->dri_context
;
108 egl_dri3_get_dri_screen(struct loader_dri3_drawable
*draw
)
110 _EGLContext
*ctx
= _eglGetCurrentContext();
111 struct dri2_egl_context
*dri2_ctx
;
114 dri2_ctx
= dri2_egl_context(ctx
);
115 return dri2_egl_display(dri2_ctx
->base
.Resource
.Display
)->dri_screen
;
119 egl_dri3_flush_drawable(struct loader_dri3_drawable
*draw
, unsigned flags
)
121 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
122 _EGLDisplay
*disp
= dri3_surf
->base
.Resource
.Display
;
124 dri2_flush_drawable_for_swapbuffers(disp
, &dri3_surf
->base
);
127 static const struct loader_dri3_vtable egl_dri3_vtable
= {
128 .get_swap_interval
= egl_dri3_get_swap_interval
,
129 .clamp_swap_interval
= egl_dri3_clamp_swap_interval
,
130 .set_swap_interval
= egl_dri3_set_swap_interval
,
131 .set_drawable_size
= egl_dri3_set_drawable_size
,
132 .in_current_context
= egl_dri3_in_current_context
,
133 .get_dri_context
= egl_dri3_get_dri_context
,
134 .get_dri_screen
= egl_dri3_get_dri_screen
,
135 .flush_drawable
= egl_dri3_flush_drawable
,
140 dri3_destroy_surface(_EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
)
142 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
146 loader_dri3_drawable_fini(&dri3_surf
->loader_drawable
);
154 dri3_set_swap_interval(_EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
,
157 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
159 loader_dri3_set_swap_interval(&dri3_surf
->loader_drawable
, interval
);
165 dri3_create_surface(_EGLDriver
*drv
, _EGLDisplay
*disp
, EGLint type
,
166 _EGLConfig
*conf
, void *native_surface
,
167 const EGLint
*attrib_list
)
169 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
170 struct dri2_egl_config
*dri2_conf
= dri2_egl_config(conf
);
171 struct dri3_egl_surface
*dri3_surf
;
172 const __DRIconfig
*dri_config
;
173 xcb_drawable_t drawable
;
175 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface
));
176 drawable
= (uintptr_t) native_surface
;
180 dri3_surf
= calloc(1, sizeof *dri3_surf
);
182 _eglError(EGL_BAD_ALLOC
, "dri3_create_surface");
186 if (!_eglInitSurface(&dri3_surf
->base
, disp
, type
, conf
, attrib_list
))
189 if (type
== EGL_PBUFFER_BIT
) {
190 drawable
= xcb_generate_id(dri2_dpy
->conn
);
191 xcb_create_pixmap(dri2_dpy
->conn
, conf
->BufferSize
,
192 drawable
, dri2_dpy
->screen
->root
,
193 dri3_surf
->base
.Width
, dri3_surf
->base
.Height
);
196 dri_config
= dri2_get_dri_config(dri2_conf
, type
,
197 dri3_surf
->base
.GLColorspace
);
199 if (loader_dri3_drawable_init(dri2_dpy
->conn
, drawable
,
200 dri2_dpy
->dri_screen
,
201 dri2_dpy
->is_different_gpu
, dri_config
,
202 &dri2_dpy
->loader_dri3_ext
,
204 &dri3_surf
->loader_drawable
)) {
205 _eglError(EGL_BAD_ALLOC
, "dri3_surface_create");
209 return &dri3_surf
->base
;
212 if (type
== EGL_PBUFFER_BIT
)
213 xcb_free_pixmap(dri2_dpy
->conn
, drawable
);
221 dri3_authenticate(_EGLDisplay
*disp
, uint32_t id
)
223 #ifdef HAVE_WAYLAND_PLATFORM
224 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
226 if (dri2_dpy
->device_name
) {
227 _eglLog(_EGL_WARNING
,
228 "Wayland client render node authentication is unnecessary");
232 _eglLog(_EGL_WARNING
,
233 "Wayland client primary node authentication isn't supported");
240 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
243 dri3_create_window_surface(_EGLDriver
*drv
, _EGLDisplay
*disp
,
244 _EGLConfig
*conf
, void *native_window
,
245 const EGLint
*attrib_list
)
247 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
250 surf
= dri3_create_surface(drv
, disp
, EGL_WINDOW_BIT
, conf
,
251 native_window
, attrib_list
);
253 dri3_set_swap_interval(drv
, disp
, surf
, dri2_dpy
->default_swap_interval
);
259 dri3_create_pixmap_surface(_EGLDriver
*drv
, _EGLDisplay
*disp
,
260 _EGLConfig
*conf
, void *native_pixmap
,
261 const EGLint
*attrib_list
)
263 return dri3_create_surface(drv
, disp
, EGL_PIXMAP_BIT
, conf
,
264 native_pixmap
, attrib_list
);
268 dri3_create_pbuffer_surface(_EGLDriver
*drv
, _EGLDisplay
*disp
,
269 _EGLConfig
*conf
, const EGLint
*attrib_list
)
271 return dri3_create_surface(drv
, disp
, EGL_PBUFFER_BIT
, conf
,
272 XCB_WINDOW_NONE
, attrib_list
);
276 dri3_get_sync_values(_EGLDisplay
*display
, _EGLSurface
*surface
,
277 EGLuint64KHR
*ust
, EGLuint64KHR
*msc
,
280 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surface
);
282 return loader_dri3_wait_for_msc(&dri3_surf
->loader_drawable
, 0, 0, 0,
283 (int64_t *) ust
, (int64_t *) msc
,
284 (int64_t *) sbc
) ? EGL_TRUE
: EGL_FALSE
;
288 dri3_create_image_khr_pixmap(_EGLDisplay
*disp
, _EGLContext
*ctx
,
289 EGLClientBuffer buffer
, const EGLint
*attr_list
)
291 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
292 struct dri2_egl_image
*dri2_img
;
293 xcb_drawable_t drawable
;
294 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie
;
295 xcb_dri3_buffer_from_pixmap_reply_t
*bp_reply
;
298 drawable
= (xcb_drawable_t
) (uintptr_t) buffer
;
299 bp_cookie
= xcb_dri3_buffer_from_pixmap(dri2_dpy
->conn
, drawable
);
300 bp_reply
= xcb_dri3_buffer_from_pixmap_reply(dri2_dpy
->conn
,
303 _eglError(EGL_BAD_ALLOC
, "xcb_dri3_buffer_from_pixmap");
307 switch (bp_reply
->depth
) {
309 format
= __DRI_IMAGE_FORMAT_RGB565
;
312 format
= __DRI_IMAGE_FORMAT_XRGB8888
;
315 format
= __DRI_IMAGE_FORMAT_ARGB8888
;
318 _eglError(EGL_BAD_PARAMETER
,
319 "dri3_create_image_khr: unsupported pixmap depth");
321 return EGL_NO_IMAGE_KHR
;
324 dri2_img
= malloc(sizeof *dri2_img
);
326 _eglError(EGL_BAD_ALLOC
, "dri3_create_image_khr");
327 return EGL_NO_IMAGE_KHR
;
330 _eglInitImage(&dri2_img
->base
, disp
);
332 dri2_img
->dri_image
= loader_dri3_create_image(dri2_dpy
->conn
,
335 dri2_dpy
->dri_screen
,
341 return &dri2_img
->base
;
345 dri3_create_image_khr(_EGLDriver
*drv
, _EGLDisplay
*disp
,
346 _EGLContext
*ctx
, EGLenum target
,
347 EGLClientBuffer buffer
, const EGLint
*attr_list
)
352 case EGL_NATIVE_PIXMAP_KHR
:
353 return dri3_create_image_khr_pixmap(disp
, ctx
, buffer
, attr_list
);
355 return dri2_create_image_khr(drv
, disp
, ctx
, target
, buffer
, attr_list
);
360 * Called by the driver when it needs to update the real front buffer with the
361 * contents of its fake front buffer.
364 dri3_flush_front_buffer(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
366 /* There does not seem to be any kind of consensus on whether we should
367 * support front-buffer rendering or not:
368 * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
370 _eglLog(_EGL_WARNING
, "FIXME: egl/x11 doesn't support front buffer rendering.");
372 (void) loaderPrivate
;
375 const __DRIimageLoaderExtension dri3_image_loader_extension
= {
376 .base
= { __DRI_IMAGE_LOADER
, 1 },
378 .getBuffers
= loader_dri3_get_buffers
,
379 .flushFrontBuffer
= dri3_flush_front_buffer
,
383 dri3_swap_buffers(_EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*draw
)
385 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(draw
);
387 /* No-op for a pixmap or pbuffer surface */
388 if (draw
->Type
== EGL_PIXMAP_BIT
|| draw
->Type
== EGL_PBUFFER_BIT
)
391 return loader_dri3_swap_buffers_msc(&dri3_surf
->loader_drawable
,
393 draw
->SwapBehavior
== EGL_BUFFER_PRESERVED
) != -1;
397 dri3_copy_buffers(_EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
,
398 void *native_pixmap_target
)
400 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
403 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target
));
404 target
= (uintptr_t) native_pixmap_target
;
406 loader_dri3_copy_drawable(&dri3_surf
->loader_drawable
, target
,
407 dri3_surf
->loader_drawable
.drawable
);
413 dri3_query_buffer_age(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
)
415 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
417 return loader_dri3_query_buffer_age(&dri3_surf
->loader_drawable
);
421 dri3_query_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
422 _EGLSurface
*surf
, EGLint attribute
,
425 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
430 loader_dri3_update_drawable_geometry(&dri3_surf
->loader_drawable
);
436 return _eglQuerySurface(drv
, dpy
, surf
, attribute
, value
);
439 static __DRIdrawable
*
440 dri3_get_dri_drawable(_EGLSurface
*surf
)
442 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
444 return dri3_surf
->loader_drawable
.dri_drawable
;
447 struct dri2_egl_display_vtbl dri3_x11_display_vtbl
= {
448 .authenticate
= dri3_authenticate
,
449 .create_window_surface
= dri3_create_window_surface
,
450 .create_pixmap_surface
= dri3_create_pixmap_surface
,
451 .create_pbuffer_surface
= dri3_create_pbuffer_surface
,
452 .destroy_surface
= dri3_destroy_surface
,
453 .create_image
= dri3_create_image_khr
,
454 .swap_interval
= dri3_set_swap_interval
,
455 .swap_buffers
= dri3_swap_buffers
,
456 .swap_buffers_with_damage
= dri2_fallback_swap_buffers_with_damage
,
457 .swap_buffers_region
= dri2_fallback_swap_buffers_region
,
458 .set_damage_region
= dri2_fallback_set_damage_region
,
459 .post_sub_buffer
= dri2_fallback_post_sub_buffer
,
460 .copy_buffers
= dri3_copy_buffers
,
461 .query_buffer_age
= dri3_query_buffer_age
,
462 .query_surface
= dri3_query_surface
,
463 .create_wayland_buffer_from_image
= dri2_fallback_create_wayland_buffer_from_image
,
464 .get_sync_values
= dri3_get_sync_values
,
465 .get_dri_drawable
= dri3_get_dri_drawable
,
469 dri3_x11_connect(struct dri2_egl_display
*dri2_dpy
)
471 xcb_dri3_query_version_reply_t
*dri3_query
;
472 xcb_dri3_query_version_cookie_t dri3_query_cookie
;
473 xcb_present_query_version_reply_t
*present_query
;
474 xcb_present_query_version_cookie_t present_query_cookie
;
475 xcb_generic_error_t
*error
;
476 const xcb_query_extension_reply_t
*extension
;
478 xcb_prefetch_extension_data (dri2_dpy
->conn
, &xcb_dri3_id
);
479 xcb_prefetch_extension_data (dri2_dpy
->conn
, &xcb_present_id
);
481 extension
= xcb_get_extension_data(dri2_dpy
->conn
, &xcb_dri3_id
);
482 if (!(extension
&& extension
->present
))
485 extension
= xcb_get_extension_data(dri2_dpy
->conn
, &xcb_present_id
);
486 if (!(extension
&& extension
->present
))
489 dri3_query_cookie
= xcb_dri3_query_version(dri2_dpy
->conn
,
490 XCB_DRI3_MAJOR_VERSION
,
491 XCB_DRI3_MINOR_VERSION
);
493 present_query_cookie
= xcb_present_query_version(dri2_dpy
->conn
,
494 XCB_PRESENT_MAJOR_VERSION
,
495 XCB_PRESENT_MINOR_VERSION
);
498 xcb_dri3_query_version_reply(dri2_dpy
->conn
, dri3_query_cookie
, &error
);
499 if (dri3_query
== NULL
|| error
!= NULL
) {
500 _eglLog(_EGL_WARNING
, "DRI3: failed to query the version");
508 xcb_present_query_version_reply(dri2_dpy
->conn
,
509 present_query_cookie
, &error
);
510 if (present_query
== NULL
|| error
!= NULL
) {
511 _eglLog(_EGL_WARNING
, "DRI3: failed to query Present version");
518 dri2_dpy
->fd
= loader_dri3_open(dri2_dpy
->conn
, dri2_dpy
->screen
->root
, 0);
519 if (dri2_dpy
->fd
< 0) {
520 int conn_error
= xcb_connection_has_error(dri2_dpy
->conn
);
521 _eglLog(_EGL_WARNING
, "DRI3: Screen seems not DRI3 capable");
524 _eglLog(_EGL_WARNING
, "DRI3: Failed to initialize");
529 dri2_dpy
->fd
= loader_get_user_preferred_fd(dri2_dpy
->fd
, &dri2_dpy
->is_different_gpu
);
531 dri2_dpy
->driver_name
= loader_get_driver_for_fd(dri2_dpy
->fd
);
532 if (!dri2_dpy
->driver_name
) {
533 _eglLog(_EGL_WARNING
, "DRI3: No driver found");
538 #ifdef HAVE_WAYLAND_PLATFORM
539 /* Only try to get a render device name since dri3 doesn't provide a
540 * mechanism for authenticating client opened device node fds. If this
541 * fails then don't advertise the extension. */
542 dri2_dpy
->device_name
= drmGetRenderDeviceNameFromFd(dri2_dpy
->fd
);