/* * 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 <X11/Xlib.h> #include <X11/Xutil.h> #include "util/u_memory.h" #include "util/u_math.h" #include "util/u_format.h" #include "pipe/p_compiler.h" #include "util/u_inlines.h" #include "state_tracker/xlib_sw_winsys.h" #include "util/u_debug.h" #include "egllog.h" #include "common/native_helper.h" #include "native_x11.h" #include "x11_screen.h" struct ximage_display { struct native_display base; Display *dpy; boolean own_dpy; const struct native_event_handler *event_handler; struct x11_screen *xscr; int xscr_number; struct ximage_config *configs; int num_configs; }; struct ximage_surface { struct native_surface base; Drawable drawable; enum pipe_format color_format; XVisualInfo visual; struct ximage_display *xdpy; unsigned int server_stamp; unsigned int client_stamp; struct resource_surface *rsurf; struct xlib_drawable xdraw; }; struct ximage_config { struct native_config base; const XVisualInfo *visual; }; static INLINE struct ximage_display * ximage_display(const struct native_display *ndpy) { return (struct ximage_display *) ndpy; } static INLINE struct ximage_surface * ximage_surface(const struct native_surface *nsurf) { return (struct ximage_surface *) nsurf; } static INLINE struct ximage_config * ximage_config(const struct native_config *nconf) { return (struct ximage_config *) nconf; } /** * Update the geometry of the surface. This is a slow functions. */ static void ximage_surface_update_geometry(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); Status ok; Window root; int x, y; unsigned int w, h, border, depth; ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable, &root, &x, &y, &w, &h, &border, &depth); if (ok && resource_surface_set_size(xsurf->rsurf, w, h)) xsurf->server_stamp++; } /** * Update the buffers of the surface. */ static boolean ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) { struct ximage_surface *xsurf = ximage_surface(nsurf); if (xsurf->client_stamp != xsurf->server_stamp) { ximage_surface_update_geometry(&xsurf->base); xsurf->client_stamp = xsurf->server_stamp; } return resource_surface_add_resources(xsurf->rsurf, buffer_mask); } /** * Emulate an invalidate event. */ static void ximage_surface_invalidate(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); struct ximage_display *xdpy = xsurf->xdpy; xsurf->server_stamp++; xdpy->event_handler->invalid_surface(&xdpy->base, &xsurf->base, xsurf->server_stamp); } static boolean ximage_surface_flush_frontbuffer(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); boolean ret; ret = resource_surface_present(xsurf->rsurf, NATIVE_ATTACHMENT_FRONT_LEFT, (void *) &xsurf->xdraw); /* force buffers to be updated in next validation call */ ximage_surface_invalidate(&xsurf->base); return ret; } static boolean ximage_surface_swap_buffers(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); boolean ret; ret = resource_surface_present(xsurf->rsurf, NATIVE_ATTACHMENT_BACK_LEFT, (void *) &xsurf->xdraw); resource_surface_swap_buffers(xsurf->rsurf, NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE); /* the front/back buffers have been swapped */ ximage_surface_invalidate(&xsurf->base); return ret; } static boolean ximage_surface_present(struct native_surface *nsurf, const struct native_present_control *ctrl) { boolean ret; if (ctrl->preserve || ctrl->swap_interval) return FALSE; switch (ctrl->natt) { case NATIVE_ATTACHMENT_FRONT_LEFT: ret = ximage_surface_flush_frontbuffer(nsurf); break; case NATIVE_ATTACHMENT_BACK_LEFT: ret = ximage_surface_swap_buffers(nsurf); break; default: ret = FALSE; break; } return ret; } static boolean ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, unsigned int *seq_num, struct pipe_resource **textures, int *width, int *height) { struct ximage_surface *xsurf = ximage_surface(nsurf); uint w, h; if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask)) return FALSE; if (seq_num) *seq_num = xsurf->client_stamp; if (textures) resource_surface_get_resources(xsurf->rsurf, textures, attachment_mask); resource_surface_get_size(xsurf->rsurf, &w, &h); if (width) *width = w; if (height) *height = h; return TRUE; } static void ximage_surface_wait(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); XSync(xsurf->xdpy->dpy, FALSE); /* TODO XGetImage and update the front texture */ } static void ximage_surface_destroy(struct native_surface *nsurf) { struct ximage_surface *xsurf = ximage_surface(nsurf); resource_surface_destroy(xsurf->rsurf); FREE(xsurf); } static struct ximage_surface * ximage_display_create_surface(struct native_display *ndpy, Drawable drawable, const struct native_config *nconf) { struct ximage_display *xdpy = ximage_display(ndpy); struct ximage_config *xconf = ximage_config(nconf); struct ximage_surface *xsurf; xsurf = CALLOC_STRUCT(ximage_surface); if (!xsurf) return NULL; xsurf->xdpy = xdpy; xsurf->color_format = xconf->base.color_format; xsurf->drawable = drawable; xsurf->rsurf = resource_surface_create(xdpy->base.screen, xsurf->color_format, PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT); if (!xsurf->rsurf) { FREE(xsurf); return NULL; } xsurf->drawable = drawable; xsurf->visual = *xconf->visual; /* initialize the geometry */ ximage_surface_update_geometry(&xsurf->base); xsurf->xdraw.visual = xsurf->visual.visual; xsurf->xdraw.depth = xsurf->visual.depth; xsurf->xdraw.drawable = xsurf->drawable; xsurf->base.destroy = ximage_surface_destroy; xsurf->base.present = ximage_surface_present; xsurf->base.validate = ximage_surface_validate; xsurf->base.wait = ximage_surface_wait; return xsurf; } static struct native_surface * ximage_display_create_window_surface(struct native_display *ndpy, EGLNativeWindowType win, const struct native_config *nconf) { struct ximage_surface *xsurf; xsurf = ximage_display_create_surface(ndpy, (Drawable) win, nconf); return (xsurf) ? &xsurf->base : NULL; } static enum pipe_format get_pixmap_format(struct native_display *ndpy, EGLNativePixmapType pix) { struct ximage_display *xdpy = ximage_display(ndpy); enum pipe_format fmt; uint depth; depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); switch (depth) { case 32: fmt = PIPE_FORMAT_B8G8R8A8_UNORM; break; case 24: fmt = PIPE_FORMAT_B8G8R8X8_UNORM; break; case 16: fmt = PIPE_FORMAT_B5G6R5_UNORM; break; default: fmt = PIPE_FORMAT_NONE; break; } return fmt; } static struct native_surface * ximage_display_create_pixmap_surface(struct native_display *ndpy, EGLNativePixmapType pix, const struct native_config *nconf) { struct ximage_surface *xsurf; /* find the config */ if (!nconf) { struct ximage_display *xdpy = ximage_display(ndpy); enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); int i; if (fmt != PIPE_FORMAT_NONE) { for (i = 0; i < xdpy->num_configs; i++) { if (xdpy->configs[i].base.color_format == fmt) { nconf = &xdpy->configs[i].base; break; } } } if (!nconf) return NULL; } xsurf = ximage_display_create_surface(ndpy, (Drawable) pix, nconf); return (xsurf) ? &xsurf->base : NULL; } static enum pipe_format choose_format(const XVisualInfo *vinfo) { enum pipe_format fmt; /* TODO elaborate the formats */ switch (vinfo->depth) { case 32: fmt = PIPE_FORMAT_B8G8R8A8_UNORM; break; case 24: fmt = PIPE_FORMAT_B8G8R8X8_UNORM; break; case 16: fmt = PIPE_FORMAT_B5G6R5_UNORM; break; default: fmt = PIPE_FORMAT_NONE; break; } return fmt; } static const struct native_config ** ximage_display_get_configs(struct native_display *ndpy, int *num_configs) { struct ximage_display *xdpy = ximage_display(ndpy); const struct native_config **configs; int i; /* first time */ if (!xdpy->configs) { const XVisualInfo *visuals; int num_visuals, count; visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); if (!visuals) return NULL; /* * Create two configs for each visual. * One with depth/stencil buffer; one without */ xdpy->configs = CALLOC(num_visuals * 2, sizeof(*xdpy->configs)); if (!xdpy->configs) return NULL; count = 0; for (i = 0; i < num_visuals; i++) { struct ximage_config *xconf = &xdpy->configs[count]; xconf->visual = &visuals[i]; xconf->base.color_format = choose_format(xconf->visual); if (xconf->base.color_format == PIPE_FORMAT_NONE) continue; xconf->base.buffer_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | (1 << NATIVE_ATTACHMENT_BACK_LEFT); xconf->base.window_bit = TRUE; xconf->base.pixmap_bit = TRUE; xconf->base.native_visual_id = xconf->visual->visualid; #if defined(__cplusplus) || defined(c_plusplus) xconf->base.native_visual_type = xconf->visual->c_class; #else xconf->base.native_visual_type = xconf->visual->class; #endif count++; } xdpy->num_configs = count; } configs = MALLOC(xdpy->num_configs * sizeof(*configs)); if (configs) { for (i = 0; i < xdpy->num_configs; i++) configs[i] = (const struct native_config *) &xdpy->configs[i]; if (num_configs) *num_configs = xdpy->num_configs; } return configs; } static boolean ximage_display_get_pixmap_format(struct native_display *ndpy, EGLNativePixmapType pix, enum pipe_format *format) { struct ximage_display *xdpy = ximage_display(ndpy); *format = get_pixmap_format(&xdpy->base, pix); return (*format != PIPE_FORMAT_NONE); } static boolean ximage_display_copy_to_pixmap(struct native_display *ndpy, EGLNativePixmapType pix, struct pipe_resource *src) { /* fast path to avoid unnecessary allocation and resource_copy_region */ if (src->bind & PIPE_BIND_DISPLAY_TARGET) { struct ximage_display *xdpy = ximage_display(ndpy); enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); const struct ximage_config *xconf = NULL; struct xlib_drawable xdraw; int i; if (fmt == PIPE_FORMAT_NONE || src->format != fmt) return FALSE; for (i = 0; i < xdpy->num_configs; i++) { if (xdpy->configs[i].base.color_format == fmt) { xconf = &xdpy->configs[i]; break; } } if (!xconf) return FALSE; memset(&xdraw, 0, sizeof(xdraw)); xdraw.visual = xconf->visual->visual; xdraw.depth = xconf->visual->depth; xdraw.drawable = (Drawable) pix; xdpy->base.screen->flush_frontbuffer(xdpy->base.screen, src, 0, 0, &xdraw); return TRUE; } return native_display_copy_to_pixmap(ndpy, pix, src); } static int ximage_display_get_param(struct native_display *ndpy, enum native_param_type param) { int val; switch (param) { case NATIVE_PARAM_USE_NATIVE_BUFFER: /* private buffers are allocated */ val = FALSE; break; case NATIVE_PARAM_PRESERVE_BUFFER: case NATIVE_PARAM_MAX_SWAP_INTERVAL: default: val = 0; break; } return val; } static void ximage_display_destroy(struct native_display *ndpy) { struct ximage_display *xdpy = ximage_display(ndpy); if (xdpy->configs) FREE(xdpy->configs); ndpy_uninit(ndpy); x11_screen_destroy(xdpy->xscr); if (xdpy->own_dpy) XCloseDisplay(xdpy->dpy); FREE(xdpy); } static boolean ximage_display_init_screen(struct native_display *ndpy) { struct ximage_display *xdpy = ximage_display(ndpy); struct sw_winsys *winsys; winsys = xlib_create_sw_winsys(xdpy->dpy); if (!winsys) return FALSE; xdpy->base.screen = xdpy->event_handler->new_sw_screen(&xdpy->base, winsys); if (!xdpy->base.screen) { if (winsys->destroy) winsys->destroy(winsys); return FALSE; } return TRUE; } struct native_display * x11_create_ximage_display(Display *dpy, const struct native_event_handler *event_handler) { struct ximage_display *xdpy; xdpy = CALLOC_STRUCT(ximage_display); if (!xdpy) return NULL; xdpy->dpy = dpy; if (!xdpy->dpy) { xdpy->dpy = XOpenDisplay(NULL); if (!xdpy->dpy) { FREE(xdpy); return NULL; } xdpy->own_dpy = TRUE; } xdpy->event_handler = event_handler; xdpy->xscr_number = DefaultScreen(xdpy->dpy); xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); if (!xdpy->xscr) { if (xdpy->own_dpy) XCloseDisplay(xdpy->dpy); FREE(xdpy); return NULL; } xdpy->base.init_screen = ximage_display_init_screen; xdpy->base.destroy = ximage_display_destroy; xdpy->base.get_param = ximage_display_get_param; xdpy->base.get_configs = ximage_display_get_configs; xdpy->base.get_pixmap_format = ximage_display_get_pixmap_format; xdpy->base.copy_to_pixmap = ximage_display_copy_to_pixmap; xdpy->base.create_window_surface = ximage_display_create_window_surface; xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; return &xdpy->base; }