st/egl: Fix DRI2 on old X servers
[mesa.git] / src / gallium / state_trackers / egl / x11 / native_dri2.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.8
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "util/u_memory.h"
27 #include "util/u_math.h"
28 #include "util/u_format.h"
29 #include "util/u_inlines.h"
30 #include "util/u_hash_table.h"
31 #include "pipe/p_compiler.h"
32 #include "pipe/p_screen.h"
33 #include "pipe/p_context.h"
34 #include "pipe/p_state.h"
35 #include "state_tracker/drm_api.h"
36 #include "egllog.h"
37
38 #include "native_x11.h"
39 #include "x11_screen.h"
40
41 enum dri2_surface_type {
42 DRI2_SURFACE_TYPE_WINDOW,
43 DRI2_SURFACE_TYPE_PIXMAP,
44 };
45
46 struct dri2_display {
47 struct native_display base;
48 Display *dpy;
49 boolean own_dpy;
50
51 struct native_event_handler *event_handler;
52
53 struct drm_api *api;
54 struct x11_screen *xscr;
55 int xscr_number;
56 const char *dri_driver;
57 int dri_major, dri_minor;
58
59 struct dri2_config *configs;
60 int num_configs;
61
62 struct util_hash_table *surfaces;
63 };
64
65 struct dri2_surface {
66 struct native_surface base;
67 Drawable drawable;
68 enum dri2_surface_type type;
69 enum pipe_format color_format;
70 struct dri2_display *dri2dpy;
71
72 unsigned int server_stamp;
73 unsigned int client_stamp;
74 int width, height;
75 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
76 uint valid_mask;
77
78 boolean have_back, have_fake;
79
80 struct x11_drawable_buffer *last_xbufs;
81 int last_num_xbufs;
82 };
83
84 struct dri2_config {
85 struct native_config base;
86 };
87
88 static INLINE struct dri2_display *
89 dri2_display(const struct native_display *ndpy)
90 {
91 return (struct dri2_display *) ndpy;
92 }
93
94 static INLINE struct dri2_surface *
95 dri2_surface(const struct native_surface *nsurf)
96 {
97 return (struct dri2_surface *) nsurf;
98 }
99
100 static INLINE struct dri2_config *
101 dri2_config(const struct native_config *nconf)
102 {
103 return (struct dri2_config *) nconf;
104 }
105
106 /**
107 * Process the buffers returned by the server.
108 */
109 static void
110 dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
111 struct x11_drawable_buffer *xbufs,
112 int num_xbufs)
113 {
114 struct dri2_surface *dri2surf = dri2_surface(nsurf);
115 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
116 struct pipe_resource templ;
117 struct winsys_handle whandle;
118 uint valid_mask;
119 int i;
120
121 /* free the old textures */
122 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
123 pipe_resource_reference(&dri2surf->textures[i], NULL);
124 dri2surf->valid_mask = 0x0;
125
126 dri2surf->have_back = FALSE;
127 dri2surf->have_fake = FALSE;
128
129 if (!xbufs)
130 return;
131
132 memset(&templ, 0, sizeof(templ));
133 templ.target = PIPE_TEXTURE_2D;
134 templ.last_level = 0;
135 templ.width0 = dri2surf->width;
136 templ.height0 = dri2surf->height;
137 templ.depth0 = 1;
138 templ.format = dri2surf->color_format;
139 templ.bind = PIPE_BIND_RENDER_TARGET;
140
141 valid_mask = 0x0;
142 for (i = 0; i < num_xbufs; i++) {
143 struct x11_drawable_buffer *xbuf = &xbufs[i];
144 const char *desc;
145 enum native_attachment natt;
146
147 switch (xbuf->attachment) {
148 case DRI2BufferFrontLeft:
149 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
150 desc = "DRI2 Front Buffer";
151 break;
152 case DRI2BufferFakeFrontLeft:
153 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
154 desc = "DRI2 Fake Front Buffer";
155 dri2surf->have_fake = TRUE;
156 break;
157 case DRI2BufferBackLeft:
158 natt = NATIVE_ATTACHMENT_BACK_LEFT;
159 desc = "DRI2 Back Buffer";
160 dri2surf->have_back = TRUE;
161 break;
162 default:
163 desc = NULL;
164 break;
165 }
166
167 if (!desc || dri2surf->textures[natt]) {
168 if (!desc)
169 _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
170 else
171 _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
172 continue;
173 }
174
175 memset(&whandle, 0, sizeof(whandle));
176 whandle.stride = xbuf->pitch;
177 whandle.handle = xbuf->name;
178 dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle(
179 dri2dpy->base.screen, &templ, &whandle);
180 if (dri2surf->textures[natt])
181 valid_mask |= 1 << natt;
182 }
183
184 dri2surf->valid_mask = valid_mask;
185 }
186
187 /**
188 * Get the buffers from the server.
189 */
190 static void
191 dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
192 {
193 struct dri2_surface *dri2surf = dri2_surface(nsurf);
194 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
195 unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
196 int num_ins, num_outs, att;
197 struct x11_drawable_buffer *xbufs;
198 /* XXX check if the server supports with format */
199 boolean with_format = FALSE;
200
201
202 /* We must get the front on servers which doesn't support with format
203 * due to a silly bug in core dri2. You can't copy to/from a buffer
204 * that you haven't requested and you recive BadValue errors */
205 if (!with_format)
206 buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
207
208 /* prepare the attachments */
209 num_ins = 0;
210 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
211 if (native_attachment_mask_test(buffer_mask, att)) {
212 unsigned int dri2att;
213
214 switch (att) {
215 case NATIVE_ATTACHMENT_FRONT_LEFT:
216 dri2att = DRI2BufferFrontLeft;
217 break;
218 case NATIVE_ATTACHMENT_BACK_LEFT:
219 dri2att = DRI2BufferBackLeft;
220 break;
221 case NATIVE_ATTACHMENT_FRONT_RIGHT:
222 dri2att = DRI2BufferFrontRight;
223 break;
224 case NATIVE_ATTACHMENT_BACK_RIGHT:
225 dri2att = DRI2BufferBackRight;
226 break;
227 default:
228 assert(0);
229 dri2att = 0;
230 break;
231 }
232
233 dri2atts[num_ins] = dri2att;
234 num_ins++;
235 }
236 }
237
238 xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
239 &dri2surf->width, &dri2surf->height,
240 dri2atts, with_format, num_ins, &num_outs);
241
242 /* we should be able to do better... */
243 if (xbufs && dri2surf->last_num_xbufs == num_outs &&
244 memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
245 FREE(xbufs);
246 dri2surf->client_stamp = dri2surf->server_stamp;
247 return;
248 }
249
250 dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
251
252 dri2surf->server_stamp++;
253 dri2surf->client_stamp = dri2surf->server_stamp;
254
255 if (dri2surf->last_xbufs)
256 FREE(dri2surf->last_xbufs);
257 dri2surf->last_xbufs = xbufs;
258 dri2surf->last_num_xbufs = num_outs;
259 }
260
261 /**
262 * Update the buffers of the surface. This is a slow function due to the
263 * round-trip to the server.
264 */
265 static boolean
266 dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
267 {
268 struct dri2_surface *dri2surf = dri2_surface(nsurf);
269
270 dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
271
272 return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
273 }
274
275 /**
276 * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
277 */
278 static INLINE boolean
279 dri2_surface_receive_events(struct native_surface *nsurf)
280 {
281 struct dri2_surface *dri2surf = dri2_surface(nsurf);
282 return (dri2surf->dri2dpy->dri_minor >= 3);
283 }
284
285 static boolean
286 dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
287 {
288 struct dri2_surface *dri2surf = dri2_surface(nsurf);
289 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
290
291 /* copy to real front buffer */
292 if (dri2surf->have_fake)
293 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
294 0, 0, dri2surf->width, dri2surf->height,
295 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
296
297 /* force buffers to be updated in next validation call */
298 if (!dri2_surface_receive_events(&dri2surf->base)) {
299 dri2surf->server_stamp++;
300 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
301 &dri2surf->base, dri2surf->server_stamp);
302 }
303
304 return TRUE;
305 }
306
307 static boolean
308 dri2_surface_swap_buffers(struct native_surface *nsurf)
309 {
310 struct dri2_surface *dri2surf = dri2_surface(nsurf);
311 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
312
313 /* copy to front buffer */
314 if (dri2surf->have_back)
315 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
316 0, 0, dri2surf->width, dri2surf->height,
317 DRI2BufferBackLeft, DRI2BufferFrontLeft);
318
319 /* and update fake front buffer */
320 if (dri2surf->have_fake)
321 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
322 0, 0, dri2surf->width, dri2surf->height,
323 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
324
325 /* force buffers to be updated in next validation call */
326 if (!dri2_surface_receive_events(&dri2surf->base)) {
327 dri2surf->server_stamp++;
328 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
329 &dri2surf->base, dri2surf->server_stamp);
330 }
331
332 return TRUE;
333 }
334
335 static boolean
336 dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
337 unsigned int *seq_num, struct pipe_resource **textures,
338 int *width, int *height)
339 {
340 struct dri2_surface *dri2surf = dri2_surface(nsurf);
341
342 if (dri2surf->server_stamp != dri2surf->client_stamp ||
343 (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
344 if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
345 return FALSE;
346 }
347
348 if (seq_num)
349 *seq_num = dri2surf->client_stamp;
350
351 if (textures) {
352 int att;
353 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
354 if (native_attachment_mask_test(attachment_mask, att)) {
355 struct pipe_resource *ptex = dri2surf->textures[att];
356
357 textures[att] = NULL;
358 pipe_resource_reference(&textures[att], ptex);
359 }
360 }
361 }
362
363 if (width)
364 *width = dri2surf->width;
365 if (height)
366 *height = dri2surf->height;
367
368 return TRUE;
369 }
370
371 static void
372 dri2_surface_wait(struct native_surface *nsurf)
373 {
374 struct dri2_surface *dri2surf = dri2_surface(nsurf);
375 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
376
377 if (dri2surf->have_fake) {
378 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
379 0, 0, dri2surf->width, dri2surf->height,
380 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
381 }
382 }
383
384 static void
385 dri2_surface_destroy(struct native_surface *nsurf)
386 {
387 struct dri2_surface *dri2surf = dri2_surface(nsurf);
388 int i;
389
390 if (dri2surf->last_xbufs)
391 FREE(dri2surf->last_xbufs);
392
393 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
394 struct pipe_resource *ptex = dri2surf->textures[i];
395 pipe_resource_reference(&ptex, NULL);
396 }
397
398 if (dri2surf->drawable) {
399 x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
400 dri2surf->drawable, FALSE);
401
402 util_hash_table_remove(dri2surf->dri2dpy->surfaces,
403 (void *) dri2surf->drawable);
404 }
405 FREE(dri2surf);
406 }
407
408 static struct dri2_surface *
409 dri2_display_create_surface(struct native_display *ndpy,
410 enum dri2_surface_type type,
411 Drawable drawable,
412 const struct native_config *nconf)
413 {
414 struct dri2_display *dri2dpy = dri2_display(ndpy);
415 struct dri2_config *dri2conf = dri2_config(nconf);
416 struct dri2_surface *dri2surf;
417
418 dri2surf = CALLOC_STRUCT(dri2_surface);
419 if (!dri2surf)
420 return NULL;
421
422 dri2surf->dri2dpy = dri2dpy;
423 dri2surf->type = type;
424 dri2surf->drawable = drawable;
425 dri2surf->color_format = dri2conf->base.color_format;
426
427 dri2surf->base.destroy = dri2_surface_destroy;
428 dri2surf->base.swap_buffers = dri2_surface_swap_buffers;
429 dri2surf->base.flush_frontbuffer = dri2_surface_flush_frontbuffer;
430 dri2surf->base.validate = dri2_surface_validate;
431 dri2surf->base.wait = dri2_surface_wait;
432
433 if (drawable) {
434 x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
435 /* initialize the geometry */
436 dri2_surface_update_buffers(&dri2surf->base, 0x0);
437
438 util_hash_table_set(dri2surf->dri2dpy->surfaces,
439 (void *) dri2surf->drawable, (void *) &dri2surf->base);
440 }
441
442 return dri2surf;
443 }
444
445 static struct native_surface *
446 dri2_display_create_window_surface(struct native_display *ndpy,
447 EGLNativeWindowType win,
448 const struct native_config *nconf)
449 {
450 struct dri2_surface *dri2surf;
451
452 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_WINDOW,
453 (Drawable) win, nconf);
454 return (dri2surf) ? &dri2surf->base : NULL;
455 }
456
457 static struct native_surface *
458 dri2_display_create_pixmap_surface(struct native_display *ndpy,
459 EGLNativePixmapType pix,
460 const struct native_config *nconf)
461 {
462 struct dri2_surface *dri2surf;
463
464 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PIXMAP,
465 (Drawable) pix, nconf);
466 return (dri2surf) ? &dri2surf->base : NULL;
467 }
468
469 static int
470 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
471 {
472 int count = 0;
473
474 switch (mode->rgbBits) {
475 case 32:
476 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
477 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
478 break;
479 case 24:
480 formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
481 formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
482 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
483 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
484 break;
485 case 16:
486 formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
487 break;
488 default:
489 break;
490 }
491
492 return count;
493 }
494
495 static boolean
496 is_format_supported(struct pipe_screen *screen,
497 enum pipe_format fmt, boolean is_color)
498 {
499 return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D,
500 (is_color) ? PIPE_BIND_RENDER_TARGET :
501 PIPE_BIND_DEPTH_STENCIL, 0);
502 }
503
504 static boolean
505 dri2_display_convert_config(struct native_display *ndpy,
506 const __GLcontextModes *mode,
507 struct native_config *nconf)
508 {
509 enum pipe_format formats[32];
510 int num_formats, i;
511
512 if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
513 return FALSE;
514
515 /* skip single-buffered configs */
516 if (!mode->doubleBufferMode)
517 return FALSE;
518
519 /* only interested in native renderable configs */
520 if (!mode->xRenderable || !mode->drawableType)
521 return FALSE;
522
523 nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
524 if (mode->doubleBufferMode)
525 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
526 if (mode->stereoMode) {
527 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
528 if (mode->doubleBufferMode)
529 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
530 }
531
532 /* choose color format */
533 num_formats = choose_color_format(mode, formats);
534 for (i = 0; i < num_formats; i++) {
535 if (is_format_supported(ndpy->screen, formats[i], TRUE)) {
536 nconf->color_format = formats[i];
537 break;
538 }
539 }
540 if (nconf->color_format == PIPE_FORMAT_NONE)
541 return FALSE;
542
543 if (mode->drawableType & GLX_WINDOW_BIT)
544 nconf->window_bit = TRUE;
545 if (mode->drawableType & GLX_PIXMAP_BIT)
546 nconf->pixmap_bit = TRUE;
547
548 nconf->native_visual_id = mode->visualID;
549 nconf->native_visual_type = mode->visualType;
550 nconf->level = mode->level;
551 nconf->samples = mode->samples;
552
553 nconf->slow_config = (mode->visualRating == GLX_SLOW_CONFIG);
554
555 if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
556 nconf->transparent_rgb = TRUE;
557 nconf->transparent_rgb_values[0] = mode->transparentRed;
558 nconf->transparent_rgb_values[1] = mode->transparentGreen;
559 nconf->transparent_rgb_values[2] = mode->transparentBlue;
560 }
561
562 return TRUE;
563 }
564
565 static const struct native_config **
566 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
567 {
568 struct dri2_display *dri2dpy = dri2_display(ndpy);
569 const struct native_config **configs;
570 int i;
571
572 /* first time */
573 if (!dri2dpy->configs) {
574 const __GLcontextModes *modes;
575 int num_modes, count;
576
577 modes = x11_screen_get_glx_configs(dri2dpy->xscr);
578 if (!modes)
579 return NULL;
580 num_modes = x11_context_modes_count(modes);
581
582 dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
583 if (!dri2dpy->configs)
584 return NULL;
585
586 count = 0;
587 for (i = 0; i < num_modes; i++) {
588 struct native_config *nconf = &dri2dpy->configs[count].base;
589 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf))
590 count++;
591 modes = modes->next;
592 }
593
594 dri2dpy->num_configs = count;
595 }
596
597 configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
598 if (configs) {
599 for (i = 0; i < dri2dpy->num_configs; i++)
600 configs[i] = (const struct native_config *) &dri2dpy->configs[i];
601 if (num_configs)
602 *num_configs = dri2dpy->num_configs;
603 }
604
605 return configs;
606 }
607
608 static boolean
609 dri2_display_is_pixmap_supported(struct native_display *ndpy,
610 EGLNativePixmapType pix,
611 const struct native_config *nconf)
612 {
613 struct dri2_display *dri2dpy = dri2_display(ndpy);
614 uint depth, nconf_depth;
615
616 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
617 nconf_depth = util_format_get_blocksizebits(nconf->color_format);
618
619 /* simple depth match for now */
620 return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
621 }
622
623 static int
624 dri2_display_get_param(struct native_display *ndpy,
625 enum native_param_type param)
626 {
627 int val;
628
629 switch (param) {
630 case NATIVE_PARAM_USE_NATIVE_BUFFER:
631 /* DRI2GetBuffers use the native buffers */
632 val = TRUE;
633 break;
634 default:
635 val = 0;
636 break;
637 }
638
639 return val;
640 }
641
642 static void
643 dri2_display_destroy(struct native_display *ndpy)
644 {
645 struct dri2_display *dri2dpy = dri2_display(ndpy);
646
647 if (dri2dpy->configs)
648 FREE(dri2dpy->configs);
649
650 if (dri2dpy->base.screen)
651 dri2dpy->base.screen->destroy(dri2dpy->base.screen);
652
653 if (dri2dpy->surfaces)
654 util_hash_table_destroy(dri2dpy->surfaces);
655
656 if (dri2dpy->xscr)
657 x11_screen_destroy(dri2dpy->xscr);
658 if (dri2dpy->own_dpy)
659 XCloseDisplay(dri2dpy->dpy);
660 if (dri2dpy->api && dri2dpy->api->destroy)
661 dri2dpy->api->destroy(dri2dpy->api);
662 FREE(dri2dpy);
663 }
664
665 static void
666 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
667 void *user_data)
668 {
669 struct native_display *ndpy = (struct native_display* ) user_data;
670 struct dri2_display *dri2dpy = dri2_display(ndpy);
671 struct native_surface *nsurf;
672 struct dri2_surface *dri2surf;
673
674 nsurf = (struct native_surface *)
675 util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
676 if (!nsurf)
677 return;
678
679 dri2surf = dri2_surface(nsurf);
680
681 dri2surf->server_stamp++;
682 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
683 &dri2surf->base, dri2surf->server_stamp);
684 }
685
686 /**
687 * Initialize DRI2 and pipe screen.
688 */
689 static boolean
690 dri2_display_init_screen(struct native_display *ndpy)
691 {
692 struct dri2_display *dri2dpy = dri2_display(ndpy);
693 const char *driver = dri2dpy->api->name;
694 struct drm_create_screen_arg arg;
695 int fd;
696
697 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
698 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
699 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
700 return FALSE;
701 }
702
703 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
704 &dri2dpy->dri_major, &dri2dpy->dri_minor);
705 if (!dri2dpy->dri_driver || !driver ||
706 strcmp(dri2dpy->dri_driver, driver) != 0) {
707 _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
708 dri2dpy->dri_driver, dri2dpy->api->name);
709 return FALSE;
710 }
711
712 fd = x11_screen_enable_dri2(dri2dpy->xscr,
713 dri2_display_invalidate_buffers, &dri2dpy->base);
714 if (fd < 0)
715 return FALSE;
716
717 memset(&arg, 0, sizeof(arg));
718 arg.mode = DRM_CREATE_NORMAL;
719 dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, &arg);
720 if (!dri2dpy->base.screen) {
721 _eglLog(_EGL_WARNING, "failed to create DRM screen");
722 return FALSE;
723 }
724
725 return TRUE;
726 }
727
728 static unsigned
729 dri2_display_hash_table_hash(void *key)
730 {
731 XID drawable = pointer_to_uintptr(key);
732 return (unsigned) drawable;
733 }
734
735 static int
736 dri2_display_hash_table_compare(void *key1, void *key2)
737 {
738 return (key1 - key2);
739 }
740
741 struct native_display *
742 x11_create_dri2_display(EGLNativeDisplayType dpy,
743 struct native_event_handler *event_handler,
744 struct drm_api *api)
745 {
746 struct dri2_display *dri2dpy;
747
748 dri2dpy = CALLOC_STRUCT(dri2_display);
749 if (!dri2dpy)
750 return NULL;
751
752 dri2dpy->event_handler = event_handler;
753 dri2dpy->api = api;
754
755 dri2dpy->dpy = dpy;
756 if (!dri2dpy->dpy) {
757 dri2dpy->dpy = XOpenDisplay(NULL);
758 if (!dri2dpy->dpy) {
759 dri2_display_destroy(&dri2dpy->base);
760 return NULL;
761 }
762 dri2dpy->own_dpy = TRUE;
763 }
764
765 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
766 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
767 if (!dri2dpy->xscr) {
768 dri2_display_destroy(&dri2dpy->base);
769 return NULL;
770 }
771
772 if (!dri2_display_init_screen(&dri2dpy->base)) {
773 dri2_display_destroy(&dri2dpy->base);
774 return NULL;
775 }
776
777 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
778 dri2_display_hash_table_compare);
779 if (!dri2dpy->surfaces) {
780 dri2_display_destroy(&dri2dpy->base);
781 return NULL;
782 }
783
784 dri2dpy->base.destroy = dri2_display_destroy;
785 dri2dpy->base.get_param = dri2_display_get_param;
786 dri2dpy->base.get_configs = dri2_display_get_configs;
787 dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
788 dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
789 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
790
791 return &dri2dpy->base;
792 }