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