#include "fbobject.h"
#include "renderbuffer.h"
+#include "rbadaptors.h"
+
/* 32-bit color index format. Not a public format. */
#define COLOR_INDEX32 0x424243
get_row_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
GLint x, GLint y, void *values)
{
- const GLbyte *src = (const GLbyte *) rb->Data + 4 * (y * rb->Width + x);
+ const GLubyte *src = (const GLubyte *) rb->Data + 4 * (y * rb->Width + x);
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
ASSERT(rb->_ActualFormat == GL_RGBA8);
- _mesa_memcpy(values, src, 4 * count * sizeof(GLbyte));
+ _mesa_memcpy(values, src, 4 * count * sizeof(GLubyte));
}
ASSERT(rb->PutMonoValues);
/* free old buffer storage */
- if (rb->Data)
+ if (rb->Data) {
_mesa_free(rb->Data);
-
- /* allocate new buffer storage */
- rb->Data = _mesa_malloc(width * height * pixelSize);
- if (rb->Data == NULL) {
- rb->Width = 0;
- rb->Height = 0;
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "software renderbuffer allocation (%d x %d x %d)",
- width, height, pixelSize);
- return GL_FALSE;
+ rb->Data = NULL;
+ }
+
+ if (width > 0 && height > 0) {
+ /* allocate new buffer storage */
+ rb->Data = _mesa_malloc(width * height * pixelSize);
+ if (rb->Data == NULL) {
+ rb->Width = 0;
+ rb->Height = 0;
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "software renderbuffer allocation (%d x %d x %d)",
+ width, height, pixelSize);
+ return GL_FALSE;
+ }
}
rb->Width = width;
}
+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));
+}
+
/**********************************************************************/
/**********************************************************************/
rb->ClassID = 0;
rb->Name = name;
- rb->RefCount = 1;
+ rb->RefCount = 0;
rb->Delete = _mesa_delete_renderbuffer;
/* The rest of these should be set later by the caller of this function or
/**
* Delete a gl_framebuffer.
- * This is the default function for framebuffer->Delete().
+ * This is the default function for renderbuffer->Delete().
*/
void
_mesa_delete_renderbuffer(struct gl_renderbuffer *rb)
if (rb->Data) {
_mesa_free(rb->Data);
}
- _glthread_INIT_MUTEX(rb->Mutex);
_mesa_free(rb);
}
}
+/**
+ * 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
assert(!rb->Name);
}
+ /* If Mesa's compiled with deep color channels (16 or 32 bits / channel)
+ * and the device driver is expecting 8-bit values (GLubyte), we can
+ * use a "renderbuffer adaptor/wrapper" to do the necessary conversions.
+ */
+ if (rb->_BaseFormat == GL_RGBA) {
+ if (CHAN_BITS == 16 && rb->DataType == GL_UNSIGNED_BYTE) {
+ GET_CURRENT_CONTEXT(ctx);
+ rb = _mesa_new_renderbuffer_16wrap8(ctx, rb);
+ }
+ else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_BYTE) {
+ GET_CURRENT_CONTEXT(ctx);
+ rb = _mesa_new_renderbuffer_32wrap8(ctx, rb);
+ }
+ else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_SHORT) {
+ GET_CURRENT_CONTEXT(ctx);
+ rb = _mesa_new_renderbuffer_32wrap16(ctx, rb);
+ }
+ }
+
fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT;
fb->Attachment[bufferName].Complete = GL_TRUE;
- fb->Attachment[bufferName].Renderbuffer = rb;
+ _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb);
+}
+
+
+/**
+ * Remove the named renderbuffer from the given framebuffer.
+ */
+void
+_mesa_remove_renderbuffer(struct gl_framebuffer *fb, GLuint bufferName)
+{
+ struct gl_renderbuffer *rb;
+
+ assert(bufferName < BUFFER_COUNT);
+
+ rb = fb->Attachment[bufferName].Renderbuffer;
+ if (!rb)
+ return;
+
+ _mesa_reference_renderbuffer(&rb, NULL);
+
+ fb->Attachment[bufferName].Renderbuffer = NULL;
+}
+
+
+/**
+ * Set *ptr to point to rb. If *ptr points to another renderbuffer,
+ * dereference that buffer first. The new renderbuffer's refcount will
+ * be incremented. The old renderbuffer's refcount will be decremented.
+ */
+void
+_mesa_reference_renderbuffer(struct gl_renderbuffer **ptr,
+ struct gl_renderbuffer *rb)
+{
+ assert(ptr);
+ if (*ptr == rb) {
+ /* no change */
+ return;
+ }
+
+ if (*ptr) {
+ /* Unreference the old renderbuffer */
+ GLboolean deleteFlag = GL_FALSE;
+ struct gl_renderbuffer *oldRb = *ptr;
+
+ _glthread_LOCK_MUTEX(oldRb->Mutex);
+ ASSERT(oldRb->RefCount > 0);
+ oldRb->RefCount--;
+ /*printf("RB DECR %p to %d\n", (void*) oldRb, oldRb->RefCount);*/
+ deleteFlag = (oldRb->RefCount == 0);
+ _glthread_UNLOCK_MUTEX(oldRb->Mutex);
+
+ if (deleteFlag)
+ oldRb->Delete(oldRb);
+
+ *ptr = NULL;
+ }
+ assert(!*ptr);
+
+ if (rb) {
+ /* reference new renderbuffer */
+ _glthread_LOCK_MUTEX(rb->Mutex);
+ rb->RefCount++;
+ /*printf("RB REF %p to %d\n", (void*)rb, rb->RefCount);*/
+ _glthread_UNLOCK_MUTEX(rb->Mutex);
+ *ptr = rb;
+ }
}
return dsrb;
}
-