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>
31
#include <xcb/xfixes.h>
34
#include "util/macros.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_set_drawable_size(struct loader_dri3_drawable *draw,
50
int width, int height)
52
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
54
dri3_surf->surf.base.Width = width;
55
dri3_surf->surf.base.Height = height;
59
egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
61
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
62
_EGLContext *ctx = _eglGetCurrentContext();
64
return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
68
egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
70
_EGLContext *ctx = _eglGetCurrentContext();
71
struct dri2_egl_context *dri2_ctx;
74
dri2_ctx = dri2_egl_context(ctx);
75
return dri2_ctx->dri_context;
79
egl_dri3_get_dri_screen(void)
81
_EGLContext *ctx = _eglGetCurrentContext();
82
struct dri2_egl_context *dri2_ctx;
85
dri2_ctx = dri2_egl_context(ctx);
86
return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;
90
egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
92
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
93
_EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
95
dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
98
static const struct loader_dri3_vtable egl_dri3_vtable = {
99
.set_drawable_size = egl_dri3_set_drawable_size,
100
.in_current_context = egl_dri3_in_current_context,
101
.get_dri_context = egl_dri3_get_dri_context,
102
.get_dri_screen = egl_dri3_get_dri_screen,
103
.flush_drawable = egl_dri3_flush_drawable,
108
dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
110
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
111
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
112
xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
114
loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
116
if (surf->Type == EGL_PBUFFER_BIT)
117
xcb_free_pixmap (dri2_dpy->conn, drawable);
119
dri2_fini_surface(surf);
126
dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
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);
136
static enum loader_dri3_drawable_type
137
egl_to_loader_dri3_drawable_type(EGLint type)
141
return LOADER_DRI3_DRAWABLE_WINDOW;
143
return LOADER_DRI3_DRAWABLE_PIXMAP;
144
case EGL_PBUFFER_BIT:
145
return LOADER_DRI3_DRAWABLE_PBUFFER;
147
return LOADER_DRI3_DRAWABLE_UNKNOWN;
152
dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
153
void *native_surface, const EGLint *attrib_list)
155
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
156
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
157
struct dri3_egl_surface *dri3_surf;
158
const __DRIconfig *dri_config;
159
xcb_drawable_t drawable;
161
dri3_surf = calloc(1, sizeof *dri3_surf);
163
_eglError(EGL_BAD_ALLOC, "dri3_create_surface");
167
if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
168
attrib_list, false, native_surface))
171
if (type == EGL_PBUFFER_BIT) {
172
drawable = xcb_generate_id(dri2_dpy->conn);
173
xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
174
drawable, dri2_dpy->screen->root,
175
dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
177
STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
178
drawable = (uintptr_t) native_surface;
181
dri_config = dri2_get_dri_config(dri2_conf, type,
182
dri3_surf->surf.base.GLColorspace);
185
_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
189
if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
190
egl_to_loader_dri3_drawable_type(type),
191
dri2_dpy->dri_screen,
192
dri2_dpy->is_different_gpu,
193
dri2_dpy->multibuffers_available,
196
&dri2_dpy->loader_dri3_ext,
198
&dri3_surf->loader_drawable)) {
199
_eglError(EGL_BAD_ALLOC, "dri3_surface_create");
203
if (dri3_surf->surf.base.ProtectedContent &&
204
dri2_dpy->is_different_gpu) {
205
_eglError(EGL_BAD_ALLOC, "dri3_surface_create");
209
dri3_surf->loader_drawable.is_protected_content =
210
dri3_surf->surf.base.ProtectedContent;
212
return &dri3_surf->surf.base;
215
if (type == EGL_PBUFFER_BIT)
216
xcb_free_pixmap(dri2_dpy->conn, drawable);
224
dri3_authenticate(_EGLDisplay *disp, uint32_t id)
226
#ifdef HAVE_WAYLAND_PLATFORM
227
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
229
if (dri2_dpy->device_name) {
230
_eglLog(_EGL_WARNING,
231
"Wayland client render node authentication is unnecessary");
235
_eglLog(_EGL_WARNING,
236
"Wayland client primary node authentication isn't supported");
243
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
246
dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
247
void *native_window, const EGLint *attrib_list)
249
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
252
surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
253
native_window, attrib_list);
255
dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
261
dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
262
void *native_pixmap, const EGLint *attrib_list)
264
return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf,
265
native_pixmap, attrib_list);
269
dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
270
const EGLint *attrib_list)
272
return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
277
dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
278
EGLuint64KHR *ust, EGLuint64KHR *msc,
281
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
283
return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
284
(int64_t *) ust, (int64_t *) msc,
285
(int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
289
dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
290
EGLClientBuffer buffer, const EGLint *attr_list)
292
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
293
struct dri2_egl_image *dri2_img;
294
xcb_drawable_t drawable;
295
xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
296
xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
299
drawable = (xcb_drawable_t) (uintptr_t) buffer;
300
bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
301
bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
304
_eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
308
format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
309
if (format == __DRI_IMAGE_FORMAT_NONE) {
310
_eglError(EGL_BAD_PARAMETER,
311
"dri3_create_image_khr: unsupported pixmap depth");
313
return EGL_NO_IMAGE_KHR;
316
dri2_img = malloc(sizeof *dri2_img);
318
_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
320
return EGL_NO_IMAGE_KHR;
323
_eglInitImage(&dri2_img->base, disp);
325
dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
328
dri2_dpy->dri_screen,
334
return &dri2_img->base;
337
#ifdef HAVE_DRI3_MODIFIERS
339
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
340
EGLClientBuffer buffer,
341
const EGLint *attr_list)
343
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
344
struct dri2_egl_image *dri2_img;
345
xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
346
xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
347
xcb_drawable_t drawable;
350
drawable = (xcb_drawable_t) (uintptr_t) buffer;
351
bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
352
bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
356
_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
357
return EGL_NO_IMAGE_KHR;
360
format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
361
if (format == __DRI_IMAGE_FORMAT_NONE) {
362
_eglError(EGL_BAD_PARAMETER,
363
"dri3_create_image_khr: unsupported pixmap depth");
365
return EGL_NO_IMAGE_KHR;
368
dri2_img = malloc(sizeof *dri2_img);
370
_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
372
return EGL_NO_IMAGE_KHR;
375
_eglInitImage(&dri2_img->base, disp);
377
dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
380
dri2_dpy->dri_screen,
385
if (!dri2_img->dri_image) {
386
_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
388
return EGL_NO_IMAGE_KHR;
391
return &dri2_img->base;
396
dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
397
EGLClientBuffer buffer, const EGLint *attr_list)
399
#ifdef HAVE_DRI3_MODIFIERS
400
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
404
case EGL_NATIVE_PIXMAP_KHR:
405
#ifdef HAVE_DRI3_MODIFIERS
406
if (dri2_dpy->multibuffers_available)
407
return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
410
return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
412
return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
417
* Called by the driver when it needs to update the real front buffer with the
418
* contents of its fake front buffer.
421
dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
423
struct loader_dri3_drawable *draw = loaderPrivate;
426
/* There does not seem to be any kind of consensus on whether we should
427
* support front-buffer rendering or not:
428
* http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
430
if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW)
431
_eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
434
const __DRIimageLoaderExtension dri3_image_loader_extension = {
435
.base = { __DRI_IMAGE_LOADER, 1 },
437
.getBuffers = loader_dri3_get_buffers,
438
.flushFrontBuffer = dri3_flush_front_buffer,
442
dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
443
const EGLint *rects, EGLint n_rects)
445
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
447
return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
450
draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
454
dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
456
return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
460
dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
462
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
465
STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
466
target = (uintptr_t) native_pixmap_target;
468
loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
469
dri3_surf->loader_drawable.drawable);
475
dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
477
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
479
return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
483
dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
484
EGLint attribute, EGLint *value)
486
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
491
loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
497
return _eglQuerySurface(disp, surf, attribute, value);
500
static __DRIdrawable *
501
dri3_get_dri_drawable(_EGLSurface *surf)
503
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
505
return dri3_surf->loader_drawable.dri_drawable;
509
dri3_close_screen_notify(_EGLDisplay *disp)
511
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
513
loader_dri3_close_screen(dri2_dpy->dri_screen);
516
struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
517
.authenticate = dri3_authenticate,
518
.create_window_surface = dri3_create_window_surface,
519
.create_pixmap_surface = dri3_create_pixmap_surface,
520
.create_pbuffer_surface = dri3_create_pbuffer_surface,
521
.destroy_surface = dri3_destroy_surface,
522
.create_image = dri3_create_image_khr,
523
.swap_interval = dri3_set_swap_interval,
524
.swap_buffers = dri3_swap_buffers,
525
.swap_buffers_with_damage = dri3_swap_buffers_with_damage,
526
.copy_buffers = dri3_copy_buffers,
527
.query_buffer_age = dri3_query_buffer_age,
528
.query_surface = dri3_query_surface,
529
.get_sync_values = dri3_get_sync_values,
530
.get_dri_drawable = dri3_get_dri_drawable,
531
.close_screen_notify = dri3_close_screen_notify,
534
/* Only request versions of these protocols which we actually support. */
535
#define DRI3_SUPPORTED_MAJOR 1
536
#define PRESENT_SUPPORTED_MAJOR 1
538
#ifdef HAVE_DRI3_MODIFIERS
539
#define DRI3_SUPPORTED_MINOR 2
540
#define PRESENT_SUPPORTED_MINOR 2
542
#define PRESENT_SUPPORTED_MINOR 0
543
#define DRI3_SUPPORTED_MINOR 0
547
dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
549
xcb_dri3_query_version_reply_t *dri3_query;
550
xcb_dri3_query_version_cookie_t dri3_query_cookie;
551
xcb_present_query_version_reply_t *present_query;
552
xcb_present_query_version_cookie_t present_query_cookie;
553
xcb_xfixes_query_version_reply_t *xfixes_query;
554
xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
555
xcb_generic_error_t *error;
556
const xcb_query_extension_reply_t *extension;
558
xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
559
xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
560
xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
562
extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
563
if (!(extension && extension->present))
566
extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
567
if (!(extension && extension->present))
570
extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
571
if (!(extension && extension->present))
574
dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
575
DRI3_SUPPORTED_MAJOR,
576
DRI3_SUPPORTED_MINOR);
578
present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
579
PRESENT_SUPPORTED_MAJOR,
580
PRESENT_SUPPORTED_MINOR);
582
xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
583
XCB_XFIXES_MAJOR_VERSION,
584
XCB_XFIXES_MINOR_VERSION);
587
xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
588
if (dri3_query == NULL || error != NULL) {
589
_eglLog(_EGL_WARNING, "DRI3: failed to query the version");
595
dri2_dpy->dri3_major_version = dri3_query->major_version;
596
dri2_dpy->dri3_minor_version = dri3_query->minor_version;
600
xcb_present_query_version_reply(dri2_dpy->conn,
601
present_query_cookie, &error);
602
if (present_query == NULL || error != NULL) {
603
_eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
609
dri2_dpy->present_major_version = present_query->major_version;
610
dri2_dpy->present_minor_version = present_query->minor_version;
614
xcb_xfixes_query_version_reply(dri2_dpy->conn,
615
xfixes_query_cookie, &error);
616
if (xfixes_query == NULL || error != NULL ||
617
xfixes_query->major_version < 2) {
618
_eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
625
dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
626
if (dri2_dpy->fd < 0) {
627
int conn_error = xcb_connection_has_error(dri2_dpy->conn);
628
_eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
631
_eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
636
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
638
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
639
if (!dri2_dpy->driver_name) {
640
_eglLog(_EGL_WARNING, "DRI3: No driver found");
645
#ifdef HAVE_WAYLAND_PLATFORM
646
/* Only try to get a render device name since dri3 doesn't provide a
647
* mechanism for authenticating client opened device node fds. If this
648
* fails then don't advertise the extension. */
649
dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);