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