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