X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=c56062ac6a7402b79e9977ebce495a4c9f516f08;hb=1d5d67f8adac9f94715de9804adb536d9a7ec5ee;hp=e3aefe9b85584288f2380e1fd60cd2857a819b43;hpb=dd973cd9e81abf1c0bc1880c7905f3277d4361a0;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index e3aefe9b855..c56062ac6a7 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -78,9 +78,32 @@ 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) +static inline GLboolean +is_cube_face(GLenum target) +{ + return (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 +182,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 +221,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 +240,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 +272,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 +288,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 +384,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 +433,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); @@ -372,6 +445,44 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx, } +/** + * Fallback for ctx->Driver.ValidateFramebuffer() + * Check if the renderbuffer's formats are supported by the software + * renderer. + * Drivers should probably override this. + */ +void +_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + gl_buffer_index buf; + for (buf = 0; buf < BUFFER_COUNT; buf++) { + const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; + if (rb) { + switch (rb->_BaseFormat) { + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE: + case GL_INTENSITY: + case GL_RED: + case GL_RG: + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + return; + + default: + 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 */ + } + } + } + } +} + + /** * For debug only. */ @@ -607,7 +718,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; @@ -621,7 +732,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 @@ -661,14 +772,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)) { @@ -683,7 +794,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 { @@ -691,13 +802,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 */ @@ -733,7 +844,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, } #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) { @@ -906,10 +1017,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); } @@ -961,26 +1073,53 @@ _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) /** * Given an internal format token for a render buffer, return the - * corresponding base format. - * This is very similar to _mesa_base_tex_format() but the set of valid - * internal formats is somewhat different. + * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, + * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, + * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). + * + * This is similar to _mesa_base_tex_format() but the set of valid + * internal formats is different. * - * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT - * GL_DEPTH_STENCIL_EXT or zero if error. + * Note that even if a format is determined to be legal here, validation + * of the FBO may fail if the format is not supported by the driver/GPU. * - * XXX in the future when we support red-only and red-green formats - * we'll also return GL_RED and GL_RG. + * \param internalFormat as passed to glRenderbufferStorage() + * \return the base internal format, or 0 if internalFormat is illegal */ GLenum _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) { + /* + * Notes: some formats such as alpha, luminance, etc. were added + * with GL_ARB_framebuffer_object. + */ switch (internalFormat) { case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: - return GL_ALPHA; + return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; case GL_RGB: case GL_R3_G3_B2: case GL_RGB4: @@ -989,6 +1128,7 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGB10: case GL_RGB12: case GL_RGB16: + case GL_SRGB8_EXT: return GL_RGB; case GL_RGBA: case GL_RGBA2: @@ -998,7 +1138,7 @@ _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: case GL_STENCIL_INDEX1_EXT: @@ -1017,13 +1157,187 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) return GL_DEPTH_STENCIL_EXT; else return 0; - /* XXX add floating point formats eventually */ + 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: + return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; + case GL_RG: + case GL_RG8: + case GL_RG16: + return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; + /* 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; 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 @@ -1116,12 +1430,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); + } } @@ -1340,14 +1652,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); } } @@ -1362,7 +1672,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) { @@ -1609,32 +1919,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; } @@ -1661,35 +1952,18 @@ 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; @@ -1712,7 +1986,7 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } else { err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !IS_CUBE_FACE(textarget) + ? !is_cube_face(textarget) : (texObj->Target != textarget); } } @@ -1796,10 +2070,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, @@ -1813,13 +2103,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_FALSE; + } + + 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, @@ -1835,7 +2149,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; } @@ -1868,31 +2182,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; } @@ -1902,7 +2194,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; @@ -1968,39 +2260,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); } @@ -2032,7 +2322,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) { @@ -2043,13 +2333,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)"); @@ -2064,6 +2363,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)"); @@ -2078,6 +2381,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)"); @@ -2088,8 +2395,19 @@ _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 { - *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); + if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { + *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); + } + else { + /* According to ARB_framebuffer_sRGB, we should return LINEAR + * if the sRGB conversion is unsupported. */ + *params = GL_LINEAR; + } } return; case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: @@ -2098,12 +2416,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); } @@ -2119,6 +2450,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, @@ -2136,7 +2471,8 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, att->Renderbuffer->Format); } else { - *params = 0; + _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" + " invalid FBO attachment structure"); } return; default: @@ -2150,7 +2486,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); @@ -2160,12 +2499,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; } @@ -2184,6 +2533,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++) @@ -2201,7 +2557,8 @@ _mesa_GenerateMipmapEXT(GLenum target) #if FEATURE_EXT_framebuffer_blit static const struct gl_renderbuffer_attachment * -find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb) +find_attachment(const struct gl_framebuffer *fb, + const struct gl_renderbuffer *rb) { GLuint i; for (i = 0; i < Elements(fb->Attachment); i++) { @@ -2234,6 +2591,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); } @@ -2270,7 +2634,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; } @@ -2278,6 +2642,17 @@ _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 { colorReadRb = colorDrawRb = NULL; @@ -2286,12 +2661,21 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 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)) { + + /* 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)) { + readRb = drawRb = NULL; + mask &= ~GL_STENCIL_BUFFER_BIT; + } + else if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(stencil buffer size mismatch"); + "glBlitFramebufferEXT(stencil buffer size mismatch)"); return; } } @@ -2299,12 +2683,21 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 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)) { + + /* 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)) { + readRb = drawRb = NULL; + mask &= ~GL_DEPTH_BUFFER_BIT; + } + else if (_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth buffer size mismatch"); + "glBlitFramebufferEXT(depth buffer size mismatch)"); return; } } @@ -2323,7 +2716,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; } @@ -2332,7 +2725,7 @@ _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; } } @@ -2380,6 +2773,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,