blob: 7bf2c78742ebff8d4810b2ff91ad1f7312fde3e3 [file] [log] [blame]
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Kristian Høgsberg <krh@bitplanet.net>
26 */
27
28#include <stdlib.h>
29#include <string.h>
30#include <stdio.h>
31#include <limits.h>
32#include <dlfcn.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <unistd.h>
Tapani Pällia057b832013-12-01 11:53:55 +020036#ifdef HAVE_LIBDRM
Kristian Høgsberg2889d962011-02-02 22:10:40 -050037#include <xf86drm.h>
Samuel Thibaulta594cec2013-11-10 19:32:01 +010038#endif
Kristian Høgsberg2889d962011-02-02 22:10:40 -050039#include <sys/types.h>
40#include <sys/stat.h>
41
42#include "egl_dri2.h"
Chad Versace8b9298a2014-01-28 12:34:19 -080043#include "egl_dri2_fallbacks.h"
Kristian Høgsberg2889d962011-02-02 22:10:40 -050044
Chad Versacea2187652014-01-27 16:42:10 -080045static EGLBoolean
46dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
47 EGLint interval);
48
Haitao Fengf55d0272011-02-16 23:05:15 -050049static void
50swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
51 struct dri2_egl_surface * dri2_surf,
52 int depth)
53{
54 uint32_t mask;
55 const uint32_t function = GXcopy;
56 uint32_t valgc[2];
57
58 /* create GC's */
59 dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
60 mask = XCB_GC_FUNCTION;
61 xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
62
63 dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
64 mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
65 valgc[0] = function;
66 valgc[1] = False;
67 xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
68 dri2_surf->depth = depth;
69 switch (depth) {
70 case 32:
71 case 24:
72 dri2_surf->bytes_per_pixel = 4;
73 break;
74 case 16:
75 dri2_surf->bytes_per_pixel = 2;
76 break;
77 case 8:
78 dri2_surf->bytes_per_pixel = 1;
79 break;
80 case 0:
81 dri2_surf->bytes_per_pixel = 0;
82 break;
83 default:
84 _eglLog(_EGL_WARNING, "unsupported depth %d", depth);
85 }
86}
87
88static void
89swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
90 struct dri2_egl_surface * dri2_surf)
91{
92 xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
93 xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
94}
95
96static void
97swrastGetDrawableInfo(__DRIdrawable * draw,
98 int *x, int *y, int *w, int *h,
99 void *loaderPrivate)
100{
101 struct dri2_egl_surface *dri2_surf = loaderPrivate;
102 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
103
104 xcb_get_geometry_cookie_t cookie;
105 xcb_get_geometry_reply_t *reply;
106 xcb_generic_error_t *error;
107
108 *w = *h = 0;
109 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
110 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
111 if (reply == NULL)
112 return;
113
114 if (error != NULL) {
115 _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
116 free(error);
117 } else {
118 *w = reply->width;
119 *h = reply->height;
120 }
121 free(reply);
122}
123
124static void
125swrastPutImage(__DRIdrawable * draw, int op,
126 int x, int y, int w, int h,
127 char *data, void *loaderPrivate)
128{
129 struct dri2_egl_surface *dri2_surf = loaderPrivate;
130 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
131
132 xcb_gcontext_t gc;
133
134 switch (op) {
135 case __DRI_SWRAST_IMAGE_OP_DRAW:
136 gc = dri2_surf->gc;
137 break;
138 case __DRI_SWRAST_IMAGE_OP_SWAP:
139 gc = dri2_surf->swapgc;
140 break;
141 default:
142 return;
143 }
144
145 xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
146 gc, w, h, x, y, 0, dri2_surf->depth,
147 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
148}
149
150static void
151swrastGetImage(__DRIdrawable * read,
152 int x, int y, int w, int h,
153 char *data, void *loaderPrivate)
154{
155 struct dri2_egl_surface *dri2_surf = loaderPrivate;
156 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
157
158 xcb_get_image_cookie_t cookie;
159 xcb_get_image_reply_t *reply;
160 xcb_generic_error_t *error;
161
162 cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
163 dri2_surf->drawable, x, y, w, h, ~0);
164 reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
165 if (reply == NULL)
166 return;
167
168 if (error != NULL) {
169 _eglLog(_EGL_WARNING, "error in xcb_get_image");
170 free(error);
171 } else {
172 uint32_t bytes = xcb_get_image_data_length(reply);
173 uint8_t *idata = xcb_get_image_data(reply);
174 memcpy(data, idata, bytes);
175 }
176 free(reply);
177}
178
179
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500180/**
181 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
182 */
183static _EGLSurface *
Chad Versaced019cd82014-01-28 12:47:38 -0800184dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
185 _EGLConfig *conf, EGLNativeWindowType native_window,
186 const EGLint *attrib_list)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500187{
188 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
189 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
190 struct dri2_egl_surface *dri2_surf;
191 xcb_get_geometry_cookie_t cookie;
192 xcb_get_geometry_reply_t *reply;
193 xcb_screen_iterator_t s;
194 xcb_generic_error_t *error;
Eric Anholt31c7d4e2012-09-25 10:09:12 -0700195 xcb_drawable_t window = (uintptr_t )native_window;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500196
197 (void) drv;
198
199 dri2_surf = malloc(sizeof *dri2_surf);
200 if (!dri2_surf) {
201 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
202 return NULL;
203 }
204
205 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
206 goto cleanup_surf;
207
208 dri2_surf->region = XCB_NONE;
209 if (type == EGL_PBUFFER_BIT) {
210 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
211 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
212 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
213 dri2_surf->drawable, s.data->root,
214 dri2_surf->base.Width, dri2_surf->base.Height);
215 } else {
216 dri2_surf->drawable = window;
217 }
218
Haitao Fengf55d0272011-02-16 23:05:15 -0500219 if (dri2_dpy->dri2) {
220 dri2_surf->dri_drawable =
221 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
222 type == EGL_WINDOW_BIT ?
223 dri2_conf->dri_double_config :
224 dri2_conf->dri_single_config,
225 dri2_surf);
226 } else {
227 assert(dri2_dpy->swrast);
228 dri2_surf->dri_drawable =
229 (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
230 dri2_conf->dri_double_config,
231 dri2_surf);
232 }
233
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500234 if (dri2_surf->dri_drawable == NULL) {
235 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
236 goto cleanup_pixmap;
237 }
Haitao Fengf55d0272011-02-16 23:05:15 -0500238
239 if (dri2_dpy->dri2) {
240 xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
241 } else {
Feng, Haitao58f95f92011-03-29 13:41:35 +0800242 swrastCreateDrawable(dri2_dpy, dri2_surf, _eglGetConfigKey(conf, EGL_BUFFER_SIZE));
Haitao Fengf55d0272011-02-16 23:05:15 -0500243 }
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500244
245 if (type != EGL_PBUFFER_BIT) {
246 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
247 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
248 if (reply == NULL || error != NULL) {
249 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
250 free(error);
251 goto cleanup_dri_drawable;
252 }
253
254 dri2_surf->base.Width = reply->width;
255 dri2_surf->base.Height = reply->height;
256 free(reply);
257 }
258
Chia-I Wueb7d1b92011-12-20 17:25:22 +0800259 /* we always copy the back buffer to front */
260 dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
Fredrik Höglund71b8fc92011-12-14 21:24:10 +0100261
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500262 return &dri2_surf->base;
263
264 cleanup_dri_drawable:
265 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
266 cleanup_pixmap:
267 if (type == EGL_PBUFFER_BIT)
268 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
269 cleanup_surf:
270 free(dri2_surf);
271
272 return NULL;
273}
274
275/**
276 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
277 */
278static _EGLSurface *
Chad Versaced019cd82014-01-28 12:47:38 -0800279dri2_x11_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
280 _EGLConfig *conf, EGLNativeWindowType window,
281 const EGLint *attrib_list)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500282{
Eric Anholt7e9bd2b2012-09-25 14:05:30 -0700283 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
284 _EGLSurface *surf;
285
Chad Versaced019cd82014-01-28 12:47:38 -0800286 surf = dri2_x11_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
287 window, attrib_list);
Ian Romanickf730c212013-04-08 20:00:30 -0700288 if (surf != NULL) {
289 /* When we first create the DRI2 drawable, its swap interval on the
290 * server side is 1.
291 */
292 surf->SwapInterval = 1;
Eric Anholt7e9bd2b2012-09-25 14:05:30 -0700293
Ian Romanickf730c212013-04-08 20:00:30 -0700294 /* Override that with a driconf-set value. */
Chad Versacea2187652014-01-27 16:42:10 -0800295 dri2_x11_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
Ian Romanickf730c212013-04-08 20:00:30 -0700296 }
Eric Anholt7e9bd2b2012-09-25 14:05:30 -0700297
298 return surf;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500299}
300
301static _EGLSurface *
Chad Versaced019cd82014-01-28 12:47:38 -0800302dri2_x11_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
303 _EGLConfig *conf, EGLNativePixmapType pixmap,
304 const EGLint *attrib_list)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500305{
Chad Versaced019cd82014-01-28 12:47:38 -0800306 return dri2_x11_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
307 pixmap, attrib_list);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500308}
309
310static _EGLSurface *
Chad Versaced019cd82014-01-28 12:47:38 -0800311dri2_x11_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
312 _EGLConfig *conf, const EGLint *attrib_list)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500313{
Chad Versaced019cd82014-01-28 12:47:38 -0800314 return dri2_x11_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
315 XCB_WINDOW_NONE, attrib_list);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500316}
317
318static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800319dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500320{
321 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
322 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
323
324 (void) drv;
325
326 if (!_eglPutSurface(surf))
327 return EGL_TRUE;
328
329 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
330
Haitao Fengf55d0272011-02-16 23:05:15 -0500331 if (dri2_dpy->dri2) {
332 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
333 } else {
334 assert(dri2_dpy->swrast);
335 swrastDestroyDrawable(dri2_dpy, dri2_surf);
336 }
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500337
338 if (surf->Type == EGL_PBUFFER_BIT)
339 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
340
341 free(surf);
342
343 return EGL_TRUE;
344}
345
346/**
347 * Process list of buffer received from the server
348 *
349 * Processes the list of buffers received in a reply from the server to either
350 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
351 */
352static void
Chad Versaced019cd82014-01-28 12:47:38 -0800353dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
354 xcb_dri2_dri2_buffer_t *buffers, unsigned count)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500355{
356 struct dri2_egl_display *dri2_dpy =
357 dri2_egl_display(dri2_surf->base.Resource.Display);
358 xcb_rectangle_t rectangle;
359 unsigned i;
360
361 dri2_surf->buffer_count = count;
362 dri2_surf->have_fake_front = 0;
363
364 /* This assumes the DRI2 buffer attachment tokens matches the
365 * __DRIbuffer tokens. */
366 for (i = 0; i < count; i++) {
367 dri2_surf->buffers[i].attachment = buffers[i].attachment;
368 dri2_surf->buffers[i].name = buffers[i].name;
369 dri2_surf->buffers[i].pitch = buffers[i].pitch;
370 dri2_surf->buffers[i].cpp = buffers[i].cpp;
371 dri2_surf->buffers[i].flags = buffers[i].flags;
372
373 /* We only use the DRI drivers single buffer configs. This
374 * means that if we try to render to a window, DRI2 will give us
375 * the fake front buffer, which we'll use as a back buffer.
376 * Note that EGL doesn't require that several clients rendering
377 * to the same window must see the same aux buffers. */
378 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
379 dri2_surf->have_fake_front = 1;
380 }
381
382 if (dri2_surf->region != XCB_NONE)
383 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
384
385 rectangle.x = 0;
386 rectangle.y = 0;
387 rectangle.width = dri2_surf->base.Width;
388 rectangle.height = dri2_surf->base.Height;
389 dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
390 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
391}
392
393static __DRIbuffer *
Chad Versaced019cd82014-01-28 12:47:38 -0800394dri2_x11_get_buffers(__DRIdrawable * driDrawable,
395 int *width, int *height,
396 unsigned int *attachments, int count,
397 int *out_count, void *loaderPrivate)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500398{
399 struct dri2_egl_surface *dri2_surf = loaderPrivate;
400 struct dri2_egl_display *dri2_dpy =
401 dri2_egl_display(dri2_surf->base.Resource.Display);
402 xcb_dri2_dri2_buffer_t *buffers;
403 xcb_dri2_get_buffers_reply_t *reply;
404 xcb_dri2_get_buffers_cookie_t cookie;
405
406 (void) driDrawable;
407
408 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
409 dri2_surf->drawable,
410 count, count, attachments);
411 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
412 buffers = xcb_dri2_get_buffers_buffers (reply);
413 if (buffers == NULL)
414 return NULL;
415
416 *out_count = reply->count;
417 dri2_surf->base.Width = *width = reply->width;
418 dri2_surf->base.Height = *height = reply->height;
Chad Versaced019cd82014-01-28 12:47:38 -0800419 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500420
421 free(reply);
422
423 return dri2_surf->buffers;
424}
425
426static __DRIbuffer *
Chad Versaced019cd82014-01-28 12:47:38 -0800427dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
428 int *width, int *height,
429 unsigned int *attachments, int count,
430 int *out_count, void *loaderPrivate)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500431{
432 struct dri2_egl_surface *dri2_surf = loaderPrivate;
433 struct dri2_egl_display *dri2_dpy =
434 dri2_egl_display(dri2_surf->base.Resource.Display);
435 xcb_dri2_dri2_buffer_t *buffers;
436 xcb_dri2_get_buffers_with_format_reply_t *reply;
437 xcb_dri2_get_buffers_with_format_cookie_t cookie;
438 xcb_dri2_attach_format_t *format_attachments;
439
440 (void) driDrawable;
441
442 format_attachments = (xcb_dri2_attach_format_t *) attachments;
443 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
444 dri2_surf->drawable,
445 count, count,
446 format_attachments);
447
448 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
449 cookie, NULL);
450 if (reply == NULL)
451 return NULL;
452
453 buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
454 dri2_surf->base.Width = *width = reply->width;
455 dri2_surf->base.Height = *height = reply->height;
456 *out_count = reply->count;
Chad Versaced019cd82014-01-28 12:47:38 -0800457 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500458
459 free(reply);
460
461 return dri2_surf->buffers;
462}
463
464static void
Chad Versaced019cd82014-01-28 12:47:38 -0800465dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500466{
467 (void) driDrawable;
468
469 /* FIXME: Does EGL support front buffer rendering at all? */
470
471#if 0
472 struct dri2_egl_surface *dri2_surf = loaderPrivate;
473
474 dri2WaitGL(dri2_surf);
475#else
476 (void) loaderPrivate;
477#endif
478}
479
480static char *
Chad Versaced019cd82014-01-28 12:47:38 -0800481dri2_x11_strndup(const char *s, int length)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500482{
483 char *d;
484
485 d = malloc(length + 1);
486 if (d == NULL)
487 return NULL;
488
489 memcpy(d, s, length);
490 d[length] = '\0';
491
492 return d;
493}
494
495static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800496dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500497{
498 xcb_xfixes_query_version_reply_t *xfixes_query;
499 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
500 xcb_dri2_query_version_reply_t *dri2_query;
501 xcb_dri2_query_version_cookie_t dri2_query_cookie;
502 xcb_dri2_connect_reply_t *connect;
503 xcb_dri2_connect_cookie_t connect_cookie;
504 xcb_generic_error_t *error;
505 xcb_screen_iterator_t s;
Benjamin Franzke4ca075a2011-03-02 21:23:04 +0100506 char *driver_name, *device_name;
Benjamin Franzke80636ff2011-06-19 23:48:39 +0200507 const xcb_query_extension_reply_t *extension;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500508
509 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
510 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
511
Benjamin Franzke80636ff2011-06-19 23:48:39 +0200512 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
513 if (!(extension && extension->present))
514 return EGL_FALSE;
515
516 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
517 if (!(extension && extension->present))
518 return EGL_FALSE;
519
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500520 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
521 XCB_XFIXES_MAJOR_VERSION,
522 XCB_XFIXES_MINOR_VERSION);
523
524 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
525 XCB_DRI2_MAJOR_VERSION,
526 XCB_DRI2_MINOR_VERSION);
527
528 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
529 connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
530 s.data->root,
531 XCB_DRI2_DRIVER_TYPE_DRI);
532
533 xfixes_query =
534 xcb_xfixes_query_version_reply (dri2_dpy->conn,
535 xfixes_query_cookie, &error);
536 if (xfixes_query == NULL ||
537 error != NULL || xfixes_query->major_version < 2) {
Haitao Fengf55d0272011-02-16 23:05:15 -0500538 _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500539 free(error);
540 return EGL_FALSE;
541 }
542 free(xfixes_query);
543
544 dri2_query =
545 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
546 if (dri2_query == NULL || error != NULL) {
Haitao Fengf55d0272011-02-16 23:05:15 -0500547 _eglLog(_EGL_WARNING, "DRI2: failed to query version");
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500548 free(error);
549 return EGL_FALSE;
550 }
551 dri2_dpy->dri2_major = dri2_query->major_version;
552 dri2_dpy->dri2_minor = dri2_query->minor_version;
553 free(dri2_query);
554
555 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
556 if (connect == NULL ||
557 connect->driver_name_length + connect->device_name_length == 0) {
Haitao Fengf55d0272011-02-16 23:05:15 -0500558 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500559 return EGL_FALSE;
560 }
561
Benjamin Franzke4ca075a2011-03-02 21:23:04 +0100562 driver_name = xcb_dri2_connect_driver_name (connect);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500563 dri2_dpy->driver_name =
Chad Versaced019cd82014-01-28 12:47:38 -0800564 dri2_x11_strndup(driver_name,
565 xcb_dri2_connect_driver_name_length(connect));
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500566
Benjamin Franzke4ca075a2011-03-02 21:23:04 +0100567 device_name = xcb_dri2_connect_device_name (connect);
Benjamin Franzke4ca075a2011-03-02 21:23:04 +0100568
569 dri2_dpy->device_name =
Chad Versaced019cd82014-01-28 12:47:38 -0800570 dri2_x11_strndup(device_name,
571 xcb_dri2_connect_device_name_length(connect));
Benjamin Franzke4ca075a2011-03-02 21:23:04 +0100572
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500573 if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) {
574 free(dri2_dpy->device_name);
575 free(dri2_dpy->driver_name);
576 free(connect);
577 return EGL_FALSE;
578 }
579 free(connect);
580
581 return EGL_TRUE;
582}
583
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100584static int
585dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500586{
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100587 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500588 xcb_dri2_authenticate_reply_t *authenticate;
589 xcb_dri2_authenticate_cookie_t authenticate_cookie;
590 xcb_screen_iterator_t s;
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100591 int ret = 0;
592
593 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
594 authenticate_cookie =
595 xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, id);
596 authenticate =
597 xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
598
599 if (authenticate == NULL || !authenticate->authenticated)
600 ret = -1;
601
Matt Turner50675062012-09-03 20:24:35 -0700602 free(authenticate);
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100603
604 return ret;
605}
606
607static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800608dri2_x11_local_authenticate(_EGLDisplay *disp)
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100609{
Tapani Pällia057b832013-12-01 11:53:55 +0200610#ifdef HAVE_LIBDRM
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100611 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500612 drm_magic_t magic;
613
614 if (drmGetMagic(dri2_dpy->fd, &magic)) {
Haitao Fengf55d0272011-02-16 23:05:15 -0500615 _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500616 return EGL_FALSE;
617 }
Benjamin Franzke6b369c42011-02-21 16:22:34 +0100618
619 if (dri2_x11_authenticate(disp, magic) < 0) {
Haitao Fengf55d0272011-02-16 23:05:15 -0500620 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500621 return EGL_FALSE;
622 }
Samuel Thibaulta594cec2013-11-10 19:32:01 +0100623#endif
Tapani Pällia057b832013-12-01 11:53:55 +0200624 return EGL_TRUE;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500625}
626
627static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800628dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
629 _EGLDisplay *disp)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500630{
631 xcb_screen_iterator_t s;
632 xcb_depth_iterator_t d;
633 xcb_visualtype_t *visuals;
634 int i, j, id;
Kristian Høgsberge3d0a0e2013-09-14 23:06:36 -0700635 unsigned int rgba_masks[4];
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500636 EGLint surface_type;
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100637 EGLint config_attrs[] = {
638 EGL_NATIVE_VISUAL_ID, 0,
639 EGL_NATIVE_VISUAL_TYPE, 0,
640 EGL_NONE
641 };
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500642
643 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
644 d = xcb_screen_allowed_depths_iterator(s.data);
645 id = 1;
646
647 surface_type =
648 EGL_WINDOW_BIT |
649 EGL_PIXMAP_BIT |
650 EGL_PBUFFER_BIT |
651 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
652
653 while (d.rem > 0) {
654 EGLBoolean class_added[6] = { 0, };
655
656 visuals = xcb_depth_visuals(d.data);
657 for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
658 if (class_added[visuals[i]._class])
659 continue;
660
661 class_added[visuals[i]._class] = EGL_TRUE;
662 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100663 config_attrs[1] = visuals[i].visual_id;
664 config_attrs[3] = visuals[i]._class;
665
Kristian Høgsberge3d0a0e2013-09-14 23:06:36 -0700666 rgba_masks[0] = visuals[i].red_mask;
667 rgba_masks[1] = visuals[i].green_mask;
668 rgba_masks[2] = visuals[i].blue_mask;
669 rgba_masks[3] = 0;
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100670 dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
Kristian Høgsberg44e584a2013-09-14 23:13:22 -0700671 surface_type, config_attrs, rgba_masks);
Kristian Høgsberge3d0a0e2013-09-14 23:06:36 -0700672
673 /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
674 * Otherwise it will only match a 32-bit RGBA visual. On a
675 * composited window manager on X11, this will make all of the
676 * EGLConfigs with destination alpha get blended by the
677 * compositor. This is probably not what the application
678 * wants... especially on drivers that only have 32-bit RGBA
679 * EGLConfigs! */
680 if (d.data->depth == 24) {
681 rgba_masks[3] =
682 ~(rgba_masks[0] | rgba_masks[1] | rgba_masks[2]);
683 dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
Kristian Høgsberg44e584a2013-09-14 23:13:22 -0700684 surface_type, config_attrs, rgba_masks);
Kristian Høgsberge3d0a0e2013-09-14 23:06:36 -0700685 }
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500686 }
687 }
688
689 xcb_depth_next(&d);
690 }
691
692 if (!_eglGetArraySize(disp->Configs)) {
693 _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
694 return EGL_FALSE;
695 }
696
697 return EGL_TRUE;
698}
699
700static EGLBoolean
701dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
702 _EGLSurface *draw, xcb_xfixes_region_t region)
703{
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500704 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
705 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100706 enum xcb_dri2_attachment_t render_attachment;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500707 xcb_dri2_copy_region_cookie_t cookie;
708
Fredrik Höglund352c8892011-12-20 17:38:45 +0100709 /* No-op for a pixmap or pbuffer surface */
710 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
711 return EGL_TRUE;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500712
Fredrik Höglund352c8892011-12-20 17:38:45 +0100713 if (dri2_dpy->flush)
714 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500715
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100716 if (dri2_surf->have_fake_front)
717 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
718 else
719 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500720
721 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
722 dri2_surf->drawable,
723 region,
724 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
Benjamin Franzke87dde5b2011-02-09 15:30:20 +0100725 render_attachment);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500726 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
727
728 return EGL_TRUE;
729}
730
Fredrik Höglund352c8892011-12-20 17:38:45 +0100731static int64_t
Chad Versaced019cd82014-01-28 12:47:38 -0800732dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
733 int64_t msc, int64_t divisor, int64_t remainder)
Fredrik Höglund352c8892011-12-20 17:38:45 +0100734{
Fredrik Höglund352c8892011-12-20 17:38:45 +0100735 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
736 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
737 uint32_t msc_hi = msc >> 32;
738 uint32_t msc_lo = msc & 0xffffffff;
739 uint32_t divisor_hi = divisor >> 32;
740 uint32_t divisor_lo = divisor & 0xffffffff;
741 uint32_t remainder_hi = remainder >> 32;
742 uint32_t remainder_lo = remainder & 0xffffffff;
743 xcb_dri2_swap_buffers_cookie_t cookie;
744 xcb_dri2_swap_buffers_reply_t *reply;
745 int64_t swap_count = -1;
746
747 /* No-op for a pixmap or pbuffer surface */
748 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
749 return 0;
750
751 if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available)
752 return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
753
Fredrik Höglund352c8892011-12-20 17:38:45 +0100754 if (dri2_dpy->flush)
755 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
Fredrik Höglund352c8892011-12-20 17:38:45 +0100756
757 cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
758 msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
759
760 reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
761
762 if (reply) {
763 swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo;
764 free(reply);
765 }
766
Eric Anholteed0a802013-06-21 15:34:52 -0700767 /* Since we aren't watching for the server's invalidate events like we're
768 * supposed to (due to XCB providing no mechanism for filtering the events
769 * the way xlib does), and SwapBuffers is a common cause of invalidate
770 * events, just shove one down to the driver, even though we haven't told
771 * the driver that we're the kind of loader that provides reliable
772 * invalidate events. This causes the driver to request buffers again at
773 * its next draw, so that we get the correct buffers if a pageflip
774 * happened. The driver should still be using the viewport hack to catch
775 * window resizes.
776 */
777 if (dri2_dpy->flush &&
778 dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
779 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
780
Fredrik Höglund352c8892011-12-20 17:38:45 +0100781 return swap_count;
Fredrik Höglund352c8892011-12-20 17:38:45 +0100782}
783
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500784static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800785dri2_x11_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500786{
Haitao Fengf55d0272011-02-16 23:05:15 -0500787 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500788 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
789
Fredrik Höglund352c8892011-12-20 17:38:45 +0100790 if (dri2_dpy->dri2) {
Chad Versaced019cd82014-01-28 12:47:38 -0800791 return dri2_x11_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;
Haitao Fengf55d0272011-02-16 23:05:15 -0500792 } else {
793 assert(dri2_dpy->swrast);
Fredrik Höglund352c8892011-12-20 17:38:45 +0100794
Haitao Fengf55d0272011-02-16 23:05:15 -0500795 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
796 return EGL_TRUE;
797 }
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500798}
799
800static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800801dri2_x11_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp,
802 _EGLSurface *draw,
803 EGLint numRects, const EGLint *rects)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500804{
805 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
806 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
807 EGLBoolean ret;
808 xcb_xfixes_region_t region;
809 xcb_rectangle_t rectangles[16];
810 int i;
811
812 if (numRects > (int)ARRAY_SIZE(rectangles))
813 return dri2_copy_region(drv, disp, draw, dri2_surf->region);
814
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500815 for (i = 0; i < numRects; i++) {
816 rectangles[i].x = rects[i * 4];
Robert Bragg0a523a82012-09-18 16:10:03 +0100817 rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500818 rectangles[i].width = rects[i * 4 + 2];
819 rectangles[i].height = rects[i * 4 + 3];
820 }
821
822 region = xcb_generate_id(dri2_dpy->conn);
823 xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
824 ret = dri2_copy_region(drv, disp, draw, region);
825 xcb_xfixes_destroy_region(dri2_dpy->conn, region);
826
827 return ret;
828}
829
830static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800831dri2_x11_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
Fredrik Höglund71b8fc92011-12-14 21:24:10 +0100832 EGLint x, EGLint y, EGLint width, EGLint height)
833{
Fredrik Höglundf4251892012-11-06 17:36:34 +0100834 const EGLint rect[4] = { x, y, width, height };
Fredrik Höglund71b8fc92011-12-14 21:24:10 +0100835
Chia-I Wueb7d1b92011-12-20 17:25:22 +0800836 if (x < 0 || y < 0 || width < 0 || height < 0)
837 _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
838
Chad Versaced019cd82014-01-28 12:47:38 -0800839 return dri2_x11_swap_buffers_region(drv, disp, draw, 1, rect);
Fredrik Höglund71b8fc92011-12-14 21:24:10 +0100840}
841
842static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800843dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
844 EGLint interval)
Fredrik Höglund655f2c12011-12-20 17:17:02 +0100845{
Fredrik Höglund655f2c12011-12-20 17:17:02 +0100846 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
847 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
848
Fredrik Höglund655f2c12011-12-20 17:17:02 +0100849 if (interval > surf->Config->MaxSwapInterval)
850 interval = surf->Config->MaxSwapInterval;
851 else if (interval < surf->Config->MinSwapInterval)
852 interval = surf->Config->MinSwapInterval;
853
854 if (interval != surf->SwapInterval && dri2_dpy->swap_available)
855 xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
856
857 surf->SwapInterval = interval;
858
859 return EGL_TRUE;
Fredrik Höglund655f2c12011-12-20 17:17:02 +0100860}
861
862static EGLBoolean
Chad Versaced019cd82014-01-28 12:47:38 -0800863dri2_x11_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
864 EGLNativePixmapType native_target)
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500865{
866 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
867 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
868 xcb_gcontext_t gc;
Eric Anholt31c7d4e2012-09-25 10:09:12 -0700869 xcb_pixmap_t target = (uintptr_t )native_target;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500870
871 (void) drv;
872
873 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
874
875 gc = xcb_generate_id(dri2_dpy->conn);
876 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
877 xcb_copy_area(dri2_dpy->conn,
878 dri2_surf->drawable,
879 target,
880 gc,
881 0, 0,
882 0, 0,
883 dri2_surf->base.Width,
884 dri2_surf->base.Height);
885 xcb_free_gc(dri2_dpy->conn, gc);
886
887 return EGL_TRUE;
888}
889
890static _EGLImage *
891dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
892 EGLClientBuffer buffer, const EGLint *attr_list)
893{
894 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
895 struct dri2_egl_image *dri2_img;
896 unsigned int attachments[1];
897 xcb_drawable_t drawable;
898 xcb_dri2_get_buffers_cookie_t buffers_cookie;
899 xcb_dri2_get_buffers_reply_t *buffers_reply;
900 xcb_dri2_dri2_buffer_t *buffers;
901 xcb_get_geometry_cookie_t geometry_cookie;
902 xcb_get_geometry_reply_t *geometry_reply;
903 xcb_generic_error_t *error;
904 int stride, format;
905
906 (void) ctx;
907
José Fonseca6a661892011-05-12 15:12:16 +0100908 drawable = (xcb_drawable_t) (uintptr_t) buffer;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500909 xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
910 attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
911 buffers_cookie =
912 xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
913 drawable, 1, 1, attachments);
914 geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
915 buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
916 buffers_cookie, NULL);
917 buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
918 if (buffers == NULL) {
919 return NULL;
920 }
921
922 geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
923 geometry_cookie, &error);
924 if (geometry_reply == NULL || error != NULL) {
925 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
926 free(error);
927 free(buffers_reply);
Chia-I Wubf0c5652011-02-20 12:23:54 -0700928 return NULL;
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500929 }
930
931 switch (geometry_reply->depth) {
932 case 16:
933 format = __DRI_IMAGE_FORMAT_RGB565;
934 break;
935 case 24:
936 format = __DRI_IMAGE_FORMAT_XRGB8888;
937 break;
938 case 32:
939 format = __DRI_IMAGE_FORMAT_ARGB8888;
940 break;
941 default:
942 _eglError(EGL_BAD_PARAMETER,
943 "dri2_create_image_khr: unsupported pixmap depth");
944 free(buffers_reply);
945 free(geometry_reply);
946 return NULL;
947 }
948
949 dri2_img = malloc(sizeof *dri2_img);
950 if (!dri2_img) {
951 free(buffers_reply);
952 free(geometry_reply);
953 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
954 return EGL_NO_IMAGE_KHR;
955 }
956
957 if (!_eglInitImage(&dri2_img->base, disp)) {
958 free(buffers_reply);
959 free(geometry_reply);
Völgyes Dávidf747d032011-07-06 10:10:20 -0400960 free(dri2_img);
Kristian Høgsberg2889d962011-02-02 22:10:40 -0500961 return EGL_NO_IMAGE_KHR;
962 }
963
964 stride = buffers[0].pitch / buffers[0].cpp;
965 dri2_img->dri_image =
966 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
967 buffers_reply->width,
968 buffers_reply->height,
969 format,
970 buffers[0].name,
971 stride,
972 dri2_img);
973
974 free(buffers_reply);
975 free(geometry_reply);
976
977 return &dri2_img->base;
978}
979
980static _EGLImage *
981dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
982 _EGLContext *ctx, EGLenum target,
983 EGLClientBuffer buffer, const EGLint *attr_list)
984{
985 (void) drv;
986
987 switch (target) {
988 case EGL_NATIVE_PIXMAP_KHR:
989 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
990 default:
991 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
992 }
993}
994
Chad Versace90502b12014-01-28 11:41:46 -0800995static struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
996 .authenticate = NULL,
Chad Versace0a0c8812014-01-28 16:39:09 -0800997 .create_window_surface = dri2_x11_create_window_surface,
Chad Versacebc8b07a2014-01-28 16:45:07 -0800998 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
Chad Versacebf200762014-01-28 17:03:03 -0800999 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
Chad Versace958dd802014-01-28 17:03:03 -08001000 .destroy_surface = dri2_x11_destroy_surface,
Chad Versace8b9298a2014-01-28 12:34:19 -08001001 .swap_interval = dri2_fallback_swap_interval,
Chad Versacead173bc2014-01-28 16:21:21 -08001002 .swap_buffers = dri2_x11_swap_buffers,
Chad Versace75d398e2014-01-28 17:03:03 -08001003 .swap_buffers_region = dri2_fallback_swap_buffers_region,
Chad Versacebc2cbc02014-01-28 17:03:03 -08001004 .copy_buffers = dri2_x11_copy_buffers,
Chad Versace3fdfbd22014-01-28 17:03:03 -08001005 .query_buffer_age = dri2_fallback_query_buffer_age,
Chad Versace90502b12014-01-28 11:41:46 -08001006};
1007
1008static struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1009 .authenticate = dri2_x11_authenticate,
Chad Versace0a0c8812014-01-28 16:39:09 -08001010 .create_window_surface = dri2_x11_create_window_surface,
Chad Versacebc8b07a2014-01-28 16:45:07 -08001011 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
Chad Versacebf200762014-01-28 17:03:03 -08001012 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
Chad Versace958dd802014-01-28 17:03:03 -08001013 .destroy_surface = dri2_x11_destroy_surface,
Chad Versace8b9298a2014-01-28 12:34:19 -08001014 .swap_interval = dri2_x11_swap_interval,
Chad Versacead173bc2014-01-28 16:21:21 -08001015 .swap_buffers = dri2_x11_swap_buffers,
Chad Versaced03948a2014-01-28 16:26:44 -08001016 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
Chad Versace75d398e2014-01-28 17:03:03 -08001017 .swap_buffers_region = dri2_x11_swap_buffers_region,
Chad Versacebc2cbc02014-01-28 17:03:03 -08001018 .copy_buffers = dri2_x11_copy_buffers,
Chad Versace3fdfbd22014-01-28 17:03:03 -08001019 .query_buffer_age = dri2_fallback_query_buffer_age,
Chad Versace90502b12014-01-28 11:41:46 -08001020};
1021
Haitao Fengf55d0272011-02-16 23:05:15 -05001022static EGLBoolean
1023dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1024{
1025 struct dri2_egl_display *dri2_dpy;
1026
Haitao Fengf55d0272011-02-16 23:05:15 -05001027 drv->API.CreateImageKHR = NULL;
1028 drv->API.DestroyImageKHR = NULL;
1029 drv->API.CreateDRMImageMESA = NULL;
1030 drv->API.ExportDRMImageMESA = NULL;
1031
Matt Turner6bda0272012-09-04 23:09:22 -07001032 dri2_dpy = calloc(1, sizeof *dri2_dpy);
Haitao Fengf55d0272011-02-16 23:05:15 -05001033 if (!dri2_dpy)
1034 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1035
Haitao Fengf55d0272011-02-16 23:05:15 -05001036 disp->DriverData = (void *) dri2_dpy;
1037 if (disp->PlatformDisplay == NULL) {
1038 dri2_dpy->conn = xcb_connect(0, 0);
1039 } else {
1040 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
1041 }
1042
1043 if (xcb_connection_has_error(dri2_dpy->conn)) {
1044 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
1045 goto cleanup_dpy;
1046 }
1047
Chia-I Wucf69eea2011-06-08 16:33:55 +08001048 if (!dri2_load_driver_swrast(disp))
Haitao Fengf55d0272011-02-16 23:05:15 -05001049 goto cleanup_conn;
1050
1051 dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER;
1052 dri2_dpy->swrast_loader_extension.base.version = __DRI_SWRAST_LOADER_VERSION;
1053 dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo;
1054 dri2_dpy->swrast_loader_extension.putImage = swrastPutImage;
1055 dri2_dpy->swrast_loader_extension.getImage = swrastGetImage;
1056
1057 dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base;
1058 dri2_dpy->extensions[1] = NULL;
1059 dri2_dpy->extensions[2] = NULL;
1060
1061 if (!dri2_create_screen(disp))
1062 goto cleanup_driver;
1063
1064 if (dri2_dpy->conn) {
Chad Versaced019cd82014-01-28 12:47:38 -08001065 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
Haitao Fengf55d0272011-02-16 23:05:15 -05001066 goto cleanup_configs;
1067 }
1068
1069 /* we're supporting EGL 1.4 */
1070 disp->VersionMajor = 1;
1071 disp->VersionMinor = 4;
1072
Chad Versace90502b12014-01-28 11:41:46 -08001073 /* Fill vtbl last to prevent accidentally calling virtual function during
1074 * initialization.
1075 */
1076 dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1077
Haitao Fengf55d0272011-02-16 23:05:15 -05001078 return EGL_TRUE;
1079
1080 cleanup_configs:
1081 _eglCleanupDisplay(disp);
1082 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1083 cleanup_driver:
1084 dlclose(dri2_dpy->driver);
1085 cleanup_conn:
1086 if (disp->PlatformDisplay == NULL)
1087 xcb_disconnect(dri2_dpy->conn);
1088 cleanup_dpy:
1089 free(dri2_dpy);
1090
1091 return EGL_FALSE;
1092}
1093
Eric Anholt7e9bd2b2012-09-25 14:05:30 -07001094static void
Chad Versaced019cd82014-01-28 12:47:38 -08001095dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
Eric Anholt7e9bd2b2012-09-25 14:05:30 -07001096{
1097 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1098 int arbitrary_max_interval = 1000;
1099
1100 /* default behavior for no SwapBuffers support: no vblank syncing
1101 * either.
1102 */
1103 dri2_dpy->min_swap_interval = 0;
1104 dri2_dpy->max_swap_interval = 0;
1105
1106 if (!dri2_dpy->swap_available)
1107 return;
1108
1109 /* If we do have swapbuffers, then we can support pretty much any swap
1110 * interval, but we allow driconf to override applications.
1111 */
1112 if (dri2_dpy->config)
1113 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
1114 "vblank_mode", &vblank_mode);
1115 switch (vblank_mode) {
1116 case DRI_CONF_VBLANK_NEVER:
1117 dri2_dpy->min_swap_interval = 0;
1118 dri2_dpy->max_swap_interval = 0;
1119 dri2_dpy->default_swap_interval = 0;
1120 break;
1121 case DRI_CONF_VBLANK_ALWAYS_SYNC:
1122 dri2_dpy->min_swap_interval = 1;
1123 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1124 dri2_dpy->default_swap_interval = 1;
1125 break;
1126 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
1127 dri2_dpy->min_swap_interval = 0;
1128 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1129 dri2_dpy->default_swap_interval = 0;
1130 break;
1131 default:
1132 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
1133 dri2_dpy->min_swap_interval = 0;
1134 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1135 dri2_dpy->default_swap_interval = 1;
1136 break;
1137 }
1138}
Haitao Fengf55d0272011-02-16 23:05:15 -05001139
1140static EGLBoolean
1141dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001142{
1143 struct dri2_egl_display *dri2_dpy;
1144
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001145 drv->API.CreateImageKHR = dri2_x11_create_image_khr;
Chad Versaced019cd82014-01-28 12:47:38 -08001146 drv->API.PostSubBufferNV = dri2_x11_post_sub_buffer;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001147
Matt Turner6bda0272012-09-04 23:09:22 -07001148 dri2_dpy = calloc(1, sizeof *dri2_dpy);
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001149 if (!dri2_dpy)
1150 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1151
1152 disp->DriverData = (void *) dri2_dpy;
1153 if (disp->PlatformDisplay == NULL) {
1154 dri2_dpy->conn = xcb_connect(0, 0);
1155 } else {
1156 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
1157 }
1158
1159 if (xcb_connection_has_error(dri2_dpy->conn)) {
1160 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
1161 goto cleanup_dpy;
1162 }
1163
1164 if (dri2_dpy->conn) {
Chad Versaced019cd82014-01-28 12:47:38 -08001165 if (!dri2_x11_connect(dri2_dpy))
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001166 goto cleanup_conn;
1167 }
1168
1169 if (!dri2_load_driver(disp))
1170 goto cleanup_conn;
1171
David Friesb6012062011-12-10 11:28:45 -06001172#ifdef O_CLOEXEC
Kristian Høgsberg55a629c2011-04-07 18:27:06 -04001173 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
David Friesb6012062011-12-10 11:28:45 -06001174 if (dri2_dpy->fd == -1 && errno == EINVAL)
1175#endif
1176 {
1177 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
1178 if (dri2_dpy->fd != -1)
1179 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
1180 FD_CLOEXEC);
1181 }
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001182 if (dri2_dpy->fd == -1) {
1183 _eglLog(_EGL_WARNING,
1184 "DRI2: could not open %s (%s)", dri2_dpy->device_name,
1185 strerror(errno));
1186 goto cleanup_driver;
1187 }
1188
1189 if (dri2_dpy->conn) {
Chad Versaced019cd82014-01-28 12:47:38 -08001190 if (!dri2_x11_local_authenticate(disp))
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001191 goto cleanup_fd;
1192 }
1193
1194 if (dri2_dpy->dri2_minor >= 1) {
Haitao Feng3104e5c2011-02-09 15:05:11 +08001195 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1196 dri2_dpy->dri2_loader_extension.base.version = 3;
Chad Versaced019cd82014-01-28 12:47:38 -08001197 dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers;
1198 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer;
Haitao Feng3104e5c2011-02-09 15:05:11 +08001199 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
Chad Versaced019cd82014-01-28 12:47:38 -08001200 dri2_x11_get_buffers_with_format;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001201 } else {
Haitao Feng3104e5c2011-02-09 15:05:11 +08001202 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1203 dri2_dpy->dri2_loader_extension.base.version = 2;
Chad Versaced019cd82014-01-28 12:47:38 -08001204 dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers;
1205 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer;
Haitao Feng3104e5c2011-02-09 15:05:11 +08001206 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001207 }
1208
Haitao Feng3104e5c2011-02-09 15:05:11 +08001209 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001210 dri2_dpy->extensions[1] = &image_lookup_extension.base;
1211 dri2_dpy->extensions[2] = NULL;
1212
Fredrik Höglund655f2c12011-12-20 17:17:02 +01001213 dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
Fredrik Höglund352c8892011-12-20 17:38:45 +01001214 dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
Fredrik Höglund655f2c12011-12-20 17:17:02 +01001215
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001216 if (!dri2_create_screen(disp))
1217 goto cleanup_fd;
1218
Chad Versaced019cd82014-01-28 12:47:38 -08001219 dri2_x11_setup_swap_interval(dri2_dpy);
1220
1221 if (dri2_dpy->conn) {
1222 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
1223 goto cleanup_configs;
1224 }
Ralf Jung3998f8c2013-04-09 14:09:50 +02001225
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001226 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001227 disp->Extensions.NOK_swap_region = EGL_TRUE;
1228 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
Fredrik Höglund71b8fc92011-12-14 21:24:10 +01001229 disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001230
Benjamin Franzke6b369c42011-02-21 16:22:34 +01001231#ifdef HAVE_WAYLAND_PLATFORM
1232 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1233#endif
Tapani Pällif8c5b8a2014-01-08 15:17:58 +02001234
1235 if (dri2_dpy->conn) {
Chad Versaced019cd82014-01-28 12:47:38 -08001236 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
Tapani Pällif8c5b8a2014-01-08 15:17:58 +02001237 goto cleanup_configs;
1238 }
1239
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001240 /* we're supporting EGL 1.4 */
1241 disp->VersionMajor = 1;
1242 disp->VersionMinor = 4;
1243
Chad Versace90502b12014-01-28 11:41:46 -08001244 /* Fill vtbl last to prevent accidentally calling virtual function during
1245 * initialization.
1246 */
1247 dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1248
Kristian Høgsberg2889d962011-02-02 22:10:40 -05001249 return EGL_TRUE;
1250
1251 cleanup_configs:
1252 _eglCleanupDisplay(disp);
1253 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1254 cleanup_fd:
1255 close(dri2_dpy->fd);
1256 cleanup_driver:
1257 dlclose(dri2_dpy->driver);
1258 cleanup_conn:
1259 if (disp->PlatformDisplay == NULL)
1260 xcb_disconnect(dri2_dpy->conn);
1261 cleanup_dpy:
1262 free(dri2_dpy);
1263
1264 return EGL_FALSE;
1265}
Haitao Fengf55d0272011-02-16 23:05:15 -05001266
1267EGLBoolean
1268dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
1269{
1270 EGLBoolean initialized = EGL_TRUE;
1271
1272 int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
1273
1274 if (x11_dri2_accel) {
1275 if (!dri2_initialize_x11_dri2(drv, disp)) {
1276 initialized = dri2_initialize_x11_swrast(drv, disp);
1277 }
1278 } else {
1279 initialized = dri2_initialize_x11_swrast(drv, disp);
1280 }
1281
1282 return initialized;
1283}
1284