st/egl: Remove native_config::slow_config.
[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_driver.h"
36 #include "egllog.h"
37
38 #include "native_x11.h"
39 #include "x11_screen.h"
40
41 #ifdef GLX_DIRECT_RENDERING
42
43 struct dri2_display {
44 struct native_display base;
45 Display *dpy;
46 boolean own_dpy;
47
48 struct native_event_handler *event_handler;
49
50 struct x11_screen *xscr;
51 int xscr_number;
52 const char *dri_driver;
53 int dri_major, dri_minor;
54
55 struct dri2_config *configs;
56 int num_configs;
57
58 struct util_hash_table *surfaces;
59 };
60
61 struct dri2_surface {
62 struct native_surface base;
63 Drawable drawable;
64 enum pipe_format color_format;
65 struct dri2_display *dri2dpy;
66
67 unsigned int server_stamp;
68 unsigned int client_stamp;
69 int width, height;
70 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
71 uint valid_mask;
72
73 boolean have_back, have_fake;
74
75 struct x11_drawable_buffer *last_xbufs;
76 int last_num_xbufs;
77 };
78
79 struct dri2_config {
80 struct native_config base;
81 };
82
83 static INLINE struct dri2_display *
84 dri2_display(const struct native_display *ndpy)
85 {
86 return (struct dri2_display *) ndpy;
87 }
88
89 static INLINE struct dri2_surface *
90 dri2_surface(const struct native_surface *nsurf)
91 {
92 return (struct dri2_surface *) nsurf;
93 }
94
95 static INLINE struct dri2_config *
96 dri2_config(const struct native_config *nconf)
97 {
98 return (struct dri2_config *) nconf;
99 }
100
101 /**
102 * Process the buffers returned by the server.
103 */
104 static void
105 dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
106 struct x11_drawable_buffer *xbufs,
107 int num_xbufs)
108 {
109 struct dri2_surface *dri2surf = dri2_surface(nsurf);
110 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
111 struct pipe_resource templ;
112 struct winsys_handle whandle;
113 uint valid_mask;
114 int i;
115
116 /* free the old textures */
117 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
118 pipe_resource_reference(&dri2surf->textures[i], NULL);
119 dri2surf->valid_mask = 0x0;
120
121 dri2surf->have_back = FALSE;
122 dri2surf->have_fake = FALSE;
123
124 if (!xbufs)
125 return;
126
127 memset(&templ, 0, sizeof(templ));
128 templ.target = PIPE_TEXTURE_2D;
129 templ.last_level = 0;
130 templ.width0 = dri2surf->width;
131 templ.height0 = dri2surf->height;
132 templ.depth0 = 1;
133 templ.array_size = 1;
134 templ.format = dri2surf->color_format;
135 templ.bind = PIPE_BIND_RENDER_TARGET;
136
137 valid_mask = 0x0;
138 for (i = 0; i < num_xbufs; i++) {
139 struct x11_drawable_buffer *xbuf = &xbufs[i];
140 const char *desc;
141 enum native_attachment natt;
142
143 switch (xbuf->attachment) {
144 case DRI2BufferFrontLeft:
145 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
146 desc = "DRI2 Front Buffer";
147 break;
148 case DRI2BufferFakeFrontLeft:
149 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
150 desc = "DRI2 Fake Front Buffer";
151 dri2surf->have_fake = TRUE;
152 break;
153 case DRI2BufferBackLeft:
154 natt = NATIVE_ATTACHMENT_BACK_LEFT;
155 desc = "DRI2 Back Buffer";
156 dri2surf->have_back = TRUE;
157 break;
158 default:
159 desc = NULL;
160 break;
161 }
162
163 if (!desc || dri2surf->textures[natt]) {
164 if (!desc)
165 _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
166 else
167 _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
168 continue;
169 }
170
171 memset(&whandle, 0, sizeof(whandle));
172 whandle.stride = xbuf->pitch;
173 whandle.handle = xbuf->name;
174 dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle(
175 dri2dpy->base.screen, &templ, &whandle);
176 if (dri2surf->textures[natt])
177 valid_mask |= 1 << natt;
178 }
179
180 dri2surf->valid_mask = valid_mask;
181 }
182
183 /**
184 * Get the buffers from the server.
185 */
186 static void
187 dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
188 {
189 struct dri2_surface *dri2surf = dri2_surface(nsurf);
190 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
191 unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS * 2];
192 int num_ins, num_outs, att;
193 struct x11_drawable_buffer *xbufs;
194 uint bpp = util_format_get_blocksizebits(dri2surf->color_format);
195 boolean with_format = FALSE; /* never ask for depth/stencil */
196
197 /* We must get the front on servers which doesn't support with format
198 * due to a silly bug in core dri2. You can't copy to/from a buffer
199 * that you haven't requested and you recive BadValue errors */
200 if (dri2surf->dri2dpy->dri_minor < 1) {
201 with_format = FALSE;
202 buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
203 }
204
205 /* prepare the attachments */
206 num_ins = 0;
207 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
208 if (native_attachment_mask_test(buffer_mask, att)) {
209 unsigned int dri2att;
210
211 switch (att) {
212 case NATIVE_ATTACHMENT_FRONT_LEFT:
213 dri2att = DRI2BufferFrontLeft;
214 break;
215 case NATIVE_ATTACHMENT_BACK_LEFT:
216 dri2att = DRI2BufferBackLeft;
217 break;
218 case NATIVE_ATTACHMENT_FRONT_RIGHT:
219 dri2att = DRI2BufferFrontRight;
220 break;
221 case NATIVE_ATTACHMENT_BACK_RIGHT:
222 dri2att = DRI2BufferBackRight;
223 break;
224 default:
225 assert(0);
226 dri2att = 0;
227 break;
228 }
229
230 dri2atts[num_ins++] = dri2att;
231 if (with_format)
232 dri2atts[num_ins++] = bpp;
233 }
234 }
235 if (with_format)
236 num_ins /= 2;
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_present(struct native_surface *nsurf,
337 enum native_attachment natt,
338 boolean preserve,
339 uint swap_interval)
340 {
341 boolean ret;
342
343 if (swap_interval)
344 return FALSE;
345
346 switch (natt) {
347 case NATIVE_ATTACHMENT_FRONT_LEFT:
348 ret = dri2_surface_flush_frontbuffer(nsurf);
349 break;
350 case NATIVE_ATTACHMENT_BACK_LEFT:
351 ret = dri2_surface_swap_buffers(nsurf);
352 break;
353 default:
354 ret = FALSE;
355 break;
356 }
357
358 return ret;
359 }
360
361 static boolean
362 dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
363 unsigned int *seq_num, struct pipe_resource **textures,
364 int *width, int *height)
365 {
366 struct dri2_surface *dri2surf = dri2_surface(nsurf);
367
368 if (dri2surf->server_stamp != dri2surf->client_stamp ||
369 (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
370 if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
371 return FALSE;
372 }
373
374 if (seq_num)
375 *seq_num = dri2surf->client_stamp;
376
377 if (textures) {
378 int att;
379 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
380 if (native_attachment_mask_test(attachment_mask, att)) {
381 struct pipe_resource *ptex = dri2surf->textures[att];
382
383 textures[att] = NULL;
384 pipe_resource_reference(&textures[att], ptex);
385 }
386 }
387 }
388
389 if (width)
390 *width = dri2surf->width;
391 if (height)
392 *height = dri2surf->height;
393
394 return TRUE;
395 }
396
397 static void
398 dri2_surface_wait(struct native_surface *nsurf)
399 {
400 struct dri2_surface *dri2surf = dri2_surface(nsurf);
401 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
402
403 if (dri2surf->have_fake) {
404 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
405 0, 0, dri2surf->width, dri2surf->height,
406 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
407 }
408 }
409
410 static void
411 dri2_surface_destroy(struct native_surface *nsurf)
412 {
413 struct dri2_surface *dri2surf = dri2_surface(nsurf);
414 int i;
415
416 if (dri2surf->last_xbufs)
417 FREE(dri2surf->last_xbufs);
418
419 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
420 struct pipe_resource *ptex = dri2surf->textures[i];
421 pipe_resource_reference(&ptex, NULL);
422 }
423
424 if (dri2surf->drawable) {
425 x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
426 dri2surf->drawable, FALSE);
427
428 util_hash_table_remove(dri2surf->dri2dpy->surfaces,
429 (void *) dri2surf->drawable);
430 }
431 FREE(dri2surf);
432 }
433
434 static struct dri2_surface *
435 dri2_display_create_surface(struct native_display *ndpy,
436 Drawable drawable,
437 enum pipe_format color_format)
438 {
439 struct dri2_display *dri2dpy = dri2_display(ndpy);
440 struct dri2_surface *dri2surf;
441
442 dri2surf = CALLOC_STRUCT(dri2_surface);
443 if (!dri2surf)
444 return NULL;
445
446 dri2surf->dri2dpy = dri2dpy;
447 dri2surf->drawable = drawable;
448 dri2surf->color_format = color_format;
449
450 dri2surf->base.destroy = dri2_surface_destroy;
451 dri2surf->base.present = dri2_surface_present;
452 dri2surf->base.validate = dri2_surface_validate;
453 dri2surf->base.wait = dri2_surface_wait;
454
455 if (drawable) {
456 x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
457 /* initialize the geometry */
458 dri2_surface_update_buffers(&dri2surf->base, 0x0);
459
460 util_hash_table_set(dri2surf->dri2dpy->surfaces,
461 (void *) dri2surf->drawable, (void *) &dri2surf->base);
462 }
463
464 return dri2surf;
465 }
466
467 static struct native_surface *
468 dri2_display_create_window_surface(struct native_display *ndpy,
469 EGLNativeWindowType win,
470 const struct native_config *nconf)
471 {
472 struct dri2_surface *dri2surf;
473
474 dri2surf = dri2_display_create_surface(ndpy,
475 (Drawable) win, nconf->color_format);
476 return (dri2surf) ? &dri2surf->base : NULL;
477 }
478
479 static struct native_surface *
480 dri2_display_create_pixmap_surface(struct native_display *ndpy,
481 EGLNativePixmapType pix,
482 const struct native_config *nconf)
483 {
484 struct dri2_surface *dri2surf;
485
486 if (!nconf) {
487 struct dri2_display *dri2dpy = dri2_display(ndpy);
488 uint depth, nconf_depth;
489 int i;
490
491 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
492 for (i = 0; i < dri2dpy->num_configs; i++) {
493 nconf_depth = util_format_get_blocksizebits(
494 dri2dpy->configs[i].base.color_format);
495 /* simple depth match for now */
496 if (depth == nconf_depth ||
497 (depth == 24 && depth + 8 == nconf_depth)) {
498 nconf = &dri2dpy->configs[i].base;
499 break;
500 }
501 }
502
503 if (!nconf)
504 return NULL;
505 }
506
507 dri2surf = dri2_display_create_surface(ndpy,
508 (Drawable) pix, nconf->color_format);
509 return (dri2surf) ? &dri2surf->base : NULL;
510 }
511
512 static int
513 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
514 {
515 int count = 0;
516
517 switch (mode->rgbBits) {
518 case 32:
519 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
520 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
521 break;
522 case 24:
523 formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
524 formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
525 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
526 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
527 break;
528 case 16:
529 formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
530 break;
531 default:
532 break;
533 }
534
535 return count;
536 }
537
538 static boolean
539 is_format_supported(struct pipe_screen *screen,
540 enum pipe_format fmt, unsigned sample_count, boolean is_color)
541 {
542 return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count,
543 (is_color) ? PIPE_BIND_RENDER_TARGET :
544 PIPE_BIND_DEPTH_STENCIL, 0);
545 }
546
547 static boolean
548 dri2_display_convert_config(struct native_display *ndpy,
549 const __GLcontextModes *mode,
550 struct native_config *nconf)
551 {
552 enum pipe_format formats[32];
553 int num_formats, i;
554 int sample_count = 0;
555
556 if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
557 return FALSE;
558
559 /* only interested in native renderable configs */
560 if (!mode->xRenderable || !mode->drawableType)
561 return FALSE;
562
563 nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
564 if (mode->doubleBufferMode)
565 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
566 if (mode->stereoMode) {
567 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
568 if (mode->doubleBufferMode)
569 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
570 }
571
572 /* choose color format */
573 num_formats = choose_color_format(mode, formats);
574 for (i = 0; i < num_formats; i++) {
575 if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
576 nconf->color_format = formats[i];
577 break;
578 }
579 }
580 if (nconf->color_format == PIPE_FORMAT_NONE)
581 return FALSE;
582
583 if (mode->drawableType & GLX_WINDOW_BIT)
584 nconf->window_bit = TRUE;
585 if (mode->drawableType & GLX_PIXMAP_BIT)
586 nconf->pixmap_bit = TRUE;
587
588 nconf->native_visual_id = mode->visualID;
589 nconf->native_visual_type = mode->visualType;
590 nconf->level = mode->level;
591 nconf->samples = mode->samples;
592
593 if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
594 nconf->transparent_rgb = TRUE;
595 nconf->transparent_rgb_values[0] = mode->transparentRed;
596 nconf->transparent_rgb_values[1] = mode->transparentGreen;
597 nconf->transparent_rgb_values[2] = mode->transparentBlue;
598 }
599
600 return TRUE;
601 }
602
603 static const struct native_config **
604 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
605 {
606 struct dri2_display *dri2dpy = dri2_display(ndpy);
607 const struct native_config **configs;
608 int i;
609
610 /* first time */
611 if (!dri2dpy->configs) {
612 const __GLcontextModes *modes;
613 int num_modes, count;
614
615 modes = x11_screen_get_glx_configs(dri2dpy->xscr);
616 if (!modes)
617 return NULL;
618 num_modes = x11_context_modes_count(modes);
619
620 dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
621 if (!dri2dpy->configs)
622 return NULL;
623
624 count = 0;
625 for (i = 0; i < num_modes; i++) {
626 struct native_config *nconf = &dri2dpy->configs[count].base;
627 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf))
628 count++;
629 modes = modes->next;
630 }
631
632 dri2dpy->num_configs = count;
633 }
634
635 configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
636 if (configs) {
637 for (i = 0; i < dri2dpy->num_configs; i++)
638 configs[i] = (const struct native_config *) &dri2dpy->configs[i];
639 if (num_configs)
640 *num_configs = dri2dpy->num_configs;
641 }
642
643 return configs;
644 }
645
646 static boolean
647 dri2_display_is_pixmap_supported(struct native_display *ndpy,
648 EGLNativePixmapType pix,
649 const struct native_config *nconf)
650 {
651 struct dri2_display *dri2dpy = dri2_display(ndpy);
652 uint depth, nconf_depth;
653
654 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
655 nconf_depth = util_format_get_blocksizebits(nconf->color_format);
656
657 /* simple depth match for now */
658 return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
659 }
660
661 static int
662 dri2_display_get_param(struct native_display *ndpy,
663 enum native_param_type param)
664 {
665 int val;
666
667 switch (param) {
668 case NATIVE_PARAM_USE_NATIVE_BUFFER:
669 /* DRI2GetBuffers uses the native buffers */
670 val = TRUE;
671 break;
672 case NATIVE_PARAM_PRESERVE_BUFFER:
673 /* DRI2CopyRegion is used */
674 val = TRUE;
675 break;
676 case NATIVE_PARAM_MAX_SWAP_INTERVAL:
677 default:
678 val = 0;
679 break;
680 }
681
682 return val;
683 }
684
685 static void
686 dri2_display_destroy(struct native_display *ndpy)
687 {
688 struct dri2_display *dri2dpy = dri2_display(ndpy);
689
690 if (dri2dpy->configs)
691 FREE(dri2dpy->configs);
692
693 if (dri2dpy->base.screen)
694 dri2dpy->base.screen->destroy(dri2dpy->base.screen);
695
696 if (dri2dpy->surfaces)
697 util_hash_table_destroy(dri2dpy->surfaces);
698
699 if (dri2dpy->xscr)
700 x11_screen_destroy(dri2dpy->xscr);
701 if (dri2dpy->own_dpy)
702 XCloseDisplay(dri2dpy->dpy);
703 FREE(dri2dpy);
704 }
705
706 static void
707 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
708 void *user_data)
709 {
710 struct native_display *ndpy = (struct native_display* ) user_data;
711 struct dri2_display *dri2dpy = dri2_display(ndpy);
712 struct native_surface *nsurf;
713 struct dri2_surface *dri2surf;
714
715 nsurf = (struct native_surface *)
716 util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
717 if (!nsurf)
718 return;
719
720 dri2surf = dri2_surface(nsurf);
721
722 dri2surf->server_stamp++;
723 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
724 &dri2surf->base, dri2surf->server_stamp);
725 }
726
727 /**
728 * Initialize DRI2 and pipe screen.
729 */
730 static boolean
731 dri2_display_init_screen(struct native_display *ndpy)
732 {
733 struct dri2_display *dri2dpy = dri2_display(ndpy);
734 int fd;
735
736 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
737 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
738 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
739 return FALSE;
740 }
741
742 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
743 &dri2dpy->dri_major, &dri2dpy->dri_minor);
744
745 fd = x11_screen_enable_dri2(dri2dpy->xscr,
746 dri2_display_invalidate_buffers, &dri2dpy->base);
747 if (fd < 0)
748 return FALSE;
749
750 dri2dpy->base.screen =
751 dri2dpy->event_handler->new_drm_screen(&dri2dpy->base,
752 dri2dpy->dri_driver, fd);
753 if (!dri2dpy->base.screen) {
754 _eglLog(_EGL_WARNING, "failed to create DRM screen");
755 return FALSE;
756 }
757
758 return TRUE;
759 }
760
761 static unsigned
762 dri2_display_hash_table_hash(void *key)
763 {
764 XID drawable = pointer_to_uintptr(key);
765 return (unsigned) drawable;
766 }
767
768 static int
769 dri2_display_hash_table_compare(void *key1, void *key2)
770 {
771 return (key1 - key2);
772 }
773
774 struct native_display *
775 x11_create_dri2_display(Display *dpy,
776 struct native_event_handler *event_handler,
777 void *user_data)
778 {
779 struct dri2_display *dri2dpy;
780
781 dri2dpy = CALLOC_STRUCT(dri2_display);
782 if (!dri2dpy)
783 return NULL;
784
785 dri2dpy->event_handler = event_handler;
786 dri2dpy->base.user_data = user_data;
787
788 dri2dpy->dpy = dpy;
789 if (!dri2dpy->dpy) {
790 dri2dpy->dpy = XOpenDisplay(NULL);
791 if (!dri2dpy->dpy) {
792 dri2_display_destroy(&dri2dpy->base);
793 return NULL;
794 }
795 dri2dpy->own_dpy = TRUE;
796 }
797
798 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
799 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
800 if (!dri2dpy->xscr) {
801 dri2_display_destroy(&dri2dpy->base);
802 return NULL;
803 }
804
805 if (!dri2_display_init_screen(&dri2dpy->base)) {
806 dri2_display_destroy(&dri2dpy->base);
807 return NULL;
808 }
809
810 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
811 dri2_display_hash_table_compare);
812 if (!dri2dpy->surfaces) {
813 dri2_display_destroy(&dri2dpy->base);
814 return NULL;
815 }
816
817 dri2dpy->base.destroy = dri2_display_destroy;
818 dri2dpy->base.get_param = dri2_display_get_param;
819 dri2dpy->base.get_configs = dri2_display_get_configs;
820 dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
821 dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
822 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
823
824 return &dri2dpy->base;
825 }
826
827 #else /* GLX_DIRECT_RENDERING */
828
829 struct native_display *
830 x11_create_dri2_display(Display *dpy,
831 struct native_event_handler *event_handler,
832 void *user_data)
833 {
834 return NULL;
835 }
836
837 #endif /* GLX_DIRECT_RENDERING */