X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=aefcaf35097e51ae4c17cba01fe75836abb2031a;hb=8fe6755ed52acfb88a7a787c3406b64fcdd80e6e;hp=97cbd3c614d8feb253ddab1da82db9c3e52b8fa5;hpb=88ffa9ce5b8e5fe2b93238f8b9a7a888be28324e;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 97cbd3c614d..aefcaf35097 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -39,6 +39,7 @@ #include "formats.h" #include "framebuffer.h" #include "hash.h" +#include "image.h" #include "macros.h" #include "mfeatures.h" #include "mtypes.h" @@ -78,9 +79,24 @@ static struct gl_renderbuffer DummyRenderbuffer; static struct gl_framebuffer IncompleteFramebuffer; -#define IS_CUBE_FACE(TARGET) \ - ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ - (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) +/** + * Is the given FBO a user-created FBO? + */ +static inline GLboolean +is_user_fbo(const struct gl_framebuffer *fb) +{ + return fb->Name != 0; +} + + +/** + * Is the given FBO a window system FBO (like an X window)? + */ +static inline GLboolean +is_winsys_fbo(const struct gl_framebuffer *fb) +{ + return fb->Name == 0; +} static void @@ -159,6 +175,31 @@ invalidate_framebuffer(struct gl_framebuffer *fb) } +/** + * Return the gl_framebuffer object which corresponds to the given + * framebuffer target, such as GL_DRAW_FRAMEBUFFER. + * Check support for GL_EXT_framebuffer_blit to determine if certain + * targets are legal. + * \return gl_framebuffer pointer or NULL if target is illegal + */ +static struct gl_framebuffer * +get_framebuffer_target(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_DRAW_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL + ? ctx->DrawBuffer : NULL; + case GL_READ_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL + ? ctx->ReadBuffer : NULL; + case GL_FRAMEBUFFER_EXT: + return ctx->DrawBuffer; + default: + return NULL; + } +} + + /** * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding * gl_renderbuffer_attachment object. @@ -173,7 +214,7 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, { GLuint i; - assert(fb->Name > 0); + assert(is_user_fbo(fb)); switch (attachment) { case GL_COLOR_ATTACHMENT0_EXT: @@ -192,19 +233,22 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_COLOR_ATTACHMENT13_EXT: case GL_COLOR_ATTACHMENT14_EXT: case GL_COLOR_ATTACHMENT15_EXT: + /* Only OpenGL ES 1.x forbids color attachments other than + * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the + * hardware is used. + */ i = attachment - GL_COLOR_ATTACHMENT0_EXT; - if (i >= ctx->Const.MaxColorAttachments) { + if (i >= ctx->Const.MaxColorAttachments + || (i > 0 && ctx->API == API_OPENGLES)) { return NULL; } return &fb->Attachment[BUFFER_COLOR0 + i]; case GL_DEPTH_STENCIL_ATTACHMENT: + if (ctx->API != API_OPENGL) + return NULL; /* fall-through */ - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ case GL_DEPTH_ATTACHMENT_EXT: return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ case GL_STENCIL_ATTACHMENT_EXT: return &fb->Attachment[BUFFER_STENCIL]; default: @@ -221,7 +265,7 @@ static struct gl_renderbuffer_attachment * _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, GLenum attachment) { - assert(fb->Name == 0); + assert(is_winsys_fbo(fb)); switch (attachment) { case GL_FRONT_LEFT: @@ -237,13 +281,34 @@ _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, return &fb->Attachment[BUFFER_AUX0]; } return NULL; - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_DEPTH_ATTACHMENT_EXT: + + /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says: + * + * "If the default framebuffer is bound to target, then attachment must + * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi, + * identifying a color buffer; DEPTH, identifying the depth buffer; or + * STENCIL, identifying the stencil buffer." + * + * Revision #34 of the ARB_framebuffer_object spec has essentially the same + * language. However, revision #33 of the ARB_framebuffer_object spec + * says: + * + * "If the default framebuffer is bound to , then + * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi, + * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the + * depth buffer, or the stencil buffer, and may be + * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or + * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME." + * + * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed + * from glext.h, so shipping apps should not use those values. + * + * Note that neither EXT_framebuffer_object nor OES_framebuffer_object + * support queries of the window system FBO. + */ + case GL_DEPTH: return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_STENCIL_ATTACHMENT_EXT: + case GL_STENCIL: return &fb->Attachment[BUFFER_STENCIL]; default: return NULL; @@ -312,7 +377,7 @@ _mesa_set_texture_attachment(struct gl_context *ctx, att->Zoffset = zoffset; att->Complete = GL_FALSE; - if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + if (_mesa_get_attachment_teximage(att)) { ctx->Driver.RenderTexture(ctx, fb, att); } @@ -361,6 +426,7 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx, assert(att); _mesa_set_renderbuffer_attachment(ctx, att, rb); } + rb->AttachedAnytime = GL_TRUE; } else { _mesa_remove_attachment(ctx, att); @@ -394,9 +460,16 @@ _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) case GL_RG: fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; return; + default: - /* render buffer format is supported by software rendering */ - ; + switch (rb->Format) { + /* XXX This list is likely incomplete. */ + case MESA_FORMAT_RGB9_E5_FLOAT: + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + return; + default:; + /* render buffer format is supported by software rendering */ + } } } } @@ -638,7 +711,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, GLint i; GLuint j; - assert(fb->Name != 0); + assert(is_user_fbo(fb)); numImages = 0; fb->Width = 0; @@ -652,7 +725,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { struct gl_renderbuffer_attachment *att; GLenum f; - gl_format mesaFormat; + gl_format attFormat; /* * XXX for ARB_fbo, only check color buffers that are named by @@ -692,14 +765,14 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, /* get width, height, format of the renderbuffer/texture */ if (att->Type == GL_TEXTURE) { - const struct gl_texture_image *texImg - = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + const struct gl_texture_image *texImg = + _mesa_get_attachment_teximage(att); minWidth = MIN2(minWidth, texImg->Width); maxWidth = MAX2(maxWidth, texImg->Width); minHeight = MIN2(minHeight, texImg->Height); maxHeight = MAX2(maxHeight, texImg->Height); f = texImg->_BaseFormat; - mesaFormat = texImg->TexFormat; + attFormat = texImg->TexFormat; numImages++; if (!_mesa_is_legal_color_format(ctx, f) && !is_legal_depth_format(ctx, f)) { @@ -714,7 +787,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, minHeight = MIN2(minHeight, att->Renderbuffer->Height); maxHeight = MAX2(minHeight, att->Renderbuffer->Height); f = att->Renderbuffer->InternalFormat; - mesaFormat = att->Renderbuffer->Format; + attFormat = att->Renderbuffer->Format; numImages++; } else { @@ -722,13 +795,13 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, continue; } - if (numSamples < 0) { + if (att->Renderbuffer && numSamples < 0) { /* first buffer */ numSamples = att->Renderbuffer->NumSamples; } /* check if integer color */ - fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat); + fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); /* Error-check width, height, format, samples */ @@ -746,7 +819,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fbo_incomplete("width or height mismatch", -1); return; } - /* check that all color buffer have same format */ + /* check that all color buffers are the same format */ if (intFormat != GL_NONE && f != intFormat) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; fbo_incomplete("format mismatch", -1); @@ -758,13 +831,12 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; fbo_incomplete("inconsistant number of samples", i); return; - } - + } } } #if FEATURE_GL - if (ctx->API == API_OPENGL) { + if (ctx->API == API_OPENGL && !ctx->Extensions.ARB_ES2_compatibility) { /* Check that all DrawBuffers are present */ for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { if (fb->ColorDrawBuffer[j] != GL_NONE) { @@ -937,10 +1009,11 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } - if (ctx->DrawBuffer->Name) { + if (is_user_fbo(ctx->DrawBuffer)) { detach_renderbuffer(ctx, ctx->DrawBuffer, rb); } - if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { + if (is_user_fbo(ctx->ReadBuffer) + && ctx->ReadBuffer != ctx->DrawBuffer) { detach_renderbuffer(ctx, ctx->ReadBuffer, rb); } @@ -1057,7 +1130,6 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: - case GL_RGBA16_SNORM: case GL_SRGB8_ALPHA8_EXT: return GL_RGBA; case GL_STENCIL_INDEX: @@ -1077,6 +1149,16 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) return GL_DEPTH_STENCIL_EXT; else return 0; + case GL_DEPTH_COMPONENT32F: + if (ctx->Extensions.ARB_depth_buffer_float) + return GL_DEPTH_COMPONENT; + else + return 0; + case GL_DEPTH32F_STENCIL8: + if (ctx->Extensions.ARB_depth_buffer_float) + return GL_DEPTH_STENCIL; + else + return 0; case GL_RED: case GL_R8: case GL_R16: @@ -1085,13 +1167,172 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RG8: case GL_RG16: return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; - /* XXX add floating point and integer formats eventually */ + /* signed normalized texture formats */ + case GL_RED_SNORM: + case GL_R8_SNORM: + case GL_R16_SNORM: + return ctx->Extensions.EXT_texture_snorm ? GL_RED : 0; + case GL_RG_SNORM: + case GL_RG8_SNORM: + case GL_RG16_SNORM: + return ctx->Extensions.EXT_texture_snorm ? GL_RG : 0; + case GL_RGB_SNORM: + case GL_RGB8_SNORM: + case GL_RGB16_SNORM: + return ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0; + case GL_RGBA_SNORM: + case GL_RGBA8_SNORM: + case GL_RGBA16_SNORM: + return ctx->Extensions.EXT_texture_snorm ? GL_RGBA : 0; + case GL_ALPHA_SNORM: + case GL_ALPHA8_SNORM: + case GL_ALPHA16_SNORM: + return ctx->Extensions.EXT_texture_snorm && + ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE_SNORM: + case GL_LUMINANCE8_SNORM: + case GL_LUMINANCE16_SNORM: + return ctx->Extensions.EXT_texture_snorm && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + case GL_LUMINANCE_ALPHA_SNORM: + case GL_LUMINANCE8_ALPHA8_SNORM: + case GL_LUMINANCE16_ALPHA16_SNORM: + return ctx->Extensions.EXT_texture_snorm && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY_SNORM: + case GL_INTENSITY8_SNORM: + case GL_INTENSITY16_SNORM: + return ctx->Extensions.EXT_texture_snorm && + ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_R16F: + case GL_R32F: + return ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float ? GL_RED : 0; + case GL_RG16F: + case GL_RG32F: + return ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float ? GL_RG : 0; + case GL_RGB16F: + case GL_RGB32F: + return ctx->Extensions.ARB_texture_float ? GL_RGB : 0; + case GL_RGBA16F: + case GL_RGBA32F: + return ctx->Extensions.ARB_texture_float ? GL_RGBA : 0; + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + return ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + return ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + return ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + return ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_RGB9_E5: + return ctx->Extensions.EXT_texture_shared_exponent ? GL_RGB : 0; + case GL_R11F_G11F_B10F: + return ctx->Extensions.EXT_packed_float ? GL_RGB : 0; + + case GL_RGBA8UI_EXT: + case GL_RGBA16UI_EXT: + case GL_RGBA32UI_EXT: + case GL_RGBA8I_EXT: + case GL_RGBA16I_EXT: + case GL_RGBA32I_EXT: + return ctx->Extensions.EXT_texture_integer ? GL_RGBA : 0; + + case GL_RGB8UI_EXT: + case GL_RGB16UI_EXT: + case GL_RGB32UI_EXT: + case GL_RGB8I_EXT: + case GL_RGB16I_EXT: + case GL_RGB32I_EXT: + return ctx->Extensions.EXT_texture_integer ? GL_RGB : 0; + + case GL_R8UI: + case GL_R8I: + case GL_R16UI: + case GL_R16I: + case GL_R32UI: + case GL_R32I: + return ctx->Extensions.ARB_texture_rg && + ctx->Extensions.EXT_texture_integer ? GL_RED : 0; + + case GL_RG8UI: + case GL_RG8I: + case GL_RG16UI: + case GL_RG16I: + case GL_RG32UI: + case GL_RG32I: + return ctx->Extensions.ARB_texture_rg && + ctx->Extensions.EXT_texture_integer ? GL_RG : 0; + + case GL_INTENSITY8I_EXT: + case GL_INTENSITY8UI_EXT: + case GL_INTENSITY16I_EXT: + case GL_INTENSITY16UI_EXT: + case GL_INTENSITY32I_EXT: + case GL_INTENSITY32UI_EXT: + return ctx->Extensions.EXT_texture_integer && + ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + + case GL_LUMINANCE8I_EXT: + case GL_LUMINANCE8UI_EXT: + case GL_LUMINANCE16I_EXT: + case GL_LUMINANCE16UI_EXT: + case GL_LUMINANCE32I_EXT: + case GL_LUMINANCE32UI_EXT: + return ctx->Extensions.EXT_texture_integer && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + + case GL_LUMINANCE_ALPHA8I_EXT: + case GL_LUMINANCE_ALPHA8UI_EXT: + case GL_LUMINANCE_ALPHA16I_EXT: + case GL_LUMINANCE_ALPHA16UI_EXT: + case GL_LUMINANCE_ALPHA32I_EXT: + case GL_LUMINANCE_ALPHA32UI_EXT: + return ctx->Extensions.EXT_texture_integer && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + + case GL_RGB10_A2UI: + return ctx->Extensions.ARB_texture_rgb10_a2ui ? GL_RGBA : 0; default: return 0; } } +/** + * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk(). + */ +static void +invalidate_rb(GLuint key, void *data, void *userData) +{ + struct gl_framebuffer *fb = (struct gl_framebuffer *) data; + struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; + + /* If this is a user-created FBO */ + if (is_user_fbo(fb)) { + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + if (att->Type == GL_RENDERBUFFER && + att->Renderbuffer == rb) { + /* Mark fb status as indeterminate to force re-validation */ + fb->_Status = 0; + return; + } + } + } +} + + /** sentinal value, see below */ #define NO_SAMPLES 1000 @@ -1124,12 +1365,12 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, return; } - if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { + if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); return; } - if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { + if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); return; } @@ -1184,12 +1425,10 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, rb->NumSamples = 0; } - /* - test_framebuffer_completeness(ctx, fb); - */ - /* XXX if this renderbuffer is attached anywhere, invalidate attachment - * points??? - */ + /* Invalidate the framebuffers the renderbuffer is attached in. */ + if (rb->AttachedAnytime) { + _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb); + } } @@ -1238,48 +1477,10 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) static GLint get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) { - switch (pname) { - case GL_RENDERBUFFER_RED_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || - baseFormat == GL_RG || baseFormat == GL_RED) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_GREEN_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_BLUE_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_ALPHA_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA || - baseFormat == GL_LUMINANCE_ALPHA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_DEPTH_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - default: + if (_mesa_base_format_has_channel(baseFormat, pname)) + return _mesa_get_format_bits(format, pname); + else return 0; - } } @@ -1408,14 +1609,12 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) GLuint i; ASSERT(ctx->Driver.RenderTexture); - if (fb->Name == 0) + if (is_winsys_fbo(fb)) return; /* can't render to texture with winsys framebuffers */ for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; - struct gl_texture_object *texObj = att->Texture; - if (texObj - && texObj->Image[att->CubeMapFace][att->TextureLevel]) { + if (att->Texture && _mesa_get_attachment_teximage(att)) { ctx->Driver.RenderTexture(ctx, fb, att); } } @@ -1430,7 +1629,7 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) static void check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) { - if (fb->Name == 0) + if (is_winsys_fbo(fb)) return; /* can't render to texture with winsys framebuffers */ if (ctx->Driver.FinishRenderTexture) { @@ -1620,7 +1819,7 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) /* bind default */ ASSERT(fb->RefCount >= 2); _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } + } } /* remove from hash table immediately, to free the ID */ @@ -1677,32 +1876,13 @@ _mesa_CheckFramebufferStatusEXT(GLenum target) ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ + return 0; } - if (buffer->Name == 0) { + if (is_winsys_fbo(buffer)) { /* The window system / default framebuffer is always complete */ return GL_FRAMEBUFFER_COMPLETE_EXT; } @@ -1717,6 +1897,30 @@ _mesa_CheckFramebufferStatusEXT(GLenum target) } +/** + * Replicate the src attachment point. Used by framebuffer_texture() when + * the same texture is attached at GL_DEPTH_ATTACHMENT and + * GL_STENCIL_ATTACHMENT. + */ +static void +reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, + gl_buffer_index dst, + gl_buffer_index src) +{ + struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst]; + struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src]; + + assert(src_att->Texture != NULL); + assert(src_att->Renderbuffer != NULL); + + _mesa_reference_texobj(&dst_att->Texture, src_att->Texture); + _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer); + dst_att->Type = src_att->Type; + dst_att->Complete = src_att->Complete; + dst_att->TextureLevel = src_att->TextureLevel; + dst_att->Zoffset = src_att->Zoffset; +} + /** * Common code called by glFramebufferTexture1D/2D/3DEXT(). @@ -1729,41 +1933,23 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, struct gl_renderbuffer_attachment *att; struct gl_texture_object *texObj = NULL; struct gl_framebuffer *fb; - GLboolean error = GL_FALSE; ASSERT_OUTSIDE_BEGIN_END(ctx); - switch (target) { - case GL_READ_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - fb = ctx->ReadBuffer; - break; - case GL_DRAW_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - /* fall-through */ - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - error = GL_TRUE; - } - - if (error) { + fb = get_framebuffer_target(ctx, target); + if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture%sEXT(target=0x%x)", caller, target); return; } - ASSERT(fb); - /* check framebuffer binding */ - if (fb->Name == 0) { + if (is_winsys_fbo(fb)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture%sEXT", caller); return; } - /* The textarget, level, and zoffset parameters are only validated if * texture is non-zero. */ @@ -1780,7 +1966,7 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } else { err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !IS_CUBE_FACE(textarget) + ? !_mesa_is_cube_face(textarget) : (texObj->Target != textarget); } } @@ -1816,7 +2002,7 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } } - if ((level < 0) || + if ((level < 0) || (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(level)", caller); @@ -1835,8 +2021,34 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, _glthread_LOCK_MUTEX(fb->Mutex); if (texObj) { - _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, - level, zoffset); + if (attachment == GL_DEPTH_ATTACHMENT && + texObj == fb->Attachment[BUFFER_STENCIL].Texture) { + /* The texture object is already attached to the stencil attachment + * point. Don't create a new renderbuffer; just reuse the stencil + * attachment's. This is required to prevent a GL error in + * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL). + */ + reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH, + BUFFER_STENCIL); + } else if (attachment == GL_STENCIL_ATTACHMENT && + texObj == fb->Attachment[BUFFER_DEPTH].Texture) { + /* As above, but with depth and stencil juxtasposed. */ + reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, + BUFFER_DEPTH); + } else { + _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, + level, zoffset); + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + /* Above we created a new renderbuffer and attached it to the + * depth attachment point. Now attach it to the stencil attachment + * point too. + */ + assert(att == &fb->Attachment[BUFFER_DEPTH]); + reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL, + BUFFER_DEPTH); + } + } + /* Set the render-to-texture flag. We'll check this flag in * glTexImage() and friends to determine if we need to revalidate * any FBOs that might be rendering into this texture. @@ -1849,6 +2061,10 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } else { _mesa_remove_attachment(ctx, att); + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + assert(att == &fb->Attachment[BUFFER_DEPTH]); + _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]); + } } invalidate_framebuffer(fb); @@ -1864,10 +2080,26 @@ _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, { GET_CURRENT_CONTEXT(ctx); - if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture1DEXT(textarget)"); - return; + if (texture != 0) { + GLboolean error; + + switch (textarget) { + case GL_TEXTURE_1D: + error = GL_FALSE; + break; + case GL_TEXTURE_1D_ARRAY: + error = !ctx->Extensions.EXT_texture_array; + break; + default: + error = GL_TRUE; + } + + if (error) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture1DEXT(textarget=%s)", + _mesa_lookup_enum_by_nr(textarget)); + return; + } } framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, @@ -1881,13 +2113,37 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, { GET_CURRENT_CONTEXT(ctx); - if ((texture != 0) && - (textarget != GL_TEXTURE_2D) && - (textarget != GL_TEXTURE_RECTANGLE_ARB) && - (!IS_CUBE_FACE(textarget))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); - return; + if (texture != 0) { + GLboolean error; + + switch (textarget) { + case GL_TEXTURE_2D: + error = GL_FALSE; + break; + case GL_TEXTURE_RECTANGLE: + error = !ctx->Extensions.NV_texture_rectangle; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + error = !ctx->Extensions.ARB_texture_cube_map; + break; + case GL_TEXTURE_2D_ARRAY: + error = !ctx->Extensions.EXT_texture_array; + break; + default: + error = GL_TRUE; + } + + if (error) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture2DEXT(textarget=%s)", + _mesa_lookup_enum_by_nr(textarget)); + return; + } } framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, @@ -1903,7 +2159,7 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, GET_CURRENT_CONTEXT(ctx); if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { - _mesa_error(ctx, GL_INVALID_ENUM, + _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture3DEXT(textarget)"); return; } @@ -1936,31 +2192,9 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, ASSERT_OUTSIDE_BEGIN_END(ctx); - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)"); return; } @@ -1970,7 +2204,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, return; } - if (fb->Name == 0) { + if (is_winsys_fbo(fb)) { /* Can't attach new renderbuffers to a window system framebuffer */ _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); return; @@ -2036,39 +2270,37 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, { const struct gl_renderbuffer_attachment *att; struct gl_framebuffer *buffer; + GLenum err; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: + /* The error differs in GL andd GLES. */ + err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(target)"); return; } - if (buffer->Name == 0) { + if (is_winsys_fbo(buffer)) { + /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec + * says: + * + * "If the framebuffer currently bound to target is zero, then + * INVALID_OPERATION is generated." + * + * The EXT_framebuffer_object spec has the same wording, and the + * OES_framebuffer_object spec refers to the EXT_framebuffer_object + * spec. + */ + if (ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); + return; + } /* the default / window-system FBO */ att = _mesa_get_fb0_attachment(ctx, buffer, attachment); } @@ -2100,7 +2332,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type; + *params = is_winsys_fbo(buffer) ? GL_FRAMEBUFFER_DEFAULT : att->Type; return; case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: if (att->Type == GL_RENDERBUFFER_EXT) { @@ -2111,13 +2343,22 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } else { assert(att->Type == GL_NONE); - *params = 0; + if (ctx->API == API_OPENGL) { + *params = 0; + } else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } } return; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: if (att->Type == GL_TEXTURE) { *params = att->TextureLevel; } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(pname)"); @@ -2132,6 +2373,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, *params = 0; } } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(pname)"); @@ -2146,6 +2391,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, *params = 0; } } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(pname)"); @@ -2156,6 +2405,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(pname)"); } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else { if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); @@ -2173,12 +2426,25 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, "glGetFramebufferAttachmentParameterivEXT(pname)"); return; } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else { gl_format format = att->Renderbuffer->Format; - if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { + if (format == MESA_FORMAT_S8) { /* special cases */ *params = GL_INDEX; } + else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) { + /* depends on the attachment parameter */ + if (attachment == GL_STENCIL_ATTACHMENT) { + *params = GL_INDEX; + } + else { + *params = GL_FLOAT; + } + } else { *params = _mesa_get_format_datatype(format); } @@ -2194,6 +2460,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(pname)"); } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else if (att->Texture) { const struct gl_texture_image *texImage = _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, @@ -2211,7 +2481,8 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, att->Renderbuffer->Format); } else { - *params = 0; + _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" + " invalid FBO attachment structure"); } return; default: @@ -2225,7 +2496,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, void GLAPIENTRY _mesa_GenerateMipmapEXT(GLenum target) { + struct gl_texture_image *srcImage; struct gl_texture_object *texObj; + GLboolean error; + GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -2235,12 +2509,22 @@ _mesa_GenerateMipmapEXT(GLenum target) case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: + error = GL_FALSE; + break; case GL_TEXTURE_CUBE_MAP: - /* OK, legal value */ + error = !ctx->Extensions.ARB_texture_cube_map; + break; + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D_ARRAY: + error = !ctx->Extensions.EXT_texture_array; break; default: - /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */ - _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); + error = GL_TRUE; + } + + if (error) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)", + _mesa_lookup_enum_by_nr(target)); return; } @@ -2259,6 +2543,13 @@ _mesa_GenerateMipmapEXT(GLenum target) } _mesa_lock_texture(ctx, texObj); + + srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel); + if (!srcImage) { + _mesa_unlock_texture(ctx, texObj); + return; + } + if (target == GL_TEXTURE_CUBE_MAP) { GLuint face; for (face = 0; face < 6; face++) @@ -2288,6 +2579,44 @@ find_attachment(const struct gl_framebuffer *fb, } +/** + * Helper function for checking if the datatypes of color buffers are + * compatible for glBlitFramebuffer. From the 3.1 spec, page 198: + * + * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT + * and any of the following conditions hold: + * - The read buffer contains fixed-point or floating-point values and any + * draw buffer contains neither fixed-point nor floating-point values. + * - The read buffer contains unsigned integer values and any draw buffer + * does not contain unsigned integer values. + * - The read buffer contains signed integer values and any draw buffer + * does not contain signed integer values." + */ +static GLboolean +compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat) +{ + GLenum srcType = _mesa_get_format_datatype(srcFormat); + GLenum dstType = _mesa_get_format_datatype(dstFormat); + + if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) { + assert(srcType == GL_UNSIGNED_NORMALIZED || + srcType == GL_SIGNED_NORMALIZED || + srcType == GL_FLOAT); + /* Boil any of those types down to GL_FLOAT */ + srcType = GL_FLOAT; + } + + if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) { + assert(dstType == GL_UNSIGNED_NORMALIZED || + dstType == GL_SIGNED_NORMALIZED || + dstType == GL_FLOAT); + /* Boil any of those types down to GL_FLOAT */ + dstType = GL_FLOAT; + } + + return srcType == dstType; +} + /** * Blit rectangular region, optionally from one framebuffer to another. @@ -2310,6 +2639,13 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_BUFFERS); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, _mesa_lookup_enum_by_nr(filter)); + if (ctx->NewState) { _mesa_update_state(ctx); } @@ -2346,7 +2682,7 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) && filter != GL_NEAREST) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); + "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)"); return; } @@ -2354,33 +2690,68 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if (mask & GL_COLOR_BUFFER_BIT) { colorReadRb = readFb->_ColorReadBuffer; colorDrawRb = drawFb->_ColorDrawBuffers[0]; + + /* From the EXT_framebuffer_object spec: + * + * "If a buffer is specified in and does not exist in both + * the read and draw framebuffers, the corresponding bit is silently + * ignored." + */ + if ((colorReadRb == NULL) || (colorDrawRb == NULL)) { + colorReadRb = colorDrawRb = NULL; + mask &= ~GL_COLOR_BUFFER_BIT; + } + else if (!compatible_color_datatypes(colorReadRb->Format, + colorDrawRb->Format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(color buffer datatypes mismatch)"); + return; + } } else { colorReadRb = colorDrawRb = NULL; } if (mask & GL_STENCIL_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_StencilBuffer; - struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { + struct gl_renderbuffer *readRb = + readFb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer *drawRb = + drawFb->Attachment[BUFFER_STENCIL].Renderbuffer; + + /* From the EXT_framebuffer_object spec: + * + * "If a buffer is specified in and does not exist in both + * the read and draw framebuffers, the corresponding bit is silently + * ignored." + */ + if ((readRb == NULL) || (drawRb == NULL)) { + mask &= ~GL_STENCIL_BUFFER_BIT; + } + else if (readRb->Format != drawRb->Format) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(stencil buffer size mismatch"); + "glBlitFramebufferEXT(stencil buffer format mismatch)"); return; } } if (mask & GL_DEPTH_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_DepthBuffer; - struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { + struct gl_renderbuffer *readRb = + readFb->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *drawRb = + drawFb->Attachment[BUFFER_DEPTH].Renderbuffer; + + /* From the EXT_framebuffer_object spec: + * + * "If a buffer is specified in and does not exist in both + * the read and draw framebuffers, the corresponding bit is silently + * ignored." + */ + if ((readRb == NULL) || (drawRb == NULL)) { + mask &= ~GL_DEPTH_BUFFER_BIT; + } + else if (readRb->Format != drawRb->Format) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth buffer size mismatch"); + "glBlitFramebufferEXT(depth buffer format mismatch)"); return; } } @@ -2389,7 +2760,7 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, drawFb->Visual.samples > 0 && readFb->Visual.samples != drawFb->Visual.samples) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(mismatched samples"); + "glBlitFramebufferEXT(mismatched samples)"); return; } @@ -2399,7 +2770,7 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes"); + "glBlitFramebufferEXT(bad src/dst multisample region sizes)"); return; } @@ -2408,7 +2779,20 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, colorDrawRb && colorReadRb->Format != colorDrawRb->Format) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); + "glBlitFramebufferEXT(bad src/dst multisample pixel formats)"); + return; + } + } + + if (filter == GL_LINEAR && (mask & GL_COLOR_BUFFER_BIT)) { + /* 3.1 spec, page 199: + * "Calling BlitFramebuffer will result in an INVALID_OPERATION error + * if filter is LINEAR and read buffer contains integer data." + */ + GLenum type = _mesa_get_format_datatype(colorReadRb->Format); + if (type == GL_INT || type == GL_UNSIGNED_INT) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(integer color type)"); return; } } @@ -2456,6 +2840,10 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, } } + if (!mask) { + return; + } + ASSERT(ctx->Driver.BlitFramebuffer); ctx->Driver.BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, @@ -2464,6 +2852,7 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, } #endif /* FEATURE_EXT_framebuffer_blit */ + #if FEATURE_ARB_geometry_shader4 void GLAPIENTRY _mesa_FramebufferTextureARB(GLenum target, GLenum attachment, @@ -2475,6 +2864,7 @@ _mesa_FramebufferTextureARB(GLenum target, GLenum attachment, "not implemented!"); } + void GLAPIENTRY _mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face)