st/egl: Assorted fixes for dri2_display_get_configs.
[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 /* fast/slow configs are probably not relevant */
564 if (mode->visualRating == GLX_SLOW_CONFIG)
565 return FALSE;
566
567 nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
568 if (mode->doubleBufferMode)
569 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
570 if (mode->stereoMode) {
571 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
572 if (mode->doubleBufferMode)
573 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
574 }
575
576 /* choose color format */
577 num_formats = choose_color_format(mode, formats);
578 for (i = 0; i < num_formats; i++) {
579 if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
580 nconf->color_format = formats[i];
581 break;
582 }
583 }
584 if (nconf->color_format == PIPE_FORMAT_NONE)
585 return FALSE;
586
587 if ((mode->drawableType & GLX_WINDOW_BIT) && mode->visualID)
588 nconf->window_bit = TRUE;
589 if (mode->drawableType & GLX_PIXMAP_BIT)
590 nconf->pixmap_bit = TRUE;
591
592 nconf->native_visual_id = mode->visualID;
593 switch (mode->visualType) {
594 case GLX_TRUE_COLOR:
595 nconf->native_visual_type = TrueColor;
596 break;
597 case GLX_DIRECT_COLOR:
598 nconf->native_visual_type = DirectColor;
599 break;
600 case GLX_PSEUDO_COLOR:
601 nconf->native_visual_type = PseudoColor;
602 break;
603 case GLX_STATIC_COLOR:
604 nconf->native_visual_type = StaticColor;
605 break;
606 case GLX_GRAY_SCALE:
607 nconf->native_visual_type = GrayScale;
608 break;
609 case GLX_STATIC_GRAY:
610 nconf->native_visual_type = StaticGray;
611 break;
612 }
613 nconf->level = mode->level;
614
615 if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
616 nconf->transparent_rgb = TRUE;
617 nconf->transparent_rgb_values[0] = mode->transparentRed;
618 nconf->transparent_rgb_values[1] = mode->transparentGreen;
619 nconf->transparent_rgb_values[2] = mode->transparentBlue;
620 }
621
622 return TRUE;
623 }
624
625 static const struct native_config **
626 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
627 {
628 struct dri2_display *dri2dpy = dri2_display(ndpy);
629 const struct native_config **configs;
630 int i;
631
632 /* first time */
633 if (!dri2dpy->configs) {
634 const __GLcontextModes *modes;
635 int num_modes, count;
636
637 modes = x11_screen_get_glx_configs(dri2dpy->xscr);
638 if (!modes)
639 return NULL;
640 num_modes = x11_context_modes_count(modes);
641
642 dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
643 if (!dri2dpy->configs)
644 return NULL;
645
646 count = 0;
647 for (i = 0; i < num_modes; i++) {
648 struct native_config *nconf = &dri2dpy->configs[count].base;
649
650 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf)) {
651 int j;
652 /* look for duplicates */
653 for (j = 0; j < count; j++) {
654 if (memcmp(&dri2dpy->configs[j], nconf, sizeof(*nconf)) == 0)
655 break;
656 }
657 if (j == count)
658 count++;
659 }
660 modes = modes->next;
661 }
662
663 dri2dpy->num_configs = count;
664 }
665
666 configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
667 if (configs) {
668 for (i = 0; i < dri2dpy->num_configs; i++)
669 configs[i] = (const struct native_config *) &dri2dpy->configs[i];
670 if (num_configs)
671 *num_configs = dri2dpy->num_configs;
672 }
673
674 return configs;
675 }
676
677 static boolean
678 dri2_display_is_pixmap_supported(struct native_display *ndpy,
679 EGLNativePixmapType pix,
680 const struct native_config *nconf)
681 {
682 struct dri2_display *dri2dpy = dri2_display(ndpy);
683 uint depth, nconf_depth;
684
685 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
686 nconf_depth = util_format_get_blocksizebits(nconf->color_format);
687
688 /* simple depth match for now */
689 return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
690 }
691
692 static int
693 dri2_display_get_param(struct native_display *ndpy,
694 enum native_param_type param)
695 {
696 int val;
697
698 switch (param) {
699 case NATIVE_PARAM_USE_NATIVE_BUFFER:
700 /* DRI2GetBuffers uses the native buffers */
701 val = TRUE;
702 break;
703 case NATIVE_PARAM_PRESERVE_BUFFER:
704 /* DRI2CopyRegion is used */
705 val = TRUE;
706 break;
707 case NATIVE_PARAM_MAX_SWAP_INTERVAL:
708 default:
709 val = 0;
710 break;
711 }
712
713 return val;
714 }
715
716 static void
717 dri2_display_destroy(struct native_display *ndpy)
718 {
719 struct dri2_display *dri2dpy = dri2_display(ndpy);
720
721 if (dri2dpy->configs)
722 FREE(dri2dpy->configs);
723
724 if (dri2dpy->base.screen)
725 dri2dpy->base.screen->destroy(dri2dpy->base.screen);
726
727 if (dri2dpy->surfaces)
728 util_hash_table_destroy(dri2dpy->surfaces);
729
730 if (dri2dpy->xscr)
731 x11_screen_destroy(dri2dpy->xscr);
732 if (dri2dpy->own_dpy)
733 XCloseDisplay(dri2dpy->dpy);
734 FREE(dri2dpy);
735 }
736
737 static void
738 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
739 void *user_data)
740 {
741 struct native_display *ndpy = (struct native_display* ) user_data;
742 struct dri2_display *dri2dpy = dri2_display(ndpy);
743 struct native_surface *nsurf;
744 struct dri2_surface *dri2surf;
745
746 nsurf = (struct native_surface *)
747 util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
748 if (!nsurf)
749 return;
750
751 dri2surf = dri2_surface(nsurf);
752
753 dri2surf->server_stamp++;
754 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
755 &dri2surf->base, dri2surf->server_stamp);
756 }
757
758 /**
759 * Initialize DRI2 and pipe screen.
760 */
761 static boolean
762 dri2_display_init_screen(struct native_display *ndpy)
763 {
764 struct dri2_display *dri2dpy = dri2_display(ndpy);
765 int fd;
766
767 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
768 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
769 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
770 return FALSE;
771 }
772
773 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
774 &dri2dpy->dri_major, &dri2dpy->dri_minor);
775
776 fd = x11_screen_enable_dri2(dri2dpy->xscr,
777 dri2_display_invalidate_buffers, &dri2dpy->base);
778 if (fd < 0)
779 return FALSE;
780
781 dri2dpy->base.screen =
782 dri2dpy->event_handler->new_drm_screen(&dri2dpy->base,
783 dri2dpy->dri_driver, fd);
784 if (!dri2dpy->base.screen) {
785 _eglLog(_EGL_WARNING, "failed to create DRM screen");
786 return FALSE;
787 }
788
789 return TRUE;
790 }
791
792 static unsigned
793 dri2_display_hash_table_hash(void *key)
794 {
795 XID drawable = pointer_to_uintptr(key);
796 return (unsigned) drawable;
797 }
798
799 static int
800 dri2_display_hash_table_compare(void *key1, void *key2)
801 {
802 return (key1 - key2);
803 }
804
805 struct native_display *
806 x11_create_dri2_display(Display *dpy,
807 struct native_event_handler *event_handler,
808 void *user_data)
809 {
810 struct dri2_display *dri2dpy;
811
812 dri2dpy = CALLOC_STRUCT(dri2_display);
813 if (!dri2dpy)
814 return NULL;
815
816 dri2dpy->event_handler = event_handler;
817 dri2dpy->base.user_data = user_data;
818
819 dri2dpy->dpy = dpy;
820 if (!dri2dpy->dpy) {
821 dri2dpy->dpy = XOpenDisplay(NULL);
822 if (!dri2dpy->dpy) {
823 dri2_display_destroy(&dri2dpy->base);
824 return NULL;
825 }
826 dri2dpy->own_dpy = TRUE;
827 }
828
829 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
830 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
831 if (!dri2dpy->xscr) {
832 dri2_display_destroy(&dri2dpy->base);
833 return NULL;
834 }
835
836 if (!dri2_display_init_screen(&dri2dpy->base)) {
837 dri2_display_destroy(&dri2dpy->base);
838 return NULL;
839 }
840
841 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
842 dri2_display_hash_table_compare);
843 if (!dri2dpy->surfaces) {
844 dri2_display_destroy(&dri2dpy->base);
845 return NULL;
846 }
847
848 dri2dpy->base.destroy = dri2_display_destroy;
849 dri2dpy->base.get_param = dri2_display_get_param;
850 dri2dpy->base.get_configs = dri2_display_get_configs;
851 dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
852 dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
853 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
854
855 return &dri2dpy->base;
856 }
857
858 #else /* GLX_DIRECT_RENDERING */
859
860 struct native_display *
861 x11_create_dri2_display(Display *dpy,
862 struct native_event_handler *event_handler,
863 void *user_data)
864 {
865 return NULL;
866 }
867
868 #endif /* GLX_DIRECT_RENDERING */