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