2 * Mesa 3-D graphics library
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
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_api.h"
38 #include "native_x11.h"
39 #include "x11_screen.h"
41 enum dri2_surface_type {
42 DRI2_SURFACE_TYPE_WINDOW,
43 DRI2_SURFACE_TYPE_PIXMAP,
47 struct native_display base;
51 struct native_event_handler *event_handler;
54 struct x11_screen *xscr;
56 const char *dri_driver;
57 int dri_major, dri_minor;
59 struct dri2_config *configs;
62 struct util_hash_table *surfaces;
66 struct native_surface base;
68 enum dri2_surface_type type;
69 enum pipe_format color_format;
70 struct dri2_display *dri2dpy;
72 unsigned int server_stamp;
73 unsigned int client_stamp;
75 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
78 boolean have_back, have_fake;
80 struct x11_drawable_buffer *last_xbufs;
85 struct native_config base;
88 static INLINE struct dri2_display *
89 dri2_display(const struct native_display *ndpy)
91 return (struct dri2_display *) ndpy;
94 static INLINE struct dri2_surface *
95 dri2_surface(const struct native_surface *nsurf)
97 return (struct dri2_surface *) nsurf;
100 static INLINE struct dri2_config *
101 dri2_config(const struct native_config *nconf)
103 return (struct dri2_config *) nconf;
107 * Process the buffers returned by the server.
110 dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
111 struct x11_drawable_buffer *xbufs,
114 struct dri2_surface *dri2surf = dri2_surface(nsurf);
115 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
116 struct pipe_resource templ;
117 struct winsys_handle whandle;
121 /* free the old textures */
122 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
123 pipe_resource_reference(&dri2surf->textures[i], NULL);
124 dri2surf->valid_mask = 0x0;
126 dri2surf->have_back = FALSE;
127 dri2surf->have_fake = FALSE;
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;
138 templ.format = dri2surf->color_format;
139 templ.bind = PIPE_BIND_RENDER_TARGET;
142 for (i = 0; i < num_xbufs; i++) {
143 struct x11_drawable_buffer *xbuf = &xbufs[i];
145 enum native_attachment natt;
147 switch (xbuf->attachment) {
148 case DRI2BufferFrontLeft:
149 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
150 desc = "DRI2 Front Buffer";
152 case DRI2BufferFakeFrontLeft:
153 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
154 desc = "DRI2 Fake Front Buffer";
155 dri2surf->have_fake = TRUE;
157 case DRI2BufferBackLeft:
158 natt = NATIVE_ATTACHMENT_BACK_LEFT;
159 desc = "DRI2 Back Buffer";
160 dri2surf->have_back = TRUE;
167 if (!desc || dri2surf->textures[natt]) {
169 _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
171 _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
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;
184 dri2surf->valid_mask = valid_mask;
188 * Get the buffers from the server.
191 dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
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 */
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) {
206 buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
209 /* prepare the attachments */
211 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
212 if (native_attachment_mask_test(buffer_mask, att)) {
213 unsigned int dri2att;
216 case NATIVE_ATTACHMENT_FRONT_LEFT:
217 dri2att = DRI2BufferFrontLeft;
219 case NATIVE_ATTACHMENT_BACK_LEFT:
220 dri2att = DRI2BufferBackLeft;
222 case NATIVE_ATTACHMENT_FRONT_RIGHT:
223 dri2att = DRI2BufferFrontRight;
225 case NATIVE_ATTACHMENT_BACK_RIGHT:
226 dri2att = DRI2BufferBackRight;
234 dri2atts[num_ins++] = dri2att;
236 dri2atts[num_ins++] = bpp;
242 xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
243 &dri2surf->width, &dri2surf->height,
244 dri2atts, with_format, num_ins, &num_outs);
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) {
250 dri2surf->client_stamp = dri2surf->server_stamp;
254 dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
256 dri2surf->server_stamp++;
257 dri2surf->client_stamp = dri2surf->server_stamp;
259 if (dri2surf->last_xbufs)
260 FREE(dri2surf->last_xbufs);
261 dri2surf->last_xbufs = xbufs;
262 dri2surf->last_num_xbufs = num_outs;
266 * Update the buffers of the surface. This is a slow function due to the
267 * round-trip to the server.
270 dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
272 struct dri2_surface *dri2surf = dri2_surface(nsurf);
274 dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
276 return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
280 * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
282 static INLINE boolean
283 dri2_surface_receive_events(struct native_surface *nsurf)
285 struct dri2_surface *dri2surf = dri2_surface(nsurf);
286 return (dri2surf->dri2dpy->dri_minor >= 3);
290 dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
292 struct dri2_surface *dri2surf = dri2_surface(nsurf);
293 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
295 /* copy to real front buffer */
296 if (dri2surf->have_fake)
297 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
298 0, 0, dri2surf->width, dri2surf->height,
299 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
301 /* force buffers to be updated in next validation call */
302 if (!dri2_surface_receive_events(&dri2surf->base)) {
303 dri2surf->server_stamp++;
304 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
305 &dri2surf->base, dri2surf->server_stamp);
312 dri2_surface_swap_buffers(struct native_surface *nsurf)
314 struct dri2_surface *dri2surf = dri2_surface(nsurf);
315 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
317 /* copy to front buffer */
318 if (dri2surf->have_back)
319 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
320 0, 0, dri2surf->width, dri2surf->height,
321 DRI2BufferBackLeft, DRI2BufferFrontLeft);
323 /* and update fake front buffer */
324 if (dri2surf->have_fake)
325 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
326 0, 0, dri2surf->width, dri2surf->height,
327 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
329 /* force buffers to be updated in next validation call */
330 if (!dri2_surface_receive_events(&dri2surf->base)) {
331 dri2surf->server_stamp++;
332 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
333 &dri2surf->base, dri2surf->server_stamp);
340 dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
341 unsigned int *seq_num, struct pipe_resource **textures,
342 int *width, int *height)
344 struct dri2_surface *dri2surf = dri2_surface(nsurf);
346 if (dri2surf->server_stamp != dri2surf->client_stamp ||
347 (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
348 if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
353 *seq_num = dri2surf->client_stamp;
357 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
358 if (native_attachment_mask_test(attachment_mask, att)) {
359 struct pipe_resource *ptex = dri2surf->textures[att];
361 textures[att] = NULL;
362 pipe_resource_reference(&textures[att], ptex);
368 *width = dri2surf->width;
370 *height = dri2surf->height;
376 dri2_surface_wait(struct native_surface *nsurf)
378 struct dri2_surface *dri2surf = dri2_surface(nsurf);
379 struct dri2_display *dri2dpy = dri2surf->dri2dpy;
381 if (dri2surf->have_fake) {
382 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
383 0, 0, dri2surf->width, dri2surf->height,
384 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
389 dri2_surface_destroy(struct native_surface *nsurf)
391 struct dri2_surface *dri2surf = dri2_surface(nsurf);
394 if (dri2surf->last_xbufs)
395 FREE(dri2surf->last_xbufs);
397 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
398 struct pipe_resource *ptex = dri2surf->textures[i];
399 pipe_resource_reference(&ptex, NULL);
402 if (dri2surf->drawable) {
403 x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
404 dri2surf->drawable, FALSE);
406 util_hash_table_remove(dri2surf->dri2dpy->surfaces,
407 (void *) dri2surf->drawable);
412 static struct dri2_surface *
413 dri2_display_create_surface(struct native_display *ndpy,
414 enum dri2_surface_type type,
416 const struct native_config *nconf)
418 struct dri2_display *dri2dpy = dri2_display(ndpy);
419 struct dri2_config *dri2conf = dri2_config(nconf);
420 struct dri2_surface *dri2surf;
422 dri2surf = CALLOC_STRUCT(dri2_surface);
426 dri2surf->dri2dpy = dri2dpy;
427 dri2surf->type = type;
428 dri2surf->drawable = drawable;
429 dri2surf->color_format = dri2conf->base.color_format;
431 dri2surf->base.destroy = dri2_surface_destroy;
432 dri2surf->base.swap_buffers = dri2_surface_swap_buffers;
433 dri2surf->base.flush_frontbuffer = dri2_surface_flush_frontbuffer;
434 dri2surf->base.validate = dri2_surface_validate;
435 dri2surf->base.wait = dri2_surface_wait;
438 x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
439 /* initialize the geometry */
440 dri2_surface_update_buffers(&dri2surf->base, 0x0);
442 util_hash_table_set(dri2surf->dri2dpy->surfaces,
443 (void *) dri2surf->drawable, (void *) &dri2surf->base);
449 static struct native_surface *
450 dri2_display_create_window_surface(struct native_display *ndpy,
451 EGLNativeWindowType win,
452 const struct native_config *nconf)
454 struct dri2_surface *dri2surf;
456 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_WINDOW,
457 (Drawable) win, nconf);
458 return (dri2surf) ? &dri2surf->base : NULL;
461 static struct native_surface *
462 dri2_display_create_pixmap_surface(struct native_display *ndpy,
463 EGLNativePixmapType pix,
464 const struct native_config *nconf)
466 struct dri2_surface *dri2surf;
468 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PIXMAP,
469 (Drawable) pix, nconf);
470 return (dri2surf) ? &dri2surf->base : NULL;
474 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
478 switch (mode->rgbBits) {
480 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
481 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
484 formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
485 formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
486 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
487 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
490 formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
500 is_format_supported(struct pipe_screen *screen,
501 enum pipe_format fmt, unsigned sample_count, boolean is_color)
503 return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count,
504 (is_color) ? PIPE_BIND_RENDER_TARGET :
505 PIPE_BIND_DEPTH_STENCIL, 0);
509 dri2_display_convert_config(struct native_display *ndpy,
510 const __GLcontextModes *mode,
511 struct native_config *nconf)
513 enum pipe_format formats[32];
515 int sample_count = 0;
517 if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
520 /* skip single-buffered configs */
521 if (!mode->doubleBufferMode)
524 /* only interested in native renderable configs */
525 if (!mode->xRenderable || !mode->drawableType)
528 nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
529 if (mode->doubleBufferMode)
530 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
531 if (mode->stereoMode) {
532 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
533 if (mode->doubleBufferMode)
534 nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
537 /* choose color format */
538 num_formats = choose_color_format(mode, formats);
539 for (i = 0; i < num_formats; i++) {
540 if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
541 nconf->color_format = formats[i];
545 if (nconf->color_format == PIPE_FORMAT_NONE)
548 if (mode->drawableType & GLX_WINDOW_BIT)
549 nconf->window_bit = TRUE;
550 if (mode->drawableType & GLX_PIXMAP_BIT)
551 nconf->pixmap_bit = TRUE;
553 nconf->native_visual_id = mode->visualID;
554 nconf->native_visual_type = mode->visualType;
555 nconf->level = mode->level;
556 nconf->samples = mode->samples;
558 nconf->slow_config = (mode->visualRating == GLX_SLOW_CONFIG);
560 if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
561 nconf->transparent_rgb = TRUE;
562 nconf->transparent_rgb_values[0] = mode->transparentRed;
563 nconf->transparent_rgb_values[1] = mode->transparentGreen;
564 nconf->transparent_rgb_values[2] = mode->transparentBlue;
570 static const struct native_config **
571 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
573 struct dri2_display *dri2dpy = dri2_display(ndpy);
574 const struct native_config **configs;
578 if (!dri2dpy->configs) {
579 const __GLcontextModes *modes;
580 int num_modes, count;
582 modes = x11_screen_get_glx_configs(dri2dpy->xscr);
585 num_modes = x11_context_modes_count(modes);
587 dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
588 if (!dri2dpy->configs)
592 for (i = 0; i < num_modes; i++) {
593 struct native_config *nconf = &dri2dpy->configs[count].base;
594 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf))
599 dri2dpy->num_configs = count;
602 configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
604 for (i = 0; i < dri2dpy->num_configs; i++)
605 configs[i] = (const struct native_config *) &dri2dpy->configs[i];
607 *num_configs = dri2dpy->num_configs;
614 dri2_display_is_pixmap_supported(struct native_display *ndpy,
615 EGLNativePixmapType pix,
616 const struct native_config *nconf)
618 struct dri2_display *dri2dpy = dri2_display(ndpy);
619 uint depth, nconf_depth;
621 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
622 nconf_depth = util_format_get_blocksizebits(nconf->color_format);
624 /* simple depth match for now */
625 return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
629 dri2_display_get_param(struct native_display *ndpy,
630 enum native_param_type param)
635 case NATIVE_PARAM_USE_NATIVE_BUFFER:
636 /* DRI2GetBuffers use the native buffers */
648 dri2_display_destroy(struct native_display *ndpy)
650 struct dri2_display *dri2dpy = dri2_display(ndpy);
652 if (dri2dpy->configs)
653 FREE(dri2dpy->configs);
655 if (dri2dpy->base.screen)
656 dri2dpy->base.screen->destroy(dri2dpy->base.screen);
658 if (dri2dpy->surfaces)
659 util_hash_table_destroy(dri2dpy->surfaces);
662 x11_screen_destroy(dri2dpy->xscr);
663 if (dri2dpy->own_dpy)
664 XCloseDisplay(dri2dpy->dpy);
665 if (dri2dpy->api && dri2dpy->api->destroy)
666 dri2dpy->api->destroy(dri2dpy->api);
671 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
674 struct native_display *ndpy = (struct native_display* ) user_data;
675 struct dri2_display *dri2dpy = dri2_display(ndpy);
676 struct native_surface *nsurf;
677 struct dri2_surface *dri2surf;
679 nsurf = (struct native_surface *)
680 util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
684 dri2surf = dri2_surface(nsurf);
686 dri2surf->server_stamp++;
687 dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
688 &dri2surf->base, dri2surf->server_stamp);
692 * Initialize DRI2 and pipe screen.
695 dri2_display_init_screen(struct native_display *ndpy)
697 struct dri2_display *dri2dpy = dri2_display(ndpy);
698 const char *driver = dri2dpy->api->name;
701 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
702 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
703 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
707 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
708 &dri2dpy->dri_major, &dri2dpy->dri_minor);
709 if (!dri2dpy->dri_driver || !driver ||
710 strcmp(dri2dpy->dri_driver, driver) != 0) {
711 _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
712 dri2dpy->dri_driver, dri2dpy->api->name);
716 fd = x11_screen_enable_dri2(dri2dpy->xscr,
717 dri2_display_invalidate_buffers, &dri2dpy->base);
721 dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, NULL);
722 if (!dri2dpy->base.screen) {
723 _eglLog(_EGL_WARNING, "failed to create DRM screen");
731 dri2_display_hash_table_hash(void *key)
733 XID drawable = pointer_to_uintptr(key);
734 return (unsigned) drawable;
738 dri2_display_hash_table_compare(void *key1, void *key2)
740 return (key1 - key2);
743 struct native_display *
744 x11_create_dri2_display(EGLNativeDisplayType dpy,
745 struct native_event_handler *event_handler,
748 struct dri2_display *dri2dpy;
750 dri2dpy = CALLOC_STRUCT(dri2_display);
754 dri2dpy->event_handler = event_handler;
759 dri2dpy->dpy = XOpenDisplay(NULL);
761 dri2_display_destroy(&dri2dpy->base);
764 dri2dpy->own_dpy = TRUE;
767 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
768 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
769 if (!dri2dpy->xscr) {
770 dri2_display_destroy(&dri2dpy->base);
774 if (!dri2_display_init_screen(&dri2dpy->base)) {
775 dri2_display_destroy(&dri2dpy->base);
779 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
780 dri2_display_hash_table_compare);
781 if (!dri2dpy->surfaces) {
782 dri2_display_destroy(&dri2dpy->base);
786 dri2dpy->base.destroy = dri2_display_destroy;
787 dri2dpy->base.get_param = dri2_display_get_param;
788 dri2dpy->base.get_configs = dri2_display_get_configs;
789 dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
790 dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
791 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
793 return &dri2dpy->base;