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