| /* |
| * Mesa 3-D graphics library |
| * Version: 7.8 |
| * |
| * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include "util/u_memory.h" |
| #include "util/u_math.h" |
| #include "util/u_format.h" |
| #include "util/u_inlines.h" |
| #include "util/u_hash_table.h" |
| #include "pipe/p_compiler.h" |
| #include "pipe/p_screen.h" |
| #include "pipe/p_context.h" |
| #include "pipe/p_state.h" |
| #include "state_tracker/drm_driver.h" |
| #include "egllog.h" |
| |
| #include "native_x11.h" |
| #include "x11_screen.h" |
| |
| #ifdef GLX_DIRECT_RENDERING |
| |
| struct dri2_display { |
| struct native_display base; |
| Display *dpy; |
| boolean own_dpy; |
| |
| struct native_event_handler *event_handler; |
| |
| struct x11_screen *xscr; |
| int xscr_number; |
| const char *dri_driver; |
| int dri_major, dri_minor; |
| |
| struct dri2_config *configs; |
| int num_configs; |
| |
| struct util_hash_table *surfaces; |
| }; |
| |
| struct dri2_surface { |
| struct native_surface base; |
| Drawable drawable; |
| enum pipe_format color_format; |
| struct dri2_display *dri2dpy; |
| |
| unsigned int server_stamp; |
| unsigned int client_stamp; |
| int width, height; |
| struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; |
| uint valid_mask; |
| |
| boolean have_back, have_fake; |
| |
| struct x11_drawable_buffer *last_xbufs; |
| int last_num_xbufs; |
| }; |
| |
| struct dri2_config { |
| struct native_config base; |
| }; |
| |
| static INLINE struct dri2_display * |
| dri2_display(const struct native_display *ndpy) |
| { |
| return (struct dri2_display *) ndpy; |
| } |
| |
| static INLINE struct dri2_surface * |
| dri2_surface(const struct native_surface *nsurf) |
| { |
| return (struct dri2_surface *) nsurf; |
| } |
| |
| static INLINE struct dri2_config * |
| dri2_config(const struct native_config *nconf) |
| { |
| return (struct dri2_config *) nconf; |
| } |
| |
| /** |
| * Process the buffers returned by the server. |
| */ |
| static void |
| dri2_surface_process_drawable_buffers(struct native_surface *nsurf, |
| struct x11_drawable_buffer *xbufs, |
| int num_xbufs) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| struct dri2_display *dri2dpy = dri2surf->dri2dpy; |
| struct pipe_resource templ; |
| struct winsys_handle whandle; |
| uint valid_mask; |
| int i; |
| |
| /* free the old textures */ |
| for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) |
| pipe_resource_reference(&dri2surf->textures[i], NULL); |
| dri2surf->valid_mask = 0x0; |
| |
| dri2surf->have_back = FALSE; |
| dri2surf->have_fake = FALSE; |
| |
| if (!xbufs) |
| return; |
| |
| memset(&templ, 0, sizeof(templ)); |
| templ.target = PIPE_TEXTURE_2D; |
| templ.last_level = 0; |
| templ.width0 = dri2surf->width; |
| templ.height0 = dri2surf->height; |
| templ.depth0 = 1; |
| templ.array_size = 1; |
| templ.format = dri2surf->color_format; |
| templ.bind = PIPE_BIND_RENDER_TARGET; |
| |
| valid_mask = 0x0; |
| for (i = 0; i < num_xbufs; i++) { |
| struct x11_drawable_buffer *xbuf = &xbufs[i]; |
| const char *desc; |
| enum native_attachment natt; |
| |
| switch (xbuf->attachment) { |
| case DRI2BufferFrontLeft: |
| natt = NATIVE_ATTACHMENT_FRONT_LEFT; |
| desc = "DRI2 Front Buffer"; |
| break; |
| case DRI2BufferFakeFrontLeft: |
| natt = NATIVE_ATTACHMENT_FRONT_LEFT; |
| desc = "DRI2 Fake Front Buffer"; |
| dri2surf->have_fake = TRUE; |
| break; |
| case DRI2BufferBackLeft: |
| natt = NATIVE_ATTACHMENT_BACK_LEFT; |
| desc = "DRI2 Back Buffer"; |
| dri2surf->have_back = TRUE; |
| break; |
| default: |
| desc = NULL; |
| break; |
| } |
| |
| if (!desc || dri2surf->textures[natt]) { |
| if (!desc) |
| _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment); |
| else |
| _eglLog(_EGL_WARNING, "both real and fake front buffers are listed"); |
| continue; |
| } |
| |
| memset(&whandle, 0, sizeof(whandle)); |
| whandle.stride = xbuf->pitch; |
| whandle.handle = xbuf->name; |
| dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle( |
| dri2dpy->base.screen, &templ, &whandle); |
| if (dri2surf->textures[natt]) |
| valid_mask |= 1 << natt; |
| } |
| |
| dri2surf->valid_mask = valid_mask; |
| } |
| |
| /** |
| * Get the buffers from the server. |
| */ |
| static void |
| dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| struct dri2_display *dri2dpy = dri2surf->dri2dpy; |
| unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS * 2]; |
| int num_ins, num_outs, att; |
| struct x11_drawable_buffer *xbufs; |
| uint bpp = util_format_get_blocksizebits(dri2surf->color_format); |
| boolean with_format = FALSE; /* never ask for depth/stencil */ |
| |
| /* We must get the front on servers which doesn't support with format |
| * due to a silly bug in core dri2. You can't copy to/from a buffer |
| * that you haven't requested and you recive BadValue errors */ |
| if (dri2surf->dri2dpy->dri_minor < 1) { |
| with_format = FALSE; |
| buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT); |
| } |
| |
| /* prepare the attachments */ |
| num_ins = 0; |
| for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { |
| if (native_attachment_mask_test(buffer_mask, att)) { |
| unsigned int dri2att; |
| |
| switch (att) { |
| case NATIVE_ATTACHMENT_FRONT_LEFT: |
| dri2att = DRI2BufferFrontLeft; |
| break; |
| case NATIVE_ATTACHMENT_BACK_LEFT: |
| dri2att = DRI2BufferBackLeft; |
| break; |
| case NATIVE_ATTACHMENT_FRONT_RIGHT: |
| dri2att = DRI2BufferFrontRight; |
| break; |
| case NATIVE_ATTACHMENT_BACK_RIGHT: |
| dri2att = DRI2BufferBackRight; |
| break; |
| default: |
| assert(0); |
| dri2att = 0; |
| break; |
| } |
| |
| dri2atts[num_ins++] = dri2att; |
| if (with_format) |
| dri2atts[num_ins++] = bpp; |
| } |
| } |
| if (with_format) |
| num_ins /= 2; |
| |
| xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable, |
| &dri2surf->width, &dri2surf->height, |
| dri2atts, with_format, num_ins, &num_outs); |
| |
| /* we should be able to do better... */ |
| if (xbufs && dri2surf->last_num_xbufs == num_outs && |
| memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) { |
| FREE(xbufs); |
| dri2surf->client_stamp = dri2surf->server_stamp; |
| return; |
| } |
| |
| dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs); |
| |
| dri2surf->server_stamp++; |
| dri2surf->client_stamp = dri2surf->server_stamp; |
| |
| if (dri2surf->last_xbufs) |
| FREE(dri2surf->last_xbufs); |
| dri2surf->last_xbufs = xbufs; |
| dri2surf->last_num_xbufs = num_outs; |
| } |
| |
| /** |
| * Update the buffers of the surface. This is a slow function due to the |
| * round-trip to the server. |
| */ |
| static boolean |
| dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| |
| dri2_surface_get_buffers(&dri2surf->base, buffer_mask); |
| |
| return ((dri2surf->valid_mask & buffer_mask) == buffer_mask); |
| } |
| |
| /** |
| * Return TRUE if the surface receives DRI2_InvalidateBuffers events. |
| */ |
| static INLINE boolean |
| dri2_surface_receive_events(struct native_surface *nsurf) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| return (dri2surf->dri2dpy->dri_minor >= 3); |
| } |
| |
| static boolean |
| dri2_surface_flush_frontbuffer(struct native_surface *nsurf) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| struct dri2_display *dri2dpy = dri2surf->dri2dpy; |
| |
| /* copy to real front buffer */ |
| if (dri2surf->have_fake) |
| x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, |
| 0, 0, dri2surf->width, dri2surf->height, |
| DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); |
| |
| /* force buffers to be updated in next validation call */ |
| if (!dri2_surface_receive_events(&dri2surf->base)) { |
| dri2surf->server_stamp++; |
| dri2dpy->event_handler->invalid_surface(&dri2dpy->base, |
| &dri2surf->base, dri2surf->server_stamp); |
| } |
| |
| return TRUE; |
| } |
| |
| static boolean |
| dri2_surface_swap_buffers(struct native_surface *nsurf) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| struct dri2_display *dri2dpy = dri2surf->dri2dpy; |
| |
| /* copy to front buffer */ |
| if (dri2surf->have_back) |
| x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, |
| 0, 0, dri2surf->width, dri2surf->height, |
| DRI2BufferBackLeft, DRI2BufferFrontLeft); |
| |
| /* and update fake front buffer */ |
| if (dri2surf->have_fake) |
| x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, |
| 0, 0, dri2surf->width, dri2surf->height, |
| DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); |
| |
| /* force buffers to be updated in next validation call */ |
| if (!dri2_surface_receive_events(&dri2surf->base)) { |
| dri2surf->server_stamp++; |
| dri2dpy->event_handler->invalid_surface(&dri2dpy->base, |
| &dri2surf->base, dri2surf->server_stamp); |
| } |
| |
| return TRUE; |
| } |
| |
| static boolean |
| dri2_surface_present(struct native_surface *nsurf, |
| enum native_attachment natt, |
| boolean preserve, |
| uint swap_interval) |
| { |
| boolean ret; |
| |
| if (swap_interval) |
| return FALSE; |
| |
| switch (natt) { |
| case NATIVE_ATTACHMENT_FRONT_LEFT: |
| ret = dri2_surface_flush_frontbuffer(nsurf); |
| break; |
| case NATIVE_ATTACHMENT_BACK_LEFT: |
| ret = dri2_surface_swap_buffers(nsurf); |
| break; |
| default: |
| ret = FALSE; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static boolean |
| dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, |
| unsigned int *seq_num, struct pipe_resource **textures, |
| int *width, int *height) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| |
| if (dri2surf->server_stamp != dri2surf->client_stamp || |
| (dri2surf->valid_mask & attachment_mask) != attachment_mask) { |
| if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask)) |
| return FALSE; |
| } |
| |
| if (seq_num) |
| *seq_num = dri2surf->client_stamp; |
| |
| if (textures) { |
| int att; |
| for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { |
| if (native_attachment_mask_test(attachment_mask, att)) { |
| struct pipe_resource *ptex = dri2surf->textures[att]; |
| |
| textures[att] = NULL; |
| pipe_resource_reference(&textures[att], ptex); |
| } |
| } |
| } |
| |
| if (width) |
| *width = dri2surf->width; |
| if (height) |
| *height = dri2surf->height; |
| |
| return TRUE; |
| } |
| |
| static void |
| dri2_surface_wait(struct native_surface *nsurf) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| struct dri2_display *dri2dpy = dri2surf->dri2dpy; |
| |
| if (dri2surf->have_fake) { |
| x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, |
| 0, 0, dri2surf->width, dri2surf->height, |
| DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); |
| } |
| } |
| |
| static void |
| dri2_surface_destroy(struct native_surface *nsurf) |
| { |
| struct dri2_surface *dri2surf = dri2_surface(nsurf); |
| int i; |
| |
| if (dri2surf->last_xbufs) |
| FREE(dri2surf->last_xbufs); |
| |
| for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { |
| struct pipe_resource *ptex = dri2surf->textures[i]; |
| pipe_resource_reference(&ptex, NULL); |
| } |
| |
| if (dri2surf->drawable) { |
| x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr, |
| dri2surf->drawable, FALSE); |
| |
| util_hash_table_remove(dri2surf->dri2dpy->surfaces, |
| (void *) dri2surf->drawable); |
| } |
| FREE(dri2surf); |
| } |
| |
| static struct dri2_surface * |
| dri2_display_create_surface(struct native_display *ndpy, |
| Drawable drawable, |
| enum pipe_format color_format) |
| { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| struct dri2_surface *dri2surf; |
| |
| dri2surf = CALLOC_STRUCT(dri2_surface); |
| if (!dri2surf) |
| return NULL; |
| |
| dri2surf->dri2dpy = dri2dpy; |
| dri2surf->drawable = drawable; |
| dri2surf->color_format = color_format; |
| |
| dri2surf->base.destroy = dri2_surface_destroy; |
| dri2surf->base.present = dri2_surface_present; |
| dri2surf->base.validate = dri2_surface_validate; |
| dri2surf->base.wait = dri2_surface_wait; |
| |
| if (drawable) { |
| x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE); |
| /* initialize the geometry */ |
| dri2_surface_update_buffers(&dri2surf->base, 0x0); |
| |
| util_hash_table_set(dri2surf->dri2dpy->surfaces, |
| (void *) dri2surf->drawable, (void *) &dri2surf->base); |
| } |
| |
| return dri2surf; |
| } |
| |
| static struct native_surface * |
| dri2_display_create_window_surface(struct native_display *ndpy, |
| EGLNativeWindowType win, |
| const struct native_config *nconf) |
| { |
| struct dri2_surface *dri2surf; |
| |
| dri2surf = dri2_display_create_surface(ndpy, |
| (Drawable) win, nconf->color_format); |
| return (dri2surf) ? &dri2surf->base : NULL; |
| } |
| |
| static struct native_surface * |
| dri2_display_create_pixmap_surface(struct native_display *ndpy, |
| EGLNativePixmapType pix, |
| const struct native_config *nconf) |
| { |
| struct dri2_surface *dri2surf; |
| |
| if (!nconf) { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| uint depth, nconf_depth; |
| int i; |
| |
| depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix); |
| for (i = 0; i < dri2dpy->num_configs; i++) { |
| nconf_depth = util_format_get_blocksizebits( |
| dri2dpy->configs[i].base.color_format); |
| /* simple depth match for now */ |
| if (depth == nconf_depth || |
| (depth == 24 && depth + 8 == nconf_depth)) { |
| nconf = &dri2dpy->configs[i].base; |
| break; |
| } |
| } |
| |
| if (!nconf) |
| return NULL; |
| } |
| |
| dri2surf = dri2_display_create_surface(ndpy, |
| (Drawable) pix, nconf->color_format); |
| return (dri2surf) ? &dri2surf->base : NULL; |
| } |
| |
| static int |
| choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32]) |
| { |
| int count = 0; |
| |
| switch (mode->rgbBits) { |
| case 32: |
| formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM; |
| formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM; |
| break; |
| case 24: |
| formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM; |
| formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM; |
| formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM; |
| formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM; |
| break; |
| case 16: |
| formats[count++] = PIPE_FORMAT_B5G6R5_UNORM; |
| break; |
| default: |
| break; |
| } |
| |
| return count; |
| } |
| |
| static boolean |
| is_format_supported(struct pipe_screen *screen, |
| enum pipe_format fmt, unsigned sample_count, boolean is_color) |
| { |
| return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count, |
| (is_color) ? PIPE_BIND_RENDER_TARGET : |
| PIPE_BIND_DEPTH_STENCIL); |
| } |
| |
| static boolean |
| dri2_display_convert_config(struct native_display *ndpy, |
| const __GLcontextModes *mode, |
| struct native_config *nconf) |
| { |
| enum pipe_format formats[32]; |
| int num_formats, i; |
| int sample_count = 0; |
| |
| if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode) |
| return FALSE; |
| |
| /* only interested in native renderable configs */ |
| if (!mode->xRenderable || !mode->drawableType) |
| return FALSE; |
| |
| /* fast/slow configs are probably not relevant */ |
| if (mode->visualRating == GLX_SLOW_CONFIG) |
| return FALSE; |
| |
| nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT; |
| if (mode->doubleBufferMode) |
| nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT; |
| if (mode->stereoMode) { |
| nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT; |
| if (mode->doubleBufferMode) |
| nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT; |
| } |
| |
| /* choose color format */ |
| num_formats = choose_color_format(mode, formats); |
| for (i = 0; i < num_formats; i++) { |
| if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) { |
| nconf->color_format = formats[i]; |
| break; |
| } |
| } |
| if (nconf->color_format == PIPE_FORMAT_NONE) |
| return FALSE; |
| |
| if ((mode->drawableType & GLX_WINDOW_BIT) && mode->visualID) |
| nconf->window_bit = TRUE; |
| if (mode->drawableType & GLX_PIXMAP_BIT) |
| nconf->pixmap_bit = TRUE; |
| |
| nconf->native_visual_id = mode->visualID; |
| switch (mode->visualType) { |
| case GLX_TRUE_COLOR: |
| nconf->native_visual_type = TrueColor; |
| break; |
| case GLX_DIRECT_COLOR: |
| nconf->native_visual_type = DirectColor; |
| break; |
| case GLX_PSEUDO_COLOR: |
| nconf->native_visual_type = PseudoColor; |
| break; |
| case GLX_STATIC_COLOR: |
| nconf->native_visual_type = StaticColor; |
| break; |
| case GLX_GRAY_SCALE: |
| nconf->native_visual_type = GrayScale; |
| break; |
| case GLX_STATIC_GRAY: |
| nconf->native_visual_type = StaticGray; |
| break; |
| } |
| nconf->level = mode->level; |
| |
| if (mode->transparentPixel == GLX_TRANSPARENT_RGB) { |
| nconf->transparent_rgb = TRUE; |
| nconf->transparent_rgb_values[0] = mode->transparentRed; |
| nconf->transparent_rgb_values[1] = mode->transparentGreen; |
| nconf->transparent_rgb_values[2] = mode->transparentBlue; |
| } |
| |
| return TRUE; |
| } |
| |
| static const struct native_config ** |
| dri2_display_get_configs(struct native_display *ndpy, int *num_configs) |
| { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| const struct native_config **configs; |
| int i; |
| |
| /* first time */ |
| if (!dri2dpy->configs) { |
| const __GLcontextModes *modes; |
| int num_modes, count; |
| |
| modes = x11_screen_get_glx_configs(dri2dpy->xscr); |
| if (!modes) |
| return NULL; |
| num_modes = x11_context_modes_count(modes); |
| |
| dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs)); |
| if (!dri2dpy->configs) |
| return NULL; |
| |
| count = 0; |
| for (i = 0; i < num_modes; i++) { |
| struct native_config *nconf = &dri2dpy->configs[count].base; |
| |
| if (dri2_display_convert_config(&dri2dpy->base, modes, nconf)) { |
| int j; |
| /* look for duplicates */ |
| for (j = 0; j < count; j++) { |
| if (memcmp(&dri2dpy->configs[j], nconf, sizeof(*nconf)) == 0) |
| break; |
| } |
| if (j == count) |
| count++; |
| } |
| modes = modes->next; |
| } |
| |
| dri2dpy->num_configs = count; |
| } |
| |
| configs = MALLOC(dri2dpy->num_configs * sizeof(*configs)); |
| if (configs) { |
| for (i = 0; i < dri2dpy->num_configs; i++) |
| configs[i] = (const struct native_config *) &dri2dpy->configs[i]; |
| if (num_configs) |
| *num_configs = dri2dpy->num_configs; |
| } |
| |
| return configs; |
| } |
| |
| static boolean |
| dri2_display_is_pixmap_supported(struct native_display *ndpy, |
| EGLNativePixmapType pix, |
| const struct native_config *nconf) |
| { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| uint depth, nconf_depth; |
| |
| depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix); |
| nconf_depth = util_format_get_blocksizebits(nconf->color_format); |
| |
| /* simple depth match for now */ |
| return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth)); |
| } |
| |
| static int |
| dri2_display_get_param(struct native_display *ndpy, |
| enum native_param_type param) |
| { |
| int val; |
| |
| switch (param) { |
| case NATIVE_PARAM_USE_NATIVE_BUFFER: |
| /* DRI2GetBuffers uses the native buffers */ |
| val = TRUE; |
| break; |
| case NATIVE_PARAM_PRESERVE_BUFFER: |
| /* DRI2CopyRegion is used */ |
| val = TRUE; |
| break; |
| case NATIVE_PARAM_MAX_SWAP_INTERVAL: |
| default: |
| val = 0; |
| break; |
| } |
| |
| return val; |
| } |
| |
| static void |
| dri2_display_destroy(struct native_display *ndpy) |
| { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| |
| if (dri2dpy->configs) |
| FREE(dri2dpy->configs); |
| |
| if (dri2dpy->base.screen) |
| dri2dpy->base.screen->destroy(dri2dpy->base.screen); |
| |
| if (dri2dpy->surfaces) |
| util_hash_table_destroy(dri2dpy->surfaces); |
| |
| if (dri2dpy->xscr) |
| x11_screen_destroy(dri2dpy->xscr); |
| if (dri2dpy->own_dpy) |
| XCloseDisplay(dri2dpy->dpy); |
| FREE(dri2dpy); |
| } |
| |
| static void |
| dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable, |
| void *user_data) |
| { |
| struct native_display *ndpy = (struct native_display* ) user_data; |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| struct native_surface *nsurf; |
| struct dri2_surface *dri2surf; |
| |
| nsurf = (struct native_surface *) |
| util_hash_table_get(dri2dpy->surfaces, (void *) drawable); |
| if (!nsurf) |
| return; |
| |
| dri2surf = dri2_surface(nsurf); |
| |
| dri2surf->server_stamp++; |
| dri2dpy->event_handler->invalid_surface(&dri2dpy->base, |
| &dri2surf->base, dri2surf->server_stamp); |
| } |
| |
| /** |
| * Initialize DRI2 and pipe screen. |
| */ |
| static boolean |
| dri2_display_init_screen(struct native_display *ndpy) |
| { |
| struct dri2_display *dri2dpy = dri2_display(ndpy); |
| int fd; |
| |
| if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) || |
| !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) { |
| _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported"); |
| return FALSE; |
| } |
| |
| dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr, |
| &dri2dpy->dri_major, &dri2dpy->dri_minor); |
| |
| fd = x11_screen_enable_dri2(dri2dpy->xscr, |
| dri2_display_invalidate_buffers, &dri2dpy->base); |
| if (fd < 0) |
| return FALSE; |
| |
| dri2dpy->base.screen = |
| dri2dpy->event_handler->new_drm_screen(&dri2dpy->base, |
| dri2dpy->dri_driver, fd); |
| if (!dri2dpy->base.screen) { |
| _eglLog(_EGL_DEBUG, "failed to create DRM screen"); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| static unsigned |
| dri2_display_hash_table_hash(void *key) |
| { |
| XID drawable = pointer_to_uintptr(key); |
| return (unsigned) drawable; |
| } |
| |
| static int |
| dri2_display_hash_table_compare(void *key1, void *key2) |
| { |
| return ((char *) key1 - (char *) key2); |
| } |
| |
| struct native_display * |
| x11_create_dri2_display(Display *dpy, |
| struct native_event_handler *event_handler, |
| void *user_data) |
| { |
| struct dri2_display *dri2dpy; |
| |
| dri2dpy = CALLOC_STRUCT(dri2_display); |
| if (!dri2dpy) |
| return NULL; |
| |
| dri2dpy->event_handler = event_handler; |
| dri2dpy->base.user_data = user_data; |
| |
| dri2dpy->dpy = dpy; |
| if (!dri2dpy->dpy) { |
| dri2dpy->dpy = XOpenDisplay(NULL); |
| if (!dri2dpy->dpy) { |
| dri2_display_destroy(&dri2dpy->base); |
| return NULL; |
| } |
| dri2dpy->own_dpy = TRUE; |
| } |
| |
| dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy); |
| dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number); |
| if (!dri2dpy->xscr) { |
| dri2_display_destroy(&dri2dpy->base); |
| return NULL; |
| } |
| |
| if (!dri2_display_init_screen(&dri2dpy->base)) { |
| dri2_display_destroy(&dri2dpy->base); |
| return NULL; |
| } |
| |
| dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash, |
| dri2_display_hash_table_compare); |
| if (!dri2dpy->surfaces) { |
| dri2_display_destroy(&dri2dpy->base); |
| return NULL; |
| } |
| |
| dri2dpy->base.destroy = dri2_display_destroy; |
| dri2dpy->base.get_param = dri2_display_get_param; |
| dri2dpy->base.get_configs = dri2_display_get_configs; |
| dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported; |
| dri2dpy->base.create_window_surface = dri2_display_create_window_surface; |
| dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface; |
| |
| return &dri2dpy->base; |
| } |
| |
| #else /* GLX_DIRECT_RENDERING */ |
| |
| struct native_display * |
| x11_create_dri2_display(Display *dpy, |
| struct native_event_handler *event_handler, |
| void *user_data) |
| { |
| return NULL; |
| } |
| |
| #endif /* GLX_DIRECT_RENDERING */ |