From: Brian Paul Date: Sat, 5 Nov 2011 16:48:18 +0000 (-0600) Subject: xlib: implement renderbuffer mapping/unmapping X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32c3957991bd0e1df744d866943a8c47b2757c9e;p=mesa.git xlib: implement renderbuffer mapping/unmapping This fixes the glReadPixels() regression for reading from the front/back color buffers. Note, we only allow one mapping of an XImage/Pixmap renderbuffer at any time. That might need to be revisited in the future. --- diff --git a/src/mesa/drivers/x11/xm_api.c b/src/mesa/drivers/x11/xm_api.c index 5f04163fac3..13b35c790c3 100644 --- a/src/mesa/drivers/x11/xm_api.c +++ b/src/mesa/drivers/x11/xm_api.c @@ -361,7 +361,7 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type, /* * Front renderbuffer */ - b->frontxrb = xmesa_new_renderbuffer(NULL, 0, &vis->mesa_visual, GL_FALSE); + b->frontxrb = xmesa_new_renderbuffer(NULL, 0, vis, GL_FALSE); if (!b->frontxrb) { free(b); return NULL; @@ -376,7 +376,7 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type, * Back renderbuffer */ if (vis->mesa_visual.doubleBufferMode) { - b->backxrb = xmesa_new_renderbuffer(NULL, 0, &vis->mesa_visual, GL_TRUE); + b->backxrb = xmesa_new_renderbuffer(NULL, 0, vis, GL_TRUE); if (!b->backxrb) { /* XXX free front xrb too */ free(b); diff --git a/src/mesa/drivers/x11/xm_buffer.c b/src/mesa/drivers/x11/xm_buffer.c index 10829b4284f..6cf9f068f22 100644 --- a/src/mesa/drivers/x11/xm_buffer.c +++ b/src/mesa/drivers/x11/xm_buffer.c @@ -37,6 +37,9 @@ #include "main/renderbuffer.h" +#define XMESA_RENDERBUFFER 0x1234 + + #if defined(USE_XSHM) static volatile int mesaXErrorFlag = 0; @@ -317,8 +320,12 @@ xmesa_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, } +/** + * Used for allocating front/back renderbuffers for an X window. + */ struct xmesa_renderbuffer * -xmesa_new_renderbuffer(struct gl_context *ctx, GLuint name, const struct gl_config *visual, +xmesa_new_renderbuffer(struct gl_context *ctx, GLuint name, + const struct xmesa_visual *xmvis, GLboolean backBuffer) { struct xmesa_renderbuffer *xrb = CALLOC_STRUCT(xmesa_renderbuffer); @@ -333,9 +340,32 @@ xmesa_new_renderbuffer(struct gl_context *ctx, GLuint name, const struct gl_conf xrb->Base.AllocStorage = xmesa_alloc_front_storage; xrb->Base.InternalFormat = GL_RGBA; - xrb->Base.Format = MESA_FORMAT_RGBA8888; xrb->Base._BaseFormat = GL_RGBA; xrb->Base.DataType = GL_UNSIGNED_BYTE; + xrb->Base.ClassID = XMESA_RENDERBUFFER; + + switch (xmvis->undithered_pf) { + case PF_8R8G8B: + /* This will really only happen for pixmaps. We'll access the + * pixmap via a temporary XImage which will be 32bpp. + */ + xrb->Base.Format = MESA_FORMAT_ARGB8888; + break; + case PF_8A8R8G8B: + xrb->Base.Format = MESA_FORMAT_ARGB8888; + break; + case PF_8A8B8G8R: + xrb->Base.Format = MESA_FORMAT_RGBA8888_REV; + break; + case PF_5R6G5B: + xrb->Base.Format = MESA_FORMAT_RGB565; + break; + default: + _mesa_warning(ctx, "Bad pixel format in xmesa_new_renderbuffer"); + xrb->Base.Format = MESA_FORMAT_ARGB8888; + break; + } + /* only need to set Red/Green/EtcBits fields for user-created RBs */ } return xrb; @@ -399,3 +429,117 @@ xmesa_delete_framebuffer(struct gl_framebuffer *fb) _mesa_free_framebuffer_data(fb); free(fb); } + + +/** + * Called via ctx->Driver.MapRenderbuffer() + */ +void +xmesa_MapRenderbuffer(struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **mapOut, GLint *rowStrideOut) +{ + struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); + + if (xrb->Base.ClassID == XMESA_RENDERBUFFER) { + XImage *ximage = xrb->ximage; + + assert(!xrb->map_mode); /* only a single mapping allowed */ + + xrb->map_mode = mode; + xrb->map_x = x; + xrb->map_y = y; + xrb->map_w = w; + xrb->map_h = h; + + if (ximage) { + int y2 = rb->Height - y - 1; + + *mapOut = (GLubyte *) ximage->data + + y2 * ximage->bytes_per_line + + x * ximage->bits_per_pixel / 8; + } + else { + /* this must be a pixmap/window renderbuffer */ + int y2 = rb->Height - y - h; + + assert(xrb->pixmap); + + /* read pixel data out of the pixmap/window into an XImage */ + ximage = XGetImage(xrb->Parent->display, + xrb->pixmap, x, y2, w, h, + AllPlanes, ZPixmap); + if (!ximage) { + *mapOut = NULL; + *rowStrideOut = 0; + return; + } + + xrb->map_ximage = ximage; + + /* the first row of the OpenGL image is last row of the XImage */ + *mapOut = (GLubyte *) ximage->data + + (h - 1) * ximage->bytes_per_line; + } + + /* We return a negative stride here since XImage data is upside down + * with respect to OpenGL images. + */ + *rowStrideOut = -ximage->bytes_per_line; + return; + } + + /* otherwise, this is an ordinary malloc-based renderbuffer */ + _mesa_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode, + mapOut, rowStrideOut); +} + + +/** + * Called via ctx->Driver.UnmapRenderbuffer() + */ +void +xmesa_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) +{ + struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); + + if (xrb->Base.ClassID == XMESA_RENDERBUFFER) { + XImage *ximage = xrb->ximage; + + if (!ximage) { + /* this must be a pixmap/window renderbuffer */ + assert(xrb->pixmap); + assert(xrb->map_ximage); + if (xrb->map_ximage) { + if (xrb->map_mode & GL_MAP_WRITE_BIT) { + /* put modified ximage data back into the pixmap/window */ + int y2 = rb->Height - xrb->map_y - xrb->map_h; + GC gc = XCreateGC(xrb->Parent->display, xrb->pixmap, 0, NULL); + + XPutImage(xrb->Parent->display, + xrb->pixmap, /* dest */ + gc, + xrb->map_ximage, /* source */ + 0, 0, /* src x, y */ + xrb->map_x, y2, /* dest x, y */ + xrb->map_w, xrb->map_h); /* size */ + + XFreeGC(xrb->Parent->display, gc); + } + XMesaDestroyImage(xrb->map_ximage); + xrb->map_ximage = NULL; + } + } + + xrb->map_mode = 0x0; + + return; + } + + /* otherwise, this is an ordinary malloc-based renderbuffer */ + _mesa_unmap_soft_renderbuffer(ctx, rb); +} + + diff --git a/src/mesa/drivers/x11/xm_dd.c b/src/mesa/drivers/x11/xm_dd.c index a59ffd3755a..c896716c0bc 100644 --- a/src/mesa/drivers/x11/xm_dd.c +++ b/src/mesa/drivers/x11/xm_dd.c @@ -1077,6 +1077,9 @@ xmesa_init_driver_functions( XMesaVisual xmvisual, } } + driver->MapRenderbuffer = xmesa_MapRenderbuffer; + driver->UnmapRenderbuffer = xmesa_UnmapRenderbuffer; + #if ENABLE_EXT_texure_compression_s3tc driver->ChooseTextureFormat = choose_tex_format; #else diff --git a/src/mesa/drivers/x11/xmesaP.h b/src/mesa/drivers/x11/xmesaP.h index f2488695e14..29f070aa040 100644 --- a/src/mesa/drivers/x11/xmesaP.h +++ b/src/mesa/drivers/x11/xmesaP.h @@ -186,6 +186,10 @@ struct xmesa_renderbuffer GLint bottom; /* used for FLIP macro, equals height - 1 */ ClearFunc clearFunc; + + GLuint map_x, map_y, map_w, map_h; + GLbitfield map_mode; + XMesaImage *map_ximage; }; @@ -473,7 +477,8 @@ extern const int xmesa_kernel1[16]; */ extern struct xmesa_renderbuffer * -xmesa_new_renderbuffer(struct gl_context *ctx, GLuint name, const struct gl_config *visual, +xmesa_new_renderbuffer(struct gl_context *ctx, GLuint name, + const struct xmesa_visual *xmvis, GLboolean backBuffer); extern void @@ -505,6 +510,16 @@ extern void xmesa_set_renderbuffer_funcs(struct xmesa_renderbuffer *xrb, enum pixel_format pixelformat, GLint depth); +extern void +xmesa_MapRenderbuffer(struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **mapOut, GLint *rowStrideOut); + +extern void +xmesa_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb); + extern void xmesa_destroy_buffers_on_display(XMesaDisplay *dpy);