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