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 "platform_x11_dri3.h"
39 #include "loader_dri3_helper.h"
41 static struct dri3_egl_surface
*
42 loader_drawable_to_egl_surface(struct loader_dri3_drawable
*draw
) {
43 size_t offset
= offsetof(struct dri3_egl_surface
, loader_drawable
);
44 return (struct dri3_egl_surface
*)(((void*) draw
) - offset
);
48 egl_dri3_set_drawable_size(struct loader_dri3_drawable
*draw
,
49 int width
, int height
)
51 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
53 dri3_surf
->surf
.base
.Width
= width
;
54 dri3_surf
->surf
.base
.Height
= height
;
58 egl_dri3_in_current_context(struct loader_dri3_drawable
*draw
)
60 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
61 _EGLContext
*ctx
= _eglGetCurrentContext();
63 return ctx
->Resource
.Display
== dri3_surf
->surf
.base
.Resource
.Display
;
67 egl_dri3_get_dri_context(struct loader_dri3_drawable
*draw
)
69 _EGLContext
*ctx
= _eglGetCurrentContext();
70 struct dri2_egl_context
*dri2_ctx
;
73 dri2_ctx
= dri2_egl_context(ctx
);
74 return dri2_ctx
->dri_context
;
78 egl_dri3_get_dri_screen(void)
80 _EGLContext
*ctx
= _eglGetCurrentContext();
81 struct dri2_egl_context
*dri2_ctx
;
84 dri2_ctx
= dri2_egl_context(ctx
);
85 return dri2_egl_display(dri2_ctx
->base
.Resource
.Display
)->dri_screen
;
89 egl_dri3_flush_drawable(struct loader_dri3_drawable
*draw
, unsigned flags
)
91 struct dri3_egl_surface
*dri3_surf
= loader_drawable_to_egl_surface(draw
);
92 _EGLDisplay
*disp
= dri3_surf
->surf
.base
.Resource
.Display
;
94 dri2_flush_drawable_for_swapbuffers(disp
, &dri3_surf
->surf
.base
);
97 static const struct loader_dri3_vtable egl_dri3_vtable
= {
98 .set_drawable_size
= egl_dri3_set_drawable_size
,
99 .in_current_context
= egl_dri3_in_current_context
,
100 .get_dri_context
= egl_dri3_get_dri_context
,
101 .get_dri_screen
= egl_dri3_get_dri_screen
,
102 .flush_drawable
= egl_dri3_flush_drawable
,
107 dri3_destroy_surface(_EGLDisplay
*disp
, _EGLSurface
*surf
)
109 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
110 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
111 xcb_drawable_t drawable
= dri3_surf
->loader_drawable
.drawable
;
113 loader_dri3_drawable_fini(&dri3_surf
->loader_drawable
);
115 if (surf
->Type
== EGL_PBUFFER_BIT
)
116 xcb_free_pixmap (dri2_dpy
->conn
, drawable
);
118 dri2_fini_surface(surf
);
125 dri3_set_swap_interval(const _EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
,
128 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
130 dri3_surf
->surf
.base
.SwapInterval
= interval
;
131 loader_dri3_set_swap_interval(&dri3_surf
->loader_drawable
, interval
);
137 dri3_create_surface(_EGLDisplay
*disp
, EGLint type
, _EGLConfig
*conf
,
138 void *native_surface
, const EGLint
*attrib_list
)
140 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
141 struct dri2_egl_config
*dri2_conf
= dri2_egl_config(conf
);
142 struct dri3_egl_surface
*dri3_surf
;
143 const __DRIconfig
*dri_config
;
144 xcb_drawable_t drawable
;
146 dri3_surf
= calloc(1, sizeof *dri3_surf
);
148 _eglError(EGL_BAD_ALLOC
, "dri3_create_surface");
152 if (!dri2_init_surface(&dri3_surf
->surf
.base
, disp
, type
, conf
,
153 attrib_list
, false, native_surface
))
156 if (type
== EGL_PBUFFER_BIT
) {
157 drawable
= xcb_generate_id(dri2_dpy
->conn
);
158 xcb_create_pixmap(dri2_dpy
->conn
, conf
->BufferSize
,
159 drawable
, dri2_dpy
->screen
->root
,
160 dri3_surf
->surf
.base
.Width
, dri3_surf
->surf
.base
.Height
);
162 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface
));
163 drawable
= (uintptr_t) native_surface
;
166 dri_config
= dri2_get_dri_config(dri2_conf
, type
,
167 dri3_surf
->surf
.base
.GLColorspace
);
170 _eglError(EGL_BAD_MATCH
, "Unsupported surfacetype/colorspace configuration");
174 if (loader_dri3_drawable_init(dri2_dpy
->conn
, drawable
,
175 dri2_dpy
->dri_screen
,
176 dri2_dpy
->is_different_gpu
,
177 dri2_dpy
->multibuffers_available
,
179 &dri2_dpy
->loader_dri3_ext
,
181 &dri3_surf
->loader_drawable
)) {
182 _eglError(EGL_BAD_ALLOC
, "dri3_surface_create");
186 return &dri3_surf
->surf
.base
;
189 if (type
== EGL_PBUFFER_BIT
)
190 xcb_free_pixmap(dri2_dpy
->conn
, drawable
);
198 dri3_authenticate(_EGLDisplay
*disp
, uint32_t id
)
200 #ifdef HAVE_WAYLAND_PLATFORM
201 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
203 if (dri2_dpy
->device_name
) {
204 _eglLog(_EGL_WARNING
,
205 "Wayland client render node authentication is unnecessary");
209 _eglLog(_EGL_WARNING
,
210 "Wayland client primary node authentication isn't supported");
217 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
220 dri3_create_window_surface(_EGLDisplay
*disp
, _EGLConfig
*conf
,
221 void *native_window
, const EGLint
*attrib_list
)
223 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
226 surf
= dri3_create_surface(disp
, EGL_WINDOW_BIT
, conf
,
227 native_window
, attrib_list
);
229 dri3_set_swap_interval(disp
->Driver
, disp
, surf
, dri2_dpy
->default_swap_interval
);
235 dri3_create_pixmap_surface(_EGLDisplay
*disp
, _EGLConfig
*conf
,
236 void *native_pixmap
, const EGLint
*attrib_list
)
238 return dri3_create_surface(disp
, EGL_PIXMAP_BIT
, conf
,
239 native_pixmap
, attrib_list
);
243 dri3_create_pbuffer_surface(_EGLDisplay
*disp
, _EGLConfig
*conf
,
244 const EGLint
*attrib_list
)
246 return dri3_create_surface(disp
, EGL_PBUFFER_BIT
, conf
,
251 dri3_get_sync_values(_EGLDisplay
*display
, _EGLSurface
*surface
,
252 EGLuint64KHR
*ust
, EGLuint64KHR
*msc
,
255 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surface
);
257 return loader_dri3_wait_for_msc(&dri3_surf
->loader_drawable
, 0, 0, 0,
258 (int64_t *) ust
, (int64_t *) msc
,
259 (int64_t *) sbc
) ? EGL_TRUE
: EGL_FALSE
;
263 dri3_create_image_khr_pixmap(_EGLDisplay
*disp
, _EGLContext
*ctx
,
264 EGLClientBuffer buffer
, const EGLint
*attr_list
)
266 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
267 struct dri2_egl_image
*dri2_img
;
268 xcb_drawable_t drawable
;
269 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie
;
270 xcb_dri3_buffer_from_pixmap_reply_t
*bp_reply
;
273 drawable
= (xcb_drawable_t
) (uintptr_t) buffer
;
274 bp_cookie
= xcb_dri3_buffer_from_pixmap(dri2_dpy
->conn
, drawable
);
275 bp_reply
= xcb_dri3_buffer_from_pixmap_reply(dri2_dpy
->conn
,
278 _eglError(EGL_BAD_ALLOC
, "xcb_dri3_buffer_from_pixmap");
282 format
= dri2_format_for_depth(dri2_dpy
, bp_reply
->depth
);
283 if (format
== __DRI_IMAGE_FORMAT_NONE
) {
284 _eglError(EGL_BAD_PARAMETER
,
285 "dri3_create_image_khr: unsupported pixmap depth");
287 return EGL_NO_IMAGE_KHR
;
290 dri2_img
= malloc(sizeof *dri2_img
);
292 _eglError(EGL_BAD_ALLOC
, "dri3_create_image_khr");
294 return EGL_NO_IMAGE_KHR
;
297 _eglInitImage(&dri2_img
->base
, disp
);
299 dri2_img
->dri_image
= loader_dri3_create_image(dri2_dpy
->conn
,
302 dri2_dpy
->dri_screen
,
308 return &dri2_img
->base
;
311 #ifdef HAVE_DRI3_MODIFIERS
313 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay
*disp
, _EGLContext
*ctx
,
314 EGLClientBuffer buffer
,
315 const EGLint
*attr_list
)
317 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
318 struct dri2_egl_image
*dri2_img
;
319 xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie
;
320 xcb_dri3_buffers_from_pixmap_reply_t
*bp_reply
;
321 xcb_drawable_t drawable
;
324 drawable
= (xcb_drawable_t
) (uintptr_t) buffer
;
325 bp_cookie
= xcb_dri3_buffers_from_pixmap(dri2_dpy
->conn
, drawable
);
326 bp_reply
= xcb_dri3_buffers_from_pixmap_reply(dri2_dpy
->conn
,
330 _eglError(EGL_BAD_ATTRIBUTE
, "dri3_create_image_khr");
331 return EGL_NO_IMAGE_KHR
;
334 format
= dri2_format_for_depth(dri2_dpy
, bp_reply
->depth
);
335 if (format
== __DRI_IMAGE_FORMAT_NONE
) {
336 _eglError(EGL_BAD_PARAMETER
,
337 "dri3_create_image_khr: unsupported pixmap depth");
339 return EGL_NO_IMAGE_KHR
;
342 dri2_img
= malloc(sizeof *dri2_img
);
344 _eglError(EGL_BAD_ALLOC
, "dri3_create_image_khr");
346 return EGL_NO_IMAGE_KHR
;
349 _eglInitImage(&dri2_img
->base
, disp
);
351 dri2_img
->dri_image
= loader_dri3_create_image_from_buffers(dri2_dpy
->conn
,
354 dri2_dpy
->dri_screen
,
359 if (!dri2_img
->dri_image
) {
360 _eglError(EGL_BAD_ATTRIBUTE
, "dri3_create_image_khr");
362 return EGL_NO_IMAGE_KHR
;
365 return &dri2_img
->base
;
370 dri3_create_image_khr(const _EGLDriver
*drv
, _EGLDisplay
*disp
,
371 _EGLContext
*ctx
, EGLenum target
,
372 EGLClientBuffer buffer
, const EGLint
*attr_list
)
374 #ifdef HAVE_DRI3_MODIFIERS
375 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
379 case EGL_NATIVE_PIXMAP_KHR
:
380 #ifdef HAVE_DRI3_MODIFIERS
381 if (dri2_dpy
->multibuffers_available
)
382 return dri3_create_image_khr_pixmap_from_buffers(disp
, ctx
, buffer
,
385 return dri3_create_image_khr_pixmap(disp
, ctx
, buffer
, attr_list
);
387 return dri2_create_image_khr(drv
, disp
, ctx
, target
, buffer
, attr_list
);
392 * Called by the driver when it needs to update the real front buffer with the
393 * contents of its fake front buffer.
396 dri3_flush_front_buffer(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
398 struct loader_dri3_drawable
*draw
= loaderPrivate
;
401 /* There does not seem to be any kind of consensus on whether we should
402 * support front-buffer rendering or not:
403 * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
405 if (!draw
->is_pixmap
)
406 _eglLog(_EGL_WARNING
, "FIXME: egl/x11 doesn't support front buffer rendering.");
409 const __DRIimageLoaderExtension dri3_image_loader_extension
= {
410 .base
= { __DRI_IMAGE_LOADER
, 1 },
412 .getBuffers
= loader_dri3_get_buffers
,
413 .flushFrontBuffer
= dri3_flush_front_buffer
,
417 dri3_swap_buffers(const _EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*draw
)
419 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(draw
);
421 return loader_dri3_swap_buffers_msc(&dri3_surf
->loader_drawable
,
423 draw
->SwapBehavior
== EGL_BUFFER_PRESERVED
) != -1;
427 dri3_copy_buffers(const _EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
,
428 void *native_pixmap_target
)
430 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
433 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target
));
434 target
= (uintptr_t) native_pixmap_target
;
436 loader_dri3_copy_drawable(&dri3_surf
->loader_drawable
, target
,
437 dri3_surf
->loader_drawable
.drawable
);
443 dri3_query_buffer_age(const _EGLDriver
*drv
, _EGLDisplay
*disp
, _EGLSurface
*surf
)
445 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
447 return loader_dri3_query_buffer_age(&dri3_surf
->loader_drawable
);
451 dri3_query_surface(const _EGLDriver
*drv
, _EGLDisplay
*disp
,
452 _EGLSurface
*surf
, EGLint attribute
,
455 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
460 loader_dri3_update_drawable_geometry(&dri3_surf
->loader_drawable
);
466 return _eglQuerySurface(drv
, disp
, surf
, attribute
, value
);
469 static __DRIdrawable
*
470 dri3_get_dri_drawable(_EGLSurface
*surf
)
472 struct dri3_egl_surface
*dri3_surf
= dri3_egl_surface(surf
);
474 return dri3_surf
->loader_drawable
.dri_drawable
;
478 dri3_close_screen_notify(_EGLDisplay
*disp
)
480 struct dri2_egl_display
*dri2_dpy
= dri2_egl_display(disp
);
482 loader_dri3_close_screen(dri2_dpy
->dri_screen
);
485 struct dri2_egl_display_vtbl dri3_x11_display_vtbl
= {
486 .authenticate
= dri3_authenticate
,
487 .create_window_surface
= dri3_create_window_surface
,
488 .create_pixmap_surface
= dri3_create_pixmap_surface
,
489 .create_pbuffer_surface
= dri3_create_pbuffer_surface
,
490 .destroy_surface
= dri3_destroy_surface
,
491 .create_image
= dri3_create_image_khr
,
492 .swap_interval
= dri3_set_swap_interval
,
493 .swap_buffers
= dri3_swap_buffers
,
494 .copy_buffers
= dri3_copy_buffers
,
495 .query_buffer_age
= dri3_query_buffer_age
,
496 .query_surface
= dri3_query_surface
,
497 .get_sync_values
= dri3_get_sync_values
,
498 .get_dri_drawable
= dri3_get_dri_drawable
,
499 .close_screen_notify
= dri3_close_screen_notify
,
502 /* Only request versions of these protocols which we actually support. */
503 #define DRI3_SUPPORTED_MAJOR 1
504 #define PRESENT_SUPPORTED_MAJOR 1
506 #ifdef HAVE_DRI3_MODIFIERS
507 #define DRI3_SUPPORTED_MINOR 2
508 #define PRESENT_SUPPORTED_MINOR 2
510 #define PRESENT_SUPPORTED_MINOR 0
511 #define DRI3_SUPPORTED_MINOR 0
515 dri3_x11_connect(struct dri2_egl_display
*dri2_dpy
)
517 xcb_dri3_query_version_reply_t
*dri3_query
;
518 xcb_dri3_query_version_cookie_t dri3_query_cookie
;
519 xcb_present_query_version_reply_t
*present_query
;
520 xcb_present_query_version_cookie_t present_query_cookie
;
521 xcb_generic_error_t
*error
;
522 const xcb_query_extension_reply_t
*extension
;
524 xcb_prefetch_extension_data (dri2_dpy
->conn
, &xcb_dri3_id
);
525 xcb_prefetch_extension_data (dri2_dpy
->conn
, &xcb_present_id
);
527 extension
= xcb_get_extension_data(dri2_dpy
->conn
, &xcb_dri3_id
);
528 if (!(extension
&& extension
->present
))
531 extension
= xcb_get_extension_data(dri2_dpy
->conn
, &xcb_present_id
);
532 if (!(extension
&& extension
->present
))
535 dri3_query_cookie
= xcb_dri3_query_version(dri2_dpy
->conn
,
536 DRI3_SUPPORTED_MAJOR
,
537 DRI3_SUPPORTED_MINOR
);
539 present_query_cookie
= xcb_present_query_version(dri2_dpy
->conn
,
540 PRESENT_SUPPORTED_MAJOR
,
541 PRESENT_SUPPORTED_MINOR
);
544 xcb_dri3_query_version_reply(dri2_dpy
->conn
, dri3_query_cookie
, &error
);
545 if (dri3_query
== NULL
|| error
!= NULL
) {
546 _eglLog(_EGL_WARNING
, "DRI3: failed to query the version");
552 dri2_dpy
->dri3_major_version
= dri3_query
->major_version
;
553 dri2_dpy
->dri3_minor_version
= dri3_query
->minor_version
;
557 xcb_present_query_version_reply(dri2_dpy
->conn
,
558 present_query_cookie
, &error
);
559 if (present_query
== NULL
|| error
!= NULL
) {
560 _eglLog(_EGL_WARNING
, "DRI3: failed to query Present version");
566 dri2_dpy
->present_major_version
= present_query
->major_version
;
567 dri2_dpy
->present_minor_version
= present_query
->minor_version
;
570 dri2_dpy
->fd
= loader_dri3_open(dri2_dpy
->conn
, dri2_dpy
->screen
->root
, 0);
571 if (dri2_dpy
->fd
< 0) {
572 int conn_error
= xcb_connection_has_error(dri2_dpy
->conn
);
573 _eglLog(_EGL_WARNING
, "DRI3: Screen seems not DRI3 capable");
576 _eglLog(_EGL_WARNING
, "DRI3: Failed to initialize");
581 dri2_dpy
->fd
= loader_get_user_preferred_fd(dri2_dpy
->fd
, &dri2_dpy
->is_different_gpu
);
583 dri2_dpy
->driver_name
= loader_get_driver_for_fd(dri2_dpy
->fd
);
584 if (!dri2_dpy
->driver_name
) {
585 _eglLog(_EGL_WARNING
, "DRI3: No driver found");
590 #ifdef HAVE_WAYLAND_PLATFORM
591 /* Only try to get a render device name since dri3 doesn't provide a
592 * mechanism for authenticating client opened device node fds. If this
593 * fails then don't advertise the extension. */
594 dri2_dpy
->device_name
= drmGetRenderDeviceNameFromFd(dri2_dpy
->fd
);