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.
This commit is contained in:
Brian Paul
2011-11-05 10:48:18 -06:00
parent 68c3d21b68
commit 32c3957991
4 changed files with 167 additions and 5 deletions

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);