egl: remove suprous header eglcompiler.h
[mesa.git] / src / egl / drivers / dri2 / platform_x11_dri3.c
1 /*
2 * Copyright © 2015 Boyan Ding
3 *
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.
13 *
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
20 * OF THIS SOFTWARE.
21 */
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <xcb/xcb.h>
29 #include <xcb/dri3.h>
30 #include <xcb/present.h>
31
32 #include <xf86drm.h>
33 #include "util/macros.h"
34
35 #include "egl_dri2.h"
36 #include "egl_dri2_fallbacks.h"
37 #include "platform_x11_dri3.h"
38
39 #include "loader.h"
40 #include "loader_dri3_helper.h"
41
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);
46 }
47
48 static int
49 egl_dri3_get_swap_interval(struct loader_dri3_drawable *draw)
50 {
51 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
52
53 return dri3_surf->base.SwapInterval;
54 }
55
56 static int
57 egl_dri3_clamp_swap_interval(struct loader_dri3_drawable *draw, int interval)
58 {
59 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
60
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;
65
66 return interval;
67 }
68
69 static void
70 egl_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval)
71 {
72 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
73
74 dri3_surf->base.SwapInterval = interval;
75 }
76
77 static void
78 egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
79 int width, int height)
80 {
81 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
82
83 dri3_surf->base.Width = width;
84 dri3_surf->base.Height = height;
85 }
86
87 static bool
88 egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
89 {
90 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
91 _EGLContext *ctx = _eglGetCurrentContext();
92
93 return ctx->Resource.Display == dri3_surf->base.Resource.Display;
94 }
95
96 static __DRIcontext *
97 egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
98 {
99 _EGLContext *ctx = _eglGetCurrentContext();
100 struct dri2_egl_context *dri2_ctx;
101 if (!ctx)
102 return NULL;
103 dri2_ctx = dri2_egl_context(ctx);
104 return dri2_ctx->dri_context;
105 }
106
107 static __DRIscreen *
108 egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
109 {
110 _EGLContext *ctx = _eglGetCurrentContext();
111 struct dri2_egl_context *dri2_ctx;
112 if (!ctx)
113 return NULL;
114 dri2_ctx = dri2_egl_context(ctx);
115 return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;
116 }
117
118 static void
119 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
120 {
121 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
122 _EGLDisplay *disp = dri3_surf->base.Resource.Display;
123
124 dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
125 }
126
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,
136 .show_fps = NULL,
137 };
138
139 static EGLBoolean
140 dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
141 {
142 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
143
144 (void) drv;
145
146 loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
147
148 free(surf);
149
150 return EGL_TRUE;
151 }
152
153 static EGLBoolean
154 dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
155 EGLint interval)
156 {
157 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
158
159 loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
160
161 return EGL_TRUE;
162 }
163
164 static _EGLSurface *
165 dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
166 _EGLConfig *conf, void *native_surface,
167 const EGLint *attrib_list)
168 {
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;
174
175 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
176 drawable = (uintptr_t) native_surface;
177
178 (void) drv;
179
180 dri3_surf = calloc(1, sizeof *dri3_surf);
181 if (!dri3_surf) {
182 _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
183 return NULL;
184 }
185
186 if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))
187 goto cleanup_surf;
188
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);
194 }
195
196 dri_config = dri2_get_dri_config(dri2_conf, type,
197 dri3_surf->base.GLColorspace);
198
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,
203 &egl_dri3_vtable,
204 &dri3_surf->loader_drawable)) {
205 _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
206 goto cleanup_pixmap;
207 }
208
209 return &dri3_surf->base;
210
211 cleanup_pixmap:
212 if (type == EGL_PBUFFER_BIT)
213 xcb_free_pixmap(dri2_dpy->conn, drawable);
214 cleanup_surf:
215 free(dri3_surf);
216
217 return NULL;
218 }
219
220 static int
221 dri3_authenticate(_EGLDisplay *disp, uint32_t id)
222 {
223 #ifdef HAVE_WAYLAND_PLATFORM
224 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
225
226 if (dri2_dpy->device_name) {
227 _eglLog(_EGL_WARNING,
228 "Wayland client render node authentication is unnecessary");
229 return 0;
230 }
231
232 _eglLog(_EGL_WARNING,
233 "Wayland client primary node authentication isn't supported");
234 #endif
235
236 return -1;
237 }
238
239 /**
240 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
241 */
242 static _EGLSurface *
243 dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
244 _EGLConfig *conf, void *native_window,
245 const EGLint *attrib_list)
246 {
247 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
248 _EGLSurface *surf;
249
250 surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
251 native_window, attrib_list);
252 if (surf != NULL)
253 dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
254
255 return surf;
256 }
257
258 static _EGLSurface *
259 dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
260 _EGLConfig *conf, void *native_pixmap,
261 const EGLint *attrib_list)
262 {
263 return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
264 native_pixmap, attrib_list);
265 }
266
267 static _EGLSurface *
268 dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
269 _EGLConfig *conf, const EGLint *attrib_list)
270 {
271 return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
272 XCB_WINDOW_NONE, attrib_list);
273 }
274
275 static EGLBoolean
276 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
277 EGLuint64KHR *ust, EGLuint64KHR *msc,
278 EGLuint64KHR *sbc)
279 {
280 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
281
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;
285 }
286
287 static _EGLImage *
288 dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
289 EGLClientBuffer buffer, const EGLint *attr_list)
290 {
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;
296 unsigned int format;
297
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,
301 bp_cookie, NULL);
302 if (!bp_reply) {
303 _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
304 return NULL;
305 }
306
307 switch (bp_reply->depth) {
308 case 16:
309 format = __DRI_IMAGE_FORMAT_RGB565;
310 break;
311 case 24:
312 format = __DRI_IMAGE_FORMAT_XRGB8888;
313 break;
314 case 32:
315 format = __DRI_IMAGE_FORMAT_ARGB8888;
316 break;
317 default:
318 _eglError(EGL_BAD_PARAMETER,
319 "dri3_create_image_khr: unsupported pixmap depth");
320 free(bp_reply);
321 return EGL_NO_IMAGE_KHR;
322 }
323
324 dri2_img = malloc(sizeof *dri2_img);
325 if (!dri2_img) {
326 _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
327 return EGL_NO_IMAGE_KHR;
328 }
329
330 if (!_eglInitImage(&dri2_img->base, disp)) {
331 free(dri2_img);
332 return EGL_NO_IMAGE_KHR;
333 }
334
335 dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
336 bp_reply,
337 format,
338 dri2_dpy->dri_screen,
339 dri2_dpy->image,
340 dri2_img);
341
342 free(bp_reply);
343
344 return &dri2_img->base;
345 }
346
347 static _EGLImage *
348 dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
349 _EGLContext *ctx, EGLenum target,
350 EGLClientBuffer buffer, const EGLint *attr_list)
351 {
352 (void) drv;
353
354 switch (target) {
355 case EGL_NATIVE_PIXMAP_KHR:
356 return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
357 default:
358 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
359 }
360 }
361
362 /**
363 * Called by the driver when it needs to update the real front buffer with the
364 * contents of its fake front buffer.
365 */
366 static void
367 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
368 {
369 /* There does not seem to be any kind of consensus on whether we should
370 * support front-buffer rendering or not:
371 * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
372 */
373 _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
374 (void) driDrawable;
375 (void) loaderPrivate;
376 }
377
378 const __DRIimageLoaderExtension dri3_image_loader_extension = {
379 .base = { __DRI_IMAGE_LOADER, 1 },
380
381 .getBuffers = loader_dri3_get_buffers,
382 .flushFrontBuffer = dri3_flush_front_buffer,
383 };
384
385 static EGLBoolean
386 dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
387 {
388 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
389
390 /* No-op for a pixmap or pbuffer surface */
391 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
392 return EGL_FALSE;
393
394 return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
395 0, 0, 0, 0,
396 draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
397 }
398
399 static EGLBoolean
400 dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
401 void *native_pixmap_target)
402 {
403 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
404 xcb_pixmap_t target;
405
406 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
407 target = (uintptr_t) native_pixmap_target;
408
409 loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
410 dri3_surf->loader_drawable.drawable);
411
412 return EGL_TRUE;
413 }
414
415 static int
416 dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
417 {
418 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
419
420 return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
421 }
422
423 static EGLBoolean
424 dri3_query_surface(_EGLDriver *drv, _EGLDisplay *dpy,
425 _EGLSurface *surf, EGLint attribute,
426 EGLint *value)
427 {
428 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
429
430 switch (attribute) {
431 case EGL_WIDTH:
432 case EGL_HEIGHT:
433 loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
434 break;
435 default:
436 break;
437 }
438
439 return _eglQuerySurface(drv, dpy, surf, attribute, value);
440 }
441
442 static __DRIdrawable *
443 dri3_get_dri_drawable(_EGLSurface *surf)
444 {
445 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
446
447 return dri3_surf->loader_drawable.dri_drawable;
448 }
449
450 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
451 .authenticate = dri3_authenticate,
452 .create_window_surface = dri3_create_window_surface,
453 .create_pixmap_surface = dri3_create_pixmap_surface,
454 .create_pbuffer_surface = dri3_create_pbuffer_surface,
455 .destroy_surface = dri3_destroy_surface,
456 .create_image = dri3_create_image_khr,
457 .swap_interval = dri3_set_swap_interval,
458 .swap_buffers = dri3_swap_buffers,
459 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
460 .swap_buffers_region = dri2_fallback_swap_buffers_region,
461 .post_sub_buffer = dri2_fallback_post_sub_buffer,
462 .copy_buffers = dri3_copy_buffers,
463 .query_buffer_age = dri3_query_buffer_age,
464 .query_surface = dri3_query_surface,
465 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
466 .get_sync_values = dri3_get_sync_values,
467 .get_dri_drawable = dri3_get_dri_drawable,
468 };
469
470 EGLBoolean
471 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
472 {
473 xcb_dri3_query_version_reply_t *dri3_query;
474 xcb_dri3_query_version_cookie_t dri3_query_cookie;
475 xcb_present_query_version_reply_t *present_query;
476 xcb_present_query_version_cookie_t present_query_cookie;
477 xcb_generic_error_t *error;
478 const xcb_query_extension_reply_t *extension;
479
480 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
481 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
482
483 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
484 if (!(extension && extension->present))
485 return EGL_FALSE;
486
487 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
488 if (!(extension && extension->present))
489 return EGL_FALSE;
490
491 dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
492 XCB_DRI3_MAJOR_VERSION,
493 XCB_DRI3_MINOR_VERSION);
494
495 present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
496 XCB_PRESENT_MAJOR_VERSION,
497 XCB_PRESENT_MINOR_VERSION);
498
499 dri3_query =
500 xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
501 if (dri3_query == NULL || error != NULL) {
502 _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
503 free(dri3_query);
504 free(error);
505 return EGL_FALSE;
506 }
507 free(dri3_query);
508
509 present_query =
510 xcb_present_query_version_reply(dri2_dpy->conn,
511 present_query_cookie, &error);
512 if (present_query == NULL || error != NULL) {
513 _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
514 free(present_query);
515 free(error);
516 return EGL_FALSE;
517 }
518 free(present_query);
519
520 dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
521 if (dri2_dpy->fd < 0) {
522 int conn_error = xcb_connection_has_error(dri2_dpy->conn);
523 _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
524
525 if (conn_error)
526 _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
527
528 return EGL_FALSE;
529 }
530
531 dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
532
533 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
534 if (!dri2_dpy->driver_name) {
535 _eglLog(_EGL_WARNING, "DRI3: No driver found");
536 close(dri2_dpy->fd);
537 return EGL_FALSE;
538 }
539
540 #ifdef HAVE_WAYLAND_PLATFORM
541 /* Only try to get a render device name since dri3 doesn't provide a
542 * mechanism for authenticating client opened device node fds. If this
543 * fails then don't advertise the extension. */
544 dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
545 #endif
546
547 return EGL_TRUE;
548 }