[Mesa-dev] [PATCH] xlib: implement renderbuffer mapping/unmapping
Brian Paul
brianp at vmware.com
Sat Nov 5 09:53:37 PDT 2011
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.
---
src/mesa/drivers/x11/xm_api.c | 4 +-
src/mesa/drivers/x11/xm_buffer.c | 148 +++++++++++++++++++++++++++++++++++++-
src/mesa/drivers/x11/xm_dd.c | 3 +
src/mesa/drivers/x11/xmesaP.h | 17 ++++-
4 files changed, 167 insertions(+), 5 deletions(-)
diff --git a/src/mesa/drivers/x11/xm_api.c b/src/mesa/drivers/x11/xm_api.c
index 5f04163..13b35c7 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 10829b4..6cf9f06 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 a59ffd3..c896716 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 f248869..29f070a 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
@@ -506,6 +511,16 @@ 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);
--
1.7.3.4
More information about the mesa-dev
mailing list