summaryrefslogtreecommitdiff
path: root/src/mesa/main/fbobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/fbobject.c')
-rw-r--r--src/mesa/main/fbobject.c346
1 files changed, 177 insertions, 169 deletions
diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
index 53c4d27e81a..ec690bdbf7f 100644
--- a/src/mesa/main/fbobject.c
+++ b/src/mesa/main/fbobject.c
@@ -36,6 +36,7 @@
#include "renderbuffer.h"
#include "state.h"
#include "teximage.h"
+#include "texobj.h"
#include "texstore.h"
@@ -66,8 +67,8 @@ static struct gl_renderbuffer DummyRenderbuffer;
/**
* Helper routine for getting a gl_renderbuffer.
*/
-static struct gl_renderbuffer *
-lookup_renderbuffer(GLcontext *ctx, GLuint id)
+struct gl_renderbuffer *
+_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
{
struct gl_renderbuffer *rb;
@@ -83,8 +84,8 @@ lookup_renderbuffer(GLcontext *ctx, GLuint id)
/**
* Helper routine for getting a gl_framebuffer.
*/
-static struct gl_framebuffer *
-lookup_framebuffer(GLcontext *ctx, GLuint id)
+struct gl_framebuffer *
+_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
{
struct gl_framebuffer *fb;
@@ -209,7 +210,7 @@ _mesa_set_texture_attachment(GLcontext *ctx,
att->Complete = GL_FALSE;
if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
- ctx->Driver.RenderbufferTexture(ctx, fb, att);
+ ctx->Driver.RenderTexture(ctx, fb, att);
}
}
@@ -223,6 +224,7 @@ _mesa_set_renderbuffer_attachment(GLcontext *ctx,
struct gl_renderbuffer_attachment *att,
struct gl_renderbuffer *rb)
{
+ /* XXX check if re-doing same attachment, exit early */
_mesa_remove_attachment(ctx, att);
att->Type = GL_RENDERBUFFER_EXT;
att->Renderbuffer = rb;
@@ -242,6 +244,10 @@ _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
{
struct gl_renderbuffer_attachment *att;
+ _glthread_LOCK_MUTEX(fb->Mutex);
+ if (rb)
+ _glthread_LOCK_MUTEX(rb->Mutex);
+
att = _mesa_get_attachment(ctx, fb, attachment);
ASSERT(att);
@@ -251,6 +257,10 @@ _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
else {
_mesa_remove_attachment(ctx, att);
}
+
+ if (rb)
+ _glthread_UNLOCK_MUTEX(rb->Mutex);
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
}
@@ -554,7 +564,7 @@ _mesa_IsRenderbufferEXT(GLuint renderbuffer)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
if (renderbuffer) {
- struct gl_renderbuffer *rb = lookup_renderbuffer(ctx, renderbuffer);
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
if (rb != NULL && rb != &DummyRenderbuffer)
return GL_TRUE;
}
@@ -579,7 +589,7 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
if (renderbuffer) {
- newRb = lookup_renderbuffer(ctx, renderbuffer);
+ newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
if (newRb == &DummyRenderbuffer) {
/* ID was reserved, but no real renderbuffer object made yet */
newRb = NULL;
@@ -626,7 +636,7 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
for (i = 0; i < n; i++) {
if (renderbuffers[i] > 0) {
struct gl_renderbuffer *rb;
- rb = lookup_renderbuffer(ctx, renderbuffers[i]);
+ rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
if (rb) {
/* check if deleting currently bound renderbuffer object */
if (rb == ctx->CurrentRenderbuffer) {
@@ -786,15 +796,26 @@ _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
return;
}
+ /* These MUST get set by the AllocStorage func */
+ rb->_ActualFormat = 0;
+ rb->RedBits =
+ rb->GreenBits =
+ rb->BlueBits =
+ rb->AlphaBits =
+ rb->IndexBits =
+ rb->DepthBits =
+ rb->StencilBits = 0;
+
/* Now allocate the storage */
ASSERT(rb->AllocStorage);
if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
/* No error - check/set fields now */
+ assert(rb->_ActualFormat);
assert(rb->Width == width);
assert(rb->Height == height);
- assert(rb->InternalFormat);
assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
rb->DepthBits || rb->StencilBits || rb->IndexBits);
+ rb->InternalFormat = internalFormat;
rb->_BaseFormat = baseFormat;
}
else {
@@ -802,6 +823,7 @@ _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
rb->Width = 0;
rb->Height = 0;
rb->InternalFormat = GL_NONE;
+ rb->_ActualFormat = GL_NONE;
rb->_BaseFormat = GL_NONE;
rb->RedBits =
rb->GreenBits =
@@ -884,7 +906,7 @@ _mesa_IsFramebufferEXT(GLuint framebuffer)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
if (framebuffer) {
- struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer);
+ struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
if (rb != NULL && rb != &DummyFramebuffer)
return GL_TRUE;
}
@@ -892,13 +914,28 @@ _mesa_IsFramebufferEXT(GLuint framebuffer)
}
+static void
+check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
+{
+ GLuint i;
+ ASSERT(ctx->Driver.RenderTexture);
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ struct gl_renderbuffer_attachment *att = fb->Attachment + i;
+ struct gl_texture_object *texObj = att->Texture;
+ if (texObj) {
+ ctx->Driver.RenderTexture(ctx, fb, att);
+ }
+ }
+}
+
+
/**
* Examine all the framebuffer's attachments to see if any are textures.
* If so, call ctx->Driver.FinishRenderTexture() for each texture to
* notify the device driver that the texture image may have changed.
*/
static void
-check_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
+check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
{
if (ctx->Driver.FinishRenderTexture) {
GLuint i;
@@ -922,6 +959,12 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (!ctx->Extensions.EXT_framebuffer_object) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindFramebufferEXT(unsupported)");
+ return;
+ }
+
switch (target) {
#if FEATURE_EXT_framebuffer_blit
case GL_DRAW_FRAMEBUFFER_EXT:
@@ -954,7 +997,7 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
if (framebuffer) {
/* Binding a user-created framebuffer object */
- newFb = lookup_framebuffer(ctx, framebuffer);
+ newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
if (newFb == &DummyFramebuffer) {
/* ID was reserved, but no real framebuffer object made yet */
newFb = NULL;
@@ -968,10 +1011,12 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
}
_mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
}
+ _glthread_LOCK_MUTEX(newFb->Mutex);
if (bindReadBuf)
newFb->RefCount++;
if (bindDrawBuf)
newFb->RefCount++;
+ _glthread_UNLOCK_MUTEX(newFb->Mutex);
}
else {
/* Binding the window system framebuffer (which was originally set
@@ -980,12 +1025,19 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
newFb = ctx->WinSysDrawBuffer;
}
+ ASSERT(newFb);
ASSERT(newFb != &DummyFramebuffer);
+ /*
+ * XXX check if re-binding same buffer and skip some of this code.
+ */
+
if (bindReadBuf) {
oldFb = ctx->ReadBuffer;
if (oldFb && oldFb->Name != 0) {
+ _glthread_LOCK_MUTEX(oldFb->Mutex);
oldFb->RefCount--;
+ _glthread_UNLOCK_MUTEX(oldFb->Mutex);
if (oldFb->RefCount == 0) {
oldFb->Delete(oldFb);
}
@@ -997,16 +1049,20 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
oldFb = ctx->DrawBuffer;
if (oldFb && oldFb->Name != 0) {
/* check if old FB had any texture attachments */
- if (ctx->Driver.FinishRenderTexture) {
- check_texture_render(ctx, oldFb);
- }
+ check_end_texture_render(ctx, oldFb);
/* check if time to delete this framebuffer */
+ _glthread_LOCK_MUTEX(oldFb->Mutex);
oldFb->RefCount--;
if (oldFb->RefCount == 0) {
oldFb->Delete(oldFb);
}
+ _glthread_UNLOCK_MUTEX(oldFb->Mutex);
}
ctx->DrawBuffer = newFb;
+ if (newFb->Name != 0) {
+ /* check if newly bound framebuffer has any texture attachments */
+ check_begin_texture_render(ctx, newFb);
+ }
}
if (ctx->Driver.BindFramebuffer) {
@@ -1027,7 +1083,7 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
for (i = 0; i < n; i++) {
if (framebuffers[i] > 0) {
struct gl_framebuffer *fb;
- fb = lookup_framebuffer(ctx, framebuffers[i]);
+ fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
if (fb) {
ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
@@ -1045,7 +1101,9 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
/* But the object will not be freed until it's no longer
* bound in any context.
*/
+ _glthread_LOCK_MUTEX(fb->Mutex);
fb->RefCount--;
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
if (fb->RefCount == 0) {
fb->Delete(fb);
}
@@ -1134,152 +1192,144 @@ _mesa_CheckFramebufferStatusEXT(GLenum target)
/**
- * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
- * \return GL_TRUE if any error, GL_FALSE otherwise
+ * Common code called by glFramebufferTexture1D/2D/3DEXT().
*/
-static GLboolean
-error_check_framebuffer_texture(GLcontext *ctx, GLuint dims,
- GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture, GLint level)
+static void
+framebuffer_texture(GLuint dims, GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level, GLint zoffset)
{
- ASSERT(dims >= 1 && dims <= 3);
+ struct gl_renderbuffer_attachment *att;
+ struct gl_texture_object *texObj = NULL;
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_FRAMEBUFFER_EXT) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glFramebufferTexture%dDEXT(target)", dims);
- return GL_TRUE;
+ return;
}
+ fb = ctx->DrawBuffer;
+ ASSERT(fb);
+
/* check framebuffer binding */
- if (ctx->DrawBuffer->Name == 0) {
+ if (fb->Name == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glFramebufferTexture%dDEXT", dims);
- return GL_TRUE;
+ return;
}
- /* only check textarget, level if texture ID is non-zero */
if (texture) {
- if ((dims == 1 && textarget != GL_TEXTURE_1D) ||
- (dims == 3 && textarget != GL_TEXTURE_3D) ||
- (dims == 2 && textarget != GL_TEXTURE_2D &&
- textarget != GL_TEXTURE_RECTANGLE_ARB &&
- !IS_CUBE_FACE(textarget))) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%dDEXT(textarget)", dims);
- return GL_TRUE;
- }
+ texObj = _mesa_lookup_texture(ctx, texture);
+ }
- if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%dDEXT(level)", dims);
- return GL_TRUE;
+ /* Check dimension-dependent things */
+ switch (dims) {
+ case 1:
+ if (textarget != GL_TEXTURE_1D) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture1DEXT(textarget)");
+ return;
}
+ if (texObj && texObj->Target != GL_TEXTURE_1D) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture1DEXT(texture target mismatch)");
+ return;
+ }
+ break;
+ case 2:
+ if (textarget != GL_TEXTURE_2D &&
+ textarget != GL_TEXTURE_RECTANGLE_ARB &&
+ !IS_CUBE_FACE(textarget)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture2DEXT(textarget)");
+ return;
+ }
+ if (texObj) {
+ if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
+ (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
+ && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
+ (texObj->Target == GL_TEXTURE_CUBE_MAP
+ && !IS_CUBE_FACE(textarget))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture1DEXT(texture target mismatch)");
+ return;
+ }
+ }
+ break;
+ case 3:
+ if (textarget != GL_TEXTURE_3D) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture3DEXT(textarget)");
+ return;
+ }
+ if (texObj && texObj->Target != GL_TEXTURE_3D) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture3DEXT(texture target mismatch)");
+ return;
+ }
+ {
+ const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
+ if (zoffset < 0 || zoffset >= maxSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture3DEXT(zoffset)");
+ return;
+ }
+ }
+ break;
+ default:
+ _mesa_problem(ctx, "Unexpected dims in error_check_framebuffer_texture");
+ return;
}
- return GL_FALSE;
-}
-
-
-/**
- * XXX The code in _mesa_FramebufferTexture1/2/3DEXT could be probably
- * be combined into one function.
- */
-void GLAPIENTRY
-_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture, GLint level)
-{
- struct gl_renderbuffer_attachment *att;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (error_check_framebuffer_texture(ctx, 1, target, attachment,
- textarget, texture, level))
+ if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%dDEXT(level)", dims);
return;
+ }
- ASSERT(textarget == GL_TEXTURE_1D);
-
- /* XXX read blit */
- att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
+ att = _mesa_get_attachment(ctx, fb, attachment);
if (att == NULL) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture1DEXT(attachment)");
+ "glFramebufferTexture%dDEXT(attachment)", dims);
return;
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
- if (texture) {
- struct gl_texture_object *texObj = (struct gl_texture_object *)
- _mesa_HashLookup(ctx->Shared->TexObjects, texture);
- if (!texObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture1DEXT(texture)");
- return;
- }
- if (texObj->Target != textarget) {
- _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
- "glFramebufferTexture1DEXT(texture target)");
- return;
- }
- _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att,
- texObj, textarget, level, 0);
+ _glthread_LOCK_MUTEX(fb->Mutex);
+ if (texObj) {
+ _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
+ level, zoffset);
}
else {
_mesa_remove_attachment(ctx, att);
}
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
}
+
void GLAPIENTRY
-_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
+_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- struct gl_renderbuffer_attachment *att;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (error_check_framebuffer_texture(ctx, 2, target, attachment,
- textarget, texture, level))
- return;
+ const GLint zoffset = 0;
+ framebuffer_texture(1, target, attachment, textarget, texture,
+ level, zoffset);
+}
- ASSERT(textarget == GL_TEXTURE_2D ||
- textarget == GL_TEXTURE_RECTANGLE_ARB ||
- IS_CUBE_FACE(textarget));
- att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
- if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture2DEXT(attachment)");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- if (texture) {
- struct gl_texture_object *texObj = (struct gl_texture_object *)
- _mesa_HashLookup(ctx->Shared->TexObjects, texture);
- if (!texObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture2DEXT(texture)");
- return;
- }
- if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
- (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
- && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
- (texObj->Target == GL_TEXTURE_CUBE_MAP
- && !IS_CUBE_FACE(textarget))) {
- _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
- "glFramebufferTexture2DEXT(texture target)");
- return;
- }
- _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att,
- texObj, textarget, level, 0);
- }
- else {
- _mesa_remove_attachment(ctx, att);
- }
+void GLAPIENTRY
+_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ const GLint zoffset = 0;
+ framebuffer_texture(2, target, attachment, textarget, texture,
+ level, zoffset);
}
@@ -1288,54 +1338,12 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture,
GLint level, GLint zoffset)
{
- struct gl_renderbuffer_attachment *att;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (error_check_framebuffer_texture(ctx, 3, target, attachment,
- textarget, texture, level))
- return;
-
- ASSERT(textarget == GL_TEXTURE_3D);
-
- att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
- if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture1DEXT(attachment)");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- if (texture) {
- const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
- struct gl_texture_object *texObj = (struct gl_texture_object *)
- _mesa_HashLookup(ctx->Shared->TexObjects, texture);
- if (!texObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture3DEXT(texture)");
- return;
- }
- if (texObj->Target != textarget) {
- _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
- "glFramebufferTexture3DEXT(texture target)");
- return;
- }
- if (zoffset < 0 || zoffset >= maxSize) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture3DEXT(zoffset)");
- return;
- }
- _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att,
- texObj, textarget, level,zoffset);
- }
- else {
- _mesa_remove_attachment(ctx, att);
- }
+ framebuffer_texture(3, target, attachment, textarget, texture,
+ level, zoffset);
}
+
void GLAPIENTRY
_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
GLenum renderbufferTarget,
@@ -1396,7 +1404,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
}
if (renderbuffer) {
- rb = lookup_renderbuffer(ctx, renderbuffer);
+ rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
if (!rb) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glFramebufferRenderbufferEXT(renderbuffer)");