Implement alpha buffer copy for SwapBuffers().
authorBrian <brian@yutani.localnet.net>
Sat, 24 Mar 2007 00:01:31 +0000 (18:01 -0600)
committerBrian <brian@yutani.localnet.net>
Sat, 24 Mar 2007 00:01:31 +0000 (18:01 -0600)
Nicolai writes:
When the pixmap pixel format has no alpha channel, the x11 driver
(software rendering) adds a wrapped alpha channel on request.

During SwapBuffers, this alpha channel is not copied from back to
front, which means that the front buffer doesn't really contain the
contents that the back buffer previously contained.

A subsequent glReadPixels from the front buffer will return an
incorrect result. The following patch attempts to fix this.

src/mesa/drivers/x11/xm_api.c
src/mesa/drivers/x11/xmesaP.h
src/mesa/main/renderbuffer.c
src/mesa/main/renderbuffer.h

index b513dc8d40aca49162e49ef4dc947a61fac619b1..24b19d8eb5ab819355b1a17eb1c7f75d5c9ad154 100644 (file)
@@ -363,7 +363,6 @@ static XMesaBuffer
 create_xmesa_buffer(XMesaDrawable d, BufferType type,
                     XMesaVisual vis, XMesaColormap cmap)
 {
-   GLboolean swAlpha;
    XMesaBuffer b;
 
    ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER);
@@ -421,10 +420,10 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type,
       /* Visual has alpha, but pixel format doesn't support it.
        * We'll use an alpha renderbuffer wrapper.
        */
-      swAlpha = GL_TRUE;
+      b->swAlpha = GL_TRUE;
    }
    else {
-      swAlpha = GL_FALSE;
+      b->swAlpha = GL_FALSE;
    }
 
    /*
@@ -435,9 +434,9 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type,
                                 vis->mesa_visual.haveDepthBuffer,
                                 vis->mesa_visual.haveStencilBuffer,
                                 vis->mesa_visual.haveAccumBuffer,
-                                swAlpha,
+                                b->swAlpha,
                                 vis->mesa_visual.numAuxBuffers > 0 );
-   
+
    /* insert buffer into linked list */
    b->Next = XMesaBufferList;
    XMesaBufferList = b;
@@ -2211,6 +2210,9 @@ void XMesaSwapBuffers( XMesaBuffer b )
                      );
          /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
       }
+
+      if (b->swAlpha)
+         _mesa_copy_soft_alpha_renderbuffers(ctx, &b->mesa_buffer);
    }
 #if !defined(XFree86Server)
    XSync( b->xm_visual->display, False );
index 5516031ffe7f0a61f3825cade8fec1f50ba68007..85cb6b66363388c2c45301a8fcc610dc413f225b 100644 (file)
@@ -224,6 +224,7 @@ struct xmesa_buffer {
    GLint db_mode;              /* 0 = single buffered */
                                /* BACK_PIXMAP = use Pixmap for back buffer */
                                /* BACK_XIMAGE = use XImage for back buffer */
+   GLboolean swAlpha;
 
    GLuint shm;                 /* X Shared Memory extension status:    */
                                /*    0 = not available                 */
index e387c42c345c0cd30e84fb9f33707aa7133789c8..ded0063c73909b141b6d57d0487d4cec23fed122 100644 (file)
@@ -1435,6 +1435,17 @@ put_mono_values_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb,
 }
 
 
+static void
+copy_buffer_alpha8(struct gl_renderbuffer* dst, struct gl_renderbuffer* src)
+{
+   ASSERT(dst->_ActualFormat == GL_ALPHA8);
+   ASSERT(src->_ActualFormat == GL_ALPHA8);
+   ASSERT(dst->Width == src->Width);
+   ASSERT(dst->Height == src->Height);
+
+   _mesa_memcpy(dst->Data, src->Data, dst->Width * dst->Height * sizeof(GLubyte));
+}
+
 
 /**********************************************************************/
 /**********************************************************************/
@@ -1765,6 +1776,27 @@ _mesa_add_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb,
 }
 
 
+/**
+ * For framebuffers that use a software alpha channel wrapper
+ * created by _mesa_add_alpha_renderbuffer or _mesa_add_soft_renderbuffers,
+ * copy the back buffer alpha channel into the front buffer alpha channel.
+ */
+void
+_mesa_copy_soft_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb)
+{
+   if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer &&
+       fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer)
+      copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer,
+                         fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
+
+
+   if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer &&
+       fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer)
+      copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer,
+                         fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
+}
+
+
 /**
  * Add a software-based depth renderbuffer to the given framebuffer.
  * This is a helper routine for device drivers when creating a
index e1a0a5597927e612ecc2a9bf3fe8bd0e3ae9339d..e5f1147b4a6de9195680d963c3f6cdaf4c5d2851 100644 (file)
@@ -64,6 +64,9 @@ _mesa_add_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb,
                               GLboolean frontLeft, GLboolean backLeft,
                               GLboolean frontRight, GLboolean backRight);
 
+extern void
+_mesa_copy_soft_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb);
+
 extern GLboolean
 _mesa_add_depth_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
                              GLuint depthBits);