3aa7c17dbc51f0b974ec871bd1c11c8700bd2e67
[mesa.git] / src / gallium / state_trackers / egl / x11 / native_dri2.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * 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_driver.h"
35 #include "egllog.h"
36
37 #include "native_x11.h"
38 #include "x11_screen.h"
39
40 #include "common/native_helper.h"
41 #ifdef HAVE_WAYLAND_BACKEND
42 #include "common/native_wayland_drm_bufmgr.h"
43 #endif
44
45 #ifdef GLX_DIRECT_RENDERING
46
47 struct dri2_display {
48 struct native_display base;
49 Display *dpy;
50 boolean own_dpy;
51
52 const struct native_event_handler *event_handler;
53
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 pipe_format color_format;
69 struct dri2_display *dri2dpy;
70
71 unsigned int server_stamp;
72 unsigned int client_stamp;
73 int width, height;
74 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
75 uint valid_mask;
76
77 boolean have_back, have_fake;
78
79 struct x11_drawable_buffer *last_xbufs;
80 int last_num_xbufs;
81 };
82
83 struct dri2_config {
84 struct native_config base;
85 };
86
87 static INLINE struct dri2_display *
88 dri2_display(const struct native_display *ndpy)
89 {
90 return (struct dri2_display *) ndpy;
91 }
92
93 static INLINE struct dri2_surface *
94 dri2_surface(const struct native_surface *nsurf)
95 {
96 return (struct dri2_surface *) nsurf;
97 }
98
99 static INLINE struct dri2_config *
100 dri2_config(const struct native_config *nconf)
101 {
102 return (struct dri2_config *) nconf;
103 }
104
105 /**
106 * Process the buffers returned by the server.
107 */
108 static void
109 dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
110 struct x11_drawable_buffer *xbufs,
111 int num_xbufs)
112 {
113 struct dri2_surface *dri2surf = dri2_surface(nsurf);
114 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
115 struct pipe_resource templ;
116 struct winsys_handle whandle;
117 uint valid_mask;
118 int i;
119
120 /* free the old textures */
121 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
122 pipe_resource_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.array_size = 1;
138 templ.format = dri2surf->color_format;
139 templ.bind = PIPE_BIND_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->resource_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 * 2];
196 int num_ins, num_outs, att;
197 struct x11_drawable_buffer *xbufs;
198 uint bpp = util_format_get_blocksizebits(dri2surf->color_format);
199 boolean with_format = FALSE; /* never ask for depth/stencil */
200
201 /* We must get the front on servers which doesn't support with format
202 * due to a silly bug in core dri2. You can't copy to/from a buffer
203 * that you haven't requested and you recive BadValue errors */
204 if (dri2surf->dri2dpy->dri_minor < 1) {
205 with_format = FALSE;
206 buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
207 }
208
209 /* prepare the attachments */
210 num_ins = 0;
211 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
212 if (native_attachment_mask_test(buffer_mask, att)) {
213 unsigned int dri2att;
214
215 switch (att) {
216 case NATIVE_ATTACHMENT_FRONT_LEFT:
217 dri2att = DRI2BufferFrontLeft;
218 break;
219 case NATIVE_ATTACHMENT_BACK_LEFT:
220 dri2att = DRI2BufferBackLeft;
221 break;
222 case NATIVE_ATTACHMENT_FRONT_RIGHT:
223 dri2att = DRI2BufferFrontRight;
224 break;
225 case NATIVE_ATTACHMENT_BACK_RIGHT:
226 dri2att = DRI2BufferBackRight;
227 break;
228 default:
229 assert(0);
230 dri2att = 0;
231 break;
232 }
233
234 dri2atts[num_ins++] = dri2att;
235 if (with_format)
236 dri2atts[num_ins++] = bpp;
237 }
238 }
239 if (with_format)
240 num_ins /= 2;
241
242 xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
243 &dri2surf->width, &dri2surf->height,
244 dri2atts, with_format, num_ins, &num_outs);
245
246 /* we should be able to do better... */
247 if (xbufs && dri2surf->last_num_xbufs == num_outs &&
248 memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
249 FREE(xbufs);
250 dri2surf->client_stamp = dri2surf->server_stamp;
251 return;
252 }
253
254 dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
255
256 dri2surf->server_stamp++;
257 dri2surf->client_stamp = dri2surf->server_stamp;
258
259 FREE(dri2surf->last_xbufs);
260 dri2surf->last_xbufs = xbufs;
261 dri2surf->last_num_xbufs = num_outs;
262 }
263
264 /**
265 * Update the buffers of the surface. This is a slow function due to the
266 * round-trip to the server.
267 */
268 static boolean
269 dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
270 {
271 struct dri2_surface *dri2surf = dri2_surface(nsurf);
272
273 dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
274
275 return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
276 }
277
278 /**
279 * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
280 */
281 static INLINE boolean
282 dri2_surface_receive_events(struct native_surface *nsurf)
283 {
284 struct dri2_surface *dri2surf = dri2_surface(nsurf);
285 return (dri2surf->dri2dpy->dri_minor >= 3);
286 }
287
288 static boolean
289 dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
290 {
291 struct dri2_surface *dri2surf = dri2_surface(nsurf);
292 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
293
294 /* copy to real front buffer */
295 if (dri2surf->have_fake)
296 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
297 0, 0, dri2surf->width, dri2surf->height,
298 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
299
300 /* force buffers to be updated in next validation call */
301 if (!dri2_surface_receive_events(&dri2surf->base)) {
302 dri2surf->server_stamp++;
303 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
304 &dri2surf->base, dri2surf->server_stamp);
305 }
306
307 return TRUE;
308 }
309
310 static boolean
311 dri2_surface_swap_buffers(struct native_surface *nsurf, int num_rects,
312 const int *rects)
313 {
314 struct dri2_surface *dri2surf = dri2_surface(nsurf);
315 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
316
317 /* copy to front buffer */
318 if (dri2surf->have_back) {
319 if (num_rects > 0)
320 x11_drawable_copy_buffers_region(dri2dpy->xscr, dri2surf->drawable,
321 num_rects, rects,
322 DRI2BufferBackLeft, DRI2BufferFrontLeft);
323 else
324 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
325 0, 0, dri2surf->width, dri2surf->height,
326 DRI2BufferBackLeft, DRI2BufferFrontLeft);
327 }
328
329 /* and update fake front buffer */
330 if (dri2surf->have_fake) {
331 if (num_rects > 0)
332 x11_drawable_copy_buffers_region(dri2dpy->xscr, dri2surf->drawable,
333 num_rects, rects,
334 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
335 else
336 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
337 0, 0, dri2surf->width, dri2surf->height,
338 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
339 }
340
341 /* force buffers to be updated in next validation call */
342 if (!dri2_surface_receive_events(&dri2surf->base)) {
343 dri2surf->server_stamp++;
344 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
345 &dri2surf->base, dri2surf->server_stamp);
346 }
347
348 return TRUE;
349 }
350
351 static boolean
352 dri2_surface_present(struct native_surface *nsurf,
353 const struct native_present_control *ctrl)
354 {
355 boolean ret;
356
357 if (ctrl->swap_interval)
358 return FALSE;
359
360 switch (ctrl->natt) {
361 case NATIVE_ATTACHMENT_FRONT_LEFT:
362 ret = dri2_surface_flush_frontbuffer(nsurf);
363 break;
364 case NATIVE_ATTACHMENT_BACK_LEFT:
365 ret = dri2_surface_swap_buffers(nsurf, ctrl->num_rects, ctrl->rects);
366 break;
367 default:
368 ret = FALSE;
369 break;
370 }
371
372 return ret;
373 }
374
375 static boolean
376 dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
377 unsigned int *seq_num, struct pipe_resource **textures,
378 int *width, int *height)
379 {
380 struct dri2_surface *dri2surf = dri2_surface(nsurf);
381
382 if (dri2surf->server_stamp != dri2surf->client_stamp ||
383 (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
384 if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
385 return FALSE;
386 }
387
388 if (seq_num)
389 *seq_num = dri2surf->client_stamp;
390
391 if (textures) {
392 int att;
393 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
394 if (native_attachment_mask_test(attachment_mask, att)) {
395 struct pipe_resource *ptex = dri2surf->textures[att];
396
397 textures[att] = NULL;
398 pipe_resource_reference(&textures[att], ptex);
399 }
400 }
401 }
402
403 if (width)
404 *width = dri2surf->width;
405 if (height)
406 *height = dri2surf->height;
407
408 return TRUE;
409 }
410
411 static void
412 dri2_surface_wait(struct native_surface *nsurf)
413 {
414 struct dri2_surface *dri2surf = dri2_surface(nsurf);
415 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
416
417 if (dri2surf->have_fake) {
418 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
419 0, 0, dri2surf->width, dri2surf->height,
420 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
421 }
422 }
423
424 static void
425 dri2_surface_destroy(struct native_surface *nsurf)
426 {
427 struct dri2_surface *dri2surf = dri2_surface(nsurf);
428 int i;
429
430 FREE(dri2surf->last_xbufs);
431
432 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
433 struct pipe_resource *ptex = dri2surf->textures[i];
434 pipe_resource_reference(&ptex, NULL);
435 }
436
437 if (dri2surf->drawable) {
438 x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
439 dri2surf->drawable, FALSE);
440
441 util_hash_table_remove(dri2surf->dri2dpy->surfaces,
442 (void *) dri2surf->drawable);
443 }
444 FREE(dri2surf);
445 }
446
447 static struct dri2_surface *
448 dri2_display_create_surface(struct native_display *ndpy,
449 Drawable drawable,
450 enum pipe_format color_format)
451 {
452 struct dri2_display *dri2dpy = dri2_display(ndpy);
453 struct dri2_surface *dri2surf;
454
455 dri2surf = CALLOC_STRUCT(dri2_surface);
456 if (!dri2surf)
457 return NULL;
458
459 dri2surf->dri2dpy = dri2dpy;
460 dri2surf->drawable = drawable;
461 dri2surf->color_format = color_format;
462
463 dri2surf->base.destroy = dri2_surface_destroy;
464 dri2surf->base.present = dri2_surface_present;
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,
488 (Drawable) win, nconf->color_format);
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 if (!nconf) {
500 struct dri2_display *dri2dpy = dri2_display(ndpy);
501 uint depth, nconf_depth;
502 int i;
503
504 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
505 for (i = 0; i < dri2dpy->num_configs; i++) {
506 nconf_depth = util_format_get_blocksizebits(
507 dri2dpy->configs[i].base.color_format);
508 /* simple depth match for now */
509 if (depth == nconf_depth ||
510 (depth == 24 && depth + 8 == nconf_depth)) {
511 nconf = &dri2dpy->configs[i].base;
512 break;
513 }
514 }
515
516 if (!nconf)
517 return NULL;
518 }
519
520 dri2surf = dri2_display_create_surface(ndpy,
521 (Drawable) pix, nconf->color_format);
522 return (dri2surf) ? &dri2surf->base : NULL;
523 }
524
525 static int
526 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
527 {
528 int count = 0;
529
530 switch (mode->rgbBits) {
531 case 32:
532 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
533 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
534 break;
535 case 24:
536 formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
537 formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
538 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
539 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
540 break;
541 case 16:
542 formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
543 break;
544 default:
545 break;
546 }
547
548 return count;
549 }
550
551 static boolean
552 is_format_supported(struct pipe_screen *screen,
553 enum pipe_format fmt, unsigned sample_count, boolean is_color)
554 {
555 return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count,
556 (is_color) ? PIPE_BIND_RENDER_TARGET :
557 PIPE_BIND_DEPTH_STENCIL);
558 }
559
560 static boolean
561 dri2_display_convert_config(struct native_display *ndpy,
562 const __GLcontextModes *mode,
563 struct native_config *nconf)
564 {
565 enum pipe_format formats[32];
566 int num_formats, i;
567 int sample_count = 0;
568
569 if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
570 return FALSE;
571
572 /* only interested in native renderable configs */
573 if (!mode->xRenderable || !mode->drawableType)
574 return FALSE;
575
576 /* fast/slow configs are probably not relevant */
577 if (mode->visualRating == GLX_SLOW_CONFIG)
578 return FALSE;
579
580 nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
581 if (mode->doubleBufferMode)
582 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
583 if (mode->stereoMode) {
584 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
585 if (mode->doubleBufferMode)
586 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
587 }
588
589 /* choose color format */
590 num_formats = choose_color_format(mode, formats);
591 for (i = 0; i < num_formats; i++) {
592 if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
593 nconf->color_format = formats[i];
594 break;
595 }
596 }
597 if (nconf->color_format == PIPE_FORMAT_NONE)
598 return FALSE;
599
600 if ((mode->drawableType & GLX_WINDOW_BIT) && mode->visualID)
601 nconf->window_bit = TRUE;
602 if (mode->drawableType & GLX_PIXMAP_BIT)
603 nconf->pixmap_bit = TRUE;
604
605 nconf->native_visual_id = mode->visualID;
606 switch (mode->visualType) {
607 case GLX_TRUE_COLOR:
608 nconf->native_visual_type = TrueColor;
609 break;
610 case GLX_DIRECT_COLOR:
611 nconf->native_visual_type = DirectColor;
612 break;
613 case GLX_PSEUDO_COLOR:
614 nconf->native_visual_type = PseudoColor;
615 break;
616 case GLX_STATIC_COLOR:
617 nconf->native_visual_type = StaticColor;
618 break;
619 case GLX_GRAY_SCALE:
620 nconf->native_visual_type = GrayScale;
621 break;
622 case GLX_STATIC_GRAY:
623 nconf->native_visual_type = StaticGray;
624 break;
625 }
626 nconf->level = mode->level;
627
628 if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
629 nconf->transparent_rgb = TRUE;
630 nconf->transparent_rgb_values[0] = mode->transparentRed;
631 nconf->transparent_rgb_values[1] = mode->transparentGreen;
632 nconf->transparent_rgb_values[2] = mode->transparentBlue;
633 }
634
635 return TRUE;
636 }
637
638 static const struct native_config **
639 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
640 {
641 struct dri2_display *dri2dpy = dri2_display(ndpy);
642 const struct native_config **configs;
643 int i;
644
645 /* first time */
646 if (!dri2dpy->configs) {
647 const __GLcontextModes *modes;
648 int num_modes, count;
649
650 modes = x11_screen_get_glx_configs(dri2dpy->xscr);
651 if (!modes)
652 return NULL;
653 num_modes = x11_context_modes_count(modes);
654
655 dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
656 if (!dri2dpy->configs)
657 return NULL;
658
659 count = 0;
660 for (i = 0; i < num_modes; i++) {
661 struct native_config *nconf = &dri2dpy->configs[count].base;
662
663 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf)) {
664 int j;
665 /* look for duplicates */
666 for (j = 0; j < count; j++) {
667 if (memcmp(&dri2dpy->configs[j], nconf, sizeof(*nconf)) == 0)
668 break;
669 }
670 if (j == count)
671 count++;
672 }
673 modes = modes->next;
674 }
675
676 dri2dpy->num_configs = count;
677 }
678
679 configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
680 if (configs) {
681 for (i = 0; i < dri2dpy->num_configs; i++)
682 configs[i] = (const struct native_config *) &dri2dpy->configs[i];
683 if (num_configs)
684 *num_configs = dri2dpy->num_configs;
685 }
686
687 return configs;
688 }
689
690 static boolean
691 dri2_display_get_pixmap_format(struct native_display *ndpy,
692 EGLNativePixmapType pix,
693 enum pipe_format *format)
694 {
695 struct dri2_display *dri2dpy = dri2_display(ndpy);
696 boolean ret = EGL_TRUE;
697 uint depth;
698
699 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
700 switch (depth) {
701 case 32:
702 case 24:
703 *format = PIPE_FORMAT_B8G8R8A8_UNORM;
704 break;
705 case 16:
706 *format = PIPE_FORMAT_B5G6R5_UNORM;
707 break;
708 default:
709 *format = PIPE_FORMAT_NONE;
710 ret = EGL_FALSE;
711 break;
712 }
713
714 return ret;
715 }
716
717 static int
718 dri2_display_get_param(struct native_display *ndpy,
719 enum native_param_type param)
720 {
721 int val;
722
723 switch (param) {
724 case NATIVE_PARAM_USE_NATIVE_BUFFER:
725 /* DRI2GetBuffers uses the native buffers */
726 val = TRUE;
727 break;
728 case NATIVE_PARAM_PRESERVE_BUFFER:
729 /* DRI2CopyRegion is used */
730 val = TRUE;
731 break;
732 case NATIVE_PARAM_PRESENT_REGION:
733 val = TRUE;
734 break;
735 case NATIVE_PARAM_MAX_SWAP_INTERVAL:
736 default:
737 val = 0;
738 break;
739 }
740
741 return val;
742 }
743
744 static void
745 dri2_display_destroy(struct native_display *ndpy)
746 {
747 struct dri2_display *dri2dpy = dri2_display(ndpy);
748
749 FREE(dri2dpy->configs);
750
751 if (dri2dpy->base.screen)
752 dri2dpy->base.screen->destroy(dri2dpy->base.screen);
753
754 if (dri2dpy->surfaces)
755 util_hash_table_destroy(dri2dpy->surfaces);
756
757 #ifdef HAVE_WAYLAND_BACKEND
758 wayland_drm_bufmgr_destroy(ndpy->wayland_bufmgr);
759 #endif
760
761 if (dri2dpy->xscr)
762 x11_screen_destroy(dri2dpy->xscr);
763 if (dri2dpy->own_dpy)
764 XCloseDisplay(dri2dpy->dpy);
765 FREE(dri2dpy);
766 }
767
768 static void
769 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
770 void *user_data)
771 {
772 struct native_display *ndpy = (struct native_display* ) user_data;
773 struct dri2_display *dri2dpy = dri2_display(ndpy);
774 struct native_surface *nsurf;
775 struct dri2_surface *dri2surf;
776
777 nsurf = (struct native_surface *)
778 util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
779 if (!nsurf)
780 return;
781
782 dri2surf = dri2_surface(nsurf);
783
784 dri2surf->server_stamp++;
785 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
786 &dri2surf->base, dri2surf->server_stamp);
787 }
788
789 #ifdef HAVE_WAYLAND_BACKEND
790
791 static int
792 dri2_display_authenticate(void *user_data, uint32_t magic)
793 {
794 struct native_display *ndpy = user_data;
795 struct dri2_display *dri2dpy = dri2_display(ndpy);
796
797 return x11_screen_authenticate(dri2dpy->xscr, magic);
798 }
799
800 #endif /* HAVE_WAYLAND_BACKEND */
801
802 /**
803 * Initialize DRI2 and pipe screen.
804 */
805 static boolean
806 dri2_display_init_screen(struct native_display *ndpy)
807 {
808 struct dri2_display *dri2dpy = dri2_display(ndpy);
809 int fd;
810
811 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
812 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
813 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
814 return FALSE;
815 }
816
817 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
818 &dri2dpy->dri_major, &dri2dpy->dri_minor);
819
820 fd = x11_screen_enable_dri2(dri2dpy->xscr,
821 dri2_display_invalidate_buffers, &dri2dpy->base);
822 if (fd < 0)
823 return FALSE;
824
825 dri2dpy->base.screen =
826 dri2dpy->event_handler->new_drm_screen(&dri2dpy->base,
827 dri2dpy->dri_driver, fd);
828 if (!dri2dpy->base.screen) {
829 _eglLog(_EGL_DEBUG, "failed to create DRM screen");
830 return FALSE;
831 }
832
833 #ifdef HAVE_WAYLAND_BACKEND
834 dri2dpy->base.wayland_bufmgr = wayland_drm_bufmgr_create(
835 dri2_display_authenticate, dri2dpy,
836 x11_screen_get_device_name(dri2dpy->xscr));
837
838 #endif
839
840 return TRUE;
841 }
842
843 static unsigned
844 dri2_display_hash_table_hash(void *key)
845 {
846 XID drawable = pointer_to_uintptr(key);
847 return (unsigned) drawable;
848 }
849
850 static int
851 dri2_display_hash_table_compare(void *key1, void *key2)
852 {
853 return ((char *) key1 - (char *) key2);
854 }
855
856 struct native_display *
857 x11_create_dri2_display(Display *dpy,
858 const struct native_event_handler *event_handler)
859 {
860 struct dri2_display *dri2dpy;
861
862 dri2dpy = CALLOC_STRUCT(dri2_display);
863 if (!dri2dpy)
864 return NULL;
865
866 dri2dpy->event_handler = event_handler;
867
868 dri2dpy->dpy = dpy;
869 if (!dri2dpy->dpy) {
870 dri2dpy->dpy = XOpenDisplay(NULL);
871 if (!dri2dpy->dpy) {
872 dri2_display_destroy(&dri2dpy->base);
873 return NULL;
874 }
875 dri2dpy->own_dpy = TRUE;
876 }
877
878 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
879 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
880 if (!dri2dpy->xscr) {
881 dri2_display_destroy(&dri2dpy->base);
882 return NULL;
883 }
884
885 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
886 dri2_display_hash_table_compare);
887 if (!dri2dpy->surfaces) {
888 dri2_display_destroy(&dri2dpy->base);
889 return NULL;
890 }
891
892 dri2dpy->base.init_screen = dri2_display_init_screen;
893 dri2dpy->base.destroy = dri2_display_destroy;
894 dri2dpy->base.get_param = dri2_display_get_param;
895 dri2dpy->base.get_configs = dri2_display_get_configs;
896 dri2dpy->base.get_pixmap_format = dri2_display_get_pixmap_format;
897 dri2dpy->base.copy_to_pixmap = native_display_copy_to_pixmap;
898 dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
899 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
900
901 return &dri2dpy->base;
902 }
903
904 #else /* GLX_DIRECT_RENDERING */
905
906 struct native_display *
907 x11_create_dri2_display(Display *dpy,
908 const struct native_event_handler *event_handler)
909 {
910 return NULL;
911 }
912
913 #endif /* GLX_DIRECT_RENDERING */