From eb75ec23497a1ce9d911fca785fd71ee92782a9e Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Mon, 20 Mar 2006 15:39:30 +0000 Subject: [PATCH] merge from trunk (additional renderbuffer error checks, debug code) --- src/mesa/main/buffers.c | 4 +- src/mesa/main/drawpix.c | 74 ++++++++-------------- src/mesa/main/fbobject.c | 32 +++++++++- src/mesa/main/framebuffer.c | 123 +++++++++++++++++++++++++++++++++++- src/mesa/main/framebuffer.h | 9 ++- 5 files changed, 189 insertions(+), 53 deletions(-) diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c index 89e92036c86..121050593f6 100644 --- a/src/mesa/main/buffers.c +++ b/src/mesa/main/buffers.c @@ -547,12 +547,12 @@ _mesa_ReadBuffer(GLenum buffer) /* general case / window-system framebuffer */ srcBuffer = read_buffer_enum_to_index(buffer); if (srcBuffer == -1) { - _mesa_error(ctx, GL_INVALID_ENUM, "glReadBuffer(buffer)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glReadBuffer(buffer=0x%x)", buffer); return; } supportedMask = supported_buffer_bitmask(ctx, bufferID); if (((1 << srcBuffer) & supportedMask) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glReadBuffer(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glReadBuffer(buffer=0x%x)", buffer); return; } } diff --git a/src/mesa/main/drawpix.c b/src/mesa/main/drawpix.c index 6d855b58006..5c4f4545ea9 100644 --- a/src/mesa/main/drawpix.c +++ b/src/mesa/main/drawpix.c @@ -27,6 +27,7 @@ #include "context.h" #include "drawpix.h" #include "feedback.h" +#include "framebuffer.h" #include "image.h" #include "state.h" @@ -43,7 +44,6 @@ error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, GLboolean drawing) { const char *readDraw = drawing ? "Draw" : "Read"; - struct gl_framebuffer *fb = drawing ? ctx->DrawBuffer : ctx->ReadBuffer; if (ctx->Extensions.EXT_packed_depth_stencil && type == GL_UNSIGNED_INT_24_8_EXT @@ -78,23 +78,35 @@ error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, "glDrawPixels(drawing RGB pixels into color index buffer)"); return GL_TRUE; } + if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); + return GL_TRUE; + } break; case GL_COLOR_INDEX: if (!drawing && ctx->Visual.rgbMode) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(reading color index format from RGB buffer"); + "glReadPixels(reading color index format from RGB buffer)"); + return GL_TRUE; + } + if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); return GL_TRUE; } break; case GL_STENCIL_INDEX: - if (fb->Visual.stencilBits == 0) { + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (!drawing && !_mesa_source_buffer_exists(ctx, format))) { _mesa_error(ctx, GL_INVALID_OPERATION, "gl%sPixels(no stencil buffer)", readDraw); return GL_TRUE; } break; case GL_DEPTH_COMPONENT: - if (fb->Visual.depthBits == 0) { + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (!drawing && !_mesa_source_buffer_exists(ctx, format))) { _mesa_error(ctx, GL_INVALID_OPERATION, "gl%sPixels(no depth buffer)", readDraw); return GL_TRUE; @@ -106,13 +118,12 @@ error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); return GL_TRUE; } - if (fb->Visual.depthBits == 0 || fb->Visual.stencilBits == 0) { + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (!drawing && !_mesa_source_buffer_exists(ctx, format))) { _mesa_error(ctx, GL_INVALID_OPERATION, "gl%sPixels(no depth or stencil buffer)", readDraw); return GL_TRUE; } - ASSERT(fb->Attachment[BUFFER_DEPTH].Renderbuffer); - ASSERT(fb->Attachment[BUFFER_STENCIL].Renderbuffer); break; default: /* this should have been caught in _mesa_is_legal_format_type() */ @@ -214,45 +225,6 @@ _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, return; } - switch (type) { - case GL_COLOR: - /* OK */ - break; - case GL_DEPTH: - if (ctx->DrawBuffer->Visual.depthBits == 0 || - ctx->ReadBuffer->Visual.depthBits == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyPixels(no depth buffer)"); - return; - } - break; - case GL_STENCIL: - if (ctx->DrawBuffer->Visual.stencilBits == 0 || - ctx->ReadBuffer->Visual.stencilBits == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyPixels(no stencil buffer)"); - return; - } - break; - case GL_DEPTH_STENCIL_EXT: - if (!ctx->Extensions.EXT_packed_depth_stencil) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); - return; - } - if (ctx->DrawBuffer->Visual.depthBits == 0 || - ctx->ReadBuffer->Visual.depthBits == 0 || - ctx->DrawBuffer->Visual.stencilBits == 0 || - ctx->ReadBuffer->Visual.stencilBits == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyPixels(no depth or stencil buffer)"); - return; - } - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); - return; - } - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, @@ -260,6 +232,13 @@ _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, return; } + if (!_mesa_source_buffer_exists(ctx, type) || + !_mesa_dest_buffer_exists(ctx, type)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyPixels(missing source or dest buffer)"); + return; + } + if (!ctx->Current.RasterPosValid) { return; } @@ -295,7 +274,6 @@ _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) { GET_CURRENT_CONTEXT(ctx); - const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (width < 0 || height < 0) { @@ -318,7 +296,7 @@ _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, return; } - if (!rb) { + if (!_mesa_source_buffer_exists(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); return; } diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 8c428f8a259..a83ed56069d 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -317,18 +317,25 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } } else if (att->Type == GL_RENDERBUFFER_EXT) { - if (att->Renderbuffer->Width < 1 || att->Renderbuffer->Height < 1) { + ASSERT(att->Renderbuffer); + if (!att->Renderbuffer->InternalFormat || + att->Renderbuffer->Width < 1 || + att->Renderbuffer->Height < 1) { att->Complete = GL_FALSE; return; } if (format == GL_COLOR) { if (att->Renderbuffer->_BaseFormat != GL_RGB && att->Renderbuffer->_BaseFormat != GL_RGBA) { + ASSERT(att->Renderbuffer->RedBits); + ASSERT(att->Renderbuffer->GreenBits); + ASSERT(att->Renderbuffer->BlueBits); att->Complete = GL_FALSE; return; } } else if (format == GL_DEPTH) { + ASSERT(att->Renderbuffer->DepthBits); if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { /* OK */ } @@ -343,6 +350,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } else { assert(format == GL_STENCIL); + ASSERT(att->Renderbuffer->StencilBits); if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { /* OK */ } @@ -364,6 +372,18 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } +/** + * Helpful for debugging + */ +static void +fbo_incomplete(const char *msg, int index) +{ + /* + _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); + */ +} + + /** * Test if the given framebuffer object is complete and update its * Status field with the results. @@ -394,6 +414,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_DEPTH, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("depth attachment incomplete", -1); return; } } @@ -402,6 +423,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_STENCIL, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("stencil attachment incomplete", -1); return; } } @@ -410,6 +432,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_COLOR, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("color attachment incomplete", i); return; } } @@ -424,6 +447,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT) { /* XXX need GL_DEPTH_STENCIL_EXT test? */ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("texture attachment incomplete", -1); return; } } @@ -449,10 +473,12 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) /* check that width, height, format are same */ if (w != width || h != height) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + fbo_incomplete("width or height mismatch", -1); return; } if (intFormat != GL_NONE && f != intFormat) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("format mismatch", -1); return; } } @@ -466,6 +492,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; + fbo_incomplete("missing drawbuffer", i); return; } } @@ -478,6 +505,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; + fbo_incomplete("missing readbuffer", -1); return; } } @@ -494,6 +522,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) struct gl_renderbuffer *rb_j = fb->Attachment[j].Renderbuffer; if (rb_i == rb_j && rb_i->_BaseFormat != GL_DEPTH_STENCIL_EXT) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT; + fbo_incomplete("multiply bound renderbuffer", -1); return; } } @@ -503,6 +532,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) if (numImages == 0) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; + fbo_incomplete("no attachments", -1); return; } diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c index 17241cfcef5..26e72da3f7c 100644 --- a/src/mesa/main/framebuffer.c +++ b/src/mesa/main/framebuffer.c @@ -2,7 +2,7 @@ * Mesa 3-D graphics library * Version: 6.5 * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -550,3 +550,124 @@ _mesa_update_framebuffer(GLcontext *ctx) compute_depth_max(fb); } + + +/** + * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, + * glCopyTex[Sub]Image, etc. exists. + * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, + * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. + * \return GL_TRUE if buffer exists, GL_FALSE otherwise + */ +GLboolean +_mesa_source_buffer_exists(GLcontext *ctx, GLenum format) +{ + const struct gl_renderbuffer_attachment *att + = ctx->ReadBuffer->Attachment; + + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return GL_FALSE; + } + + switch (format) { + case GL_COLOR: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGB: + case GL_RGBA: + case GL_COLOR_INDEX: + if (ctx->ReadBuffer->_ColorReadBuffer == NULL) { + return GL_FALSE; + } + break; + case GL_DEPTH: + case GL_DEPTH_COMPONENT: + if (!att[BUFFER_DEPTH].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + break; + case GL_STENCIL: + case GL_STENCIL_INDEX: + if (!att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + case GL_DEPTH_STENCIL_EXT: + if (!att[BUFFER_DEPTH].Renderbuffer || + !att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + default: + _mesa_problem(ctx, + "Unexpected format 0x%x in _mesa_source_buffer_exists"); + return GL_FALSE; + } + + /* OK */ + return GL_TRUE; +} + + +/** + * As above, but for drawing operations. + * XXX code do some code merging w/ above function. + */ +GLboolean +_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) +{ + const struct gl_renderbuffer_attachment *att + = ctx->ReadBuffer->Attachment; + + if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return GL_FALSE; + } + + switch (format) { + case GL_COLOR: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGB: + case GL_RGBA: + case GL_COLOR_INDEX: + /* nothing special */ + break; + case GL_DEPTH: + case GL_DEPTH_COMPONENT: + if (!att[BUFFER_DEPTH].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + break; + case GL_STENCIL: + case GL_STENCIL_INDEX: + if (!att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + case GL_DEPTH_STENCIL_EXT: + if (!att[BUFFER_DEPTH].Renderbuffer || + !att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + default: + _mesa_problem(ctx, + "Unexpected format 0x%x in _mesa_source_buffer_exists"); + return GL_FALSE; + } + + /* OK */ + return GL_TRUE; +} diff --git a/src/mesa/main/framebuffer.h b/src/mesa/main/framebuffer.h index fcc493c1937..51847b07c0f 100644 --- a/src/mesa/main/framebuffer.h +++ b/src/mesa/main/framebuffer.h @@ -2,7 +2,7 @@ * Mesa 3-D graphics library * Version: 6.5 * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -55,4 +55,11 @@ _mesa_update_framebuffer_visual(struct gl_framebuffer *fb); extern void _mesa_update_framebuffer(GLcontext *ctx); +extern GLboolean +_mesa_source_buffer_exists(GLcontext *ctx, GLenum format); + +extern GLboolean +_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format); + + #endif /* FRAMEBUFFER_H */