X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=0758d55574a886bf6ff76ea5023265a4fd49dc06;hb=406df38a6673cb7d19ce652f71fac1047b2279d0;hp=5da6a6cd16a4dcaec7c1dd8327418326467fa126;hpb=ca1b5515621d4ab9e90e27533fbc0fafa5cf641b;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 5da6a6cd16a..0758d55574a 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -38,6 +38,7 @@ #include "fbobject.h" #include "formats.h" #include "framebuffer.h" +#include "glformats.h" #include "hash.h" #include "macros.h" #include "mfeatures.h" @@ -48,9 +49,6 @@ #include "texobj.h" -/** Set this to 1 to help debug FBO incompleteness problems */ -#define DEBUG_FBO 0 - /** Set this to 1 to debug/log glBlitFramebuffer() calls */ #define DEBUG_BLIT 0 @@ -78,11 +76,6 @@ 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 void delete_dummy_renderbuffer(struct gl_renderbuffer *rb) { @@ -159,6 +152,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 && _mesa_is_desktop_gl(ctx) + ? ctx->DrawBuffer : NULL; + case GL_READ_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx) + ? 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 +191,7 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, { GLuint i; - assert(fb->Name > 0); + assert(_mesa_is_user_fbo(fb)); switch (attachment) { case GL_COLOR_ATTACHMENT0_EXT: @@ -192,19 +210,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 (!_mesa_is_desktop_gl(ctx)) + 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 +242,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(_mesa_is_winsys_fbo(fb)); switch (attachment) { case GL_FRONT_LEFT: @@ -237,13 +258,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 +354,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 +403,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 +437,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 */ + } } } } @@ -409,11 +459,9 @@ _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) static void att_incomplete(const char *msg) { -#if DEBUG_FBO - _mesa_debug(NULL, "attachment incomplete: %s\n", msg); -#else - (void) msg; -#endif + if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { + _mesa_debug(NULL, "attachment incomplete: %s\n", msg); + } } @@ -423,12 +471,9 @@ att_incomplete(const char *msg) static void fbo_incomplete(const char *msg, int index) { -#if DEBUG_FBO - _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); -#else - (void) msg; - (void) index; -#endif + if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { + _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); + } } @@ -638,7 +683,10 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, GLint i; GLuint j; - assert(fb->Name != 0); + assert(_mesa_is_user_fbo(fb)); + + /* we're changing framebuffer fields here */ + FLUSH_VERTICES(ctx, _NEW_BUFFERS); numImages = 0; fb->Width = 0; @@ -692,8 +740,8 @@ _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); @@ -722,7 +770,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, continue; } - if (numSamples < 0) { + if (att->Renderbuffer && numSamples < 0) { /* first buffer */ numSamples = att->Renderbuffer->NumSamples; } @@ -746,7 +794,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 +806,20 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; fbo_incomplete("inconsistant number of samples", i); return; - } + } + } + /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported) + */ + if (att->Type == GL_RENDERBUFFER && + att->Renderbuffer->Format == MESA_FORMAT_NONE) { + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + fbo_incomplete("unsupported renderbuffer format", i); + return; } } -#if FEATURE_GL - if (ctx->API == API_OPENGL) { + if (_mesa_is_desktop_gl(ctx) && !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) { @@ -791,9 +846,6 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, } } } -#else - (void) j; -#endif if (numImages == 0) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; @@ -937,10 +989,11 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } - if (ctx->DrawBuffer->Name) { + if (_mesa_is_user_fbo(ctx->DrawBuffer)) { detach_renderbuffer(ctx, ctx->DrawBuffer, rb); } - if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { + if (_mesa_is_user_fbo(ctx->ReadBuffer) + && ctx->ReadBuffer != ctx->DrawBuffer) { detach_renderbuffer(ctx, ctx->ReadBuffer, rb); } @@ -1018,13 +1071,15 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + return ctx->API == API_OPENGL && 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; + return ctx->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + ? GL_LUMINANCE : 0; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE4_ALPHA4: case GL_LUMINANCE6_ALPHA2: @@ -1032,66 +1087,312 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_LUMINANCE12_ALPHA4: case GL_LUMINANCE12_ALPHA12: case GL_LUMINANCE16_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + return ctx->API == API_OPENGL && 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; + return ctx->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + ? GL_INTENSITY : 0; + case GL_RGB8: + return GL_RGB; case GL_RGB: case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: - case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: + return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; case GL_SRGB8_EXT: - return GL_RGB; - case GL_RGBA: - case GL_RGBA2: + return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGB : 0; case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: - case GL_RGB10_A2: + return GL_RGBA; + case GL_RGBA: + case GL_RGBA2: case GL_RGBA12: case GL_RGBA16: - case GL_RGBA16_SNORM: + return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; + case GL_RGB10_A2: case GL_SRGB8_ALPHA8_EXT: - return GL_RGBA; + return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: + /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in + * OpenGL ES, but Mesa does not currently support them. + */ + return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0; + case GL_STENCIL_INDEX8_EXT: return GL_STENCIL_INDEX; case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT32: + return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0; case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: return GL_DEPTH_COMPONENT; case GL_DEPTH_STENCIL_EXT: + return _mesa_is_desktop_gl(ctx) + && ctx->Extensions.EXT_packed_depth_stencil + ? GL_DEPTH_STENCIL_EXT : 0; case GL_DEPTH24_STENCIL8_EXT: - if (ctx->Extensions.EXT_packed_depth_stencil) - return GL_DEPTH_STENCIL_EXT; - else - return 0; + return ctx->Extensions.EXT_packed_depth_stencil + ? GL_DEPTH_STENCIL_EXT : 0; + case GL_DEPTH_COMPONENT32F: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.ARB_depth_buffer_float) + ? GL_DEPTH_COMPONENT : 0; + case GL_DEPTH32F_STENCIL8: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.ARB_depth_buffer_float) + ? GL_DEPTH_STENCIL : 0; case GL_RED: - case GL_R8: case GL_R16: - return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg + ? GL_RED : 0; + case GL_R8: + return ctx->API != API_OPENGLES && 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; - /* XXX add floating point and integer formats eventually */ + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg + ? GL_RG : 0; + case GL_RG8: + return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg + ? GL_RG : 0; + /* signed normalized texture formats */ + case GL_R8_SNORM: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.EXT_texture_snorm) + ? GL_RED : 0; + case GL_RED_SNORM: + case GL_R16_SNORM: + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + ? GL_RED : 0; + case GL_RG8_SNORM: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.EXT_texture_snorm) + ? GL_RG : 0; + case GL_RG_SNORM: + case GL_RG16_SNORM: + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + ? GL_RG : 0; + case GL_RGB8_SNORM: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.EXT_texture_snorm) + ? GL_RGB : 0; + case GL_RGB_SNORM: + case GL_RGB16_SNORM: + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + ? GL_RGB : 0; + case GL_RGBA8_SNORM: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.EXT_texture_snorm) + ? GL_RGBA : 0; + case GL_RGBA_SNORM: + case GL_RGBA16_SNORM: + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + ? GL_RGBA : 0; + case GL_ALPHA_SNORM: + case GL_ALPHA8_SNORM: + case GL_ALPHA16_SNORM: + return ctx->API == API_OPENGL && + 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->API == API_OPENGL && + 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->API == API_OPENGL && + 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->API == API_OPENGL && + ctx->Extensions.EXT_texture_snorm && + ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_R16F: + case GL_R32F: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && + ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float) ? GL_RED : 0; + case GL_RG16F: + case GL_RG32F: + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && + ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float) ? GL_RG : 0; + case GL_RGB16F: + case GL_RGB32F: + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) + || _mesa_is_gles3(ctx) + ? GL_RGB : 0; + case GL_RGBA16F: + case GL_RGBA32F: + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) + || _mesa_is_gles3(ctx) + ? GL_RGBA : 0; + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + return ctx->API == API_OPENGL && + ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + return ctx->API == API_OPENGL && + 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->API == API_OPENGL && + ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + return ctx->API == API_OPENGL && + ctx->Extensions.ARB_texture_float && + ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_RGB9_E5: + return (_mesa_is_desktop_gl(ctx) + && ctx->Extensions.EXT_texture_shared_exponent) + || _mesa_is_gles3(ctx) ? GL_RGB : 0; + case GL_R11F_G11F_B10F: + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) + || _mesa_is_gles3(ctx) ? 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->Version >= 30 + || (_mesa_is_desktop_gl(ctx) && + 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->Version >= 30 + || (_mesa_is_desktop_gl(ctx) && + 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->Version >= 30 + || (_mesa_is_desktop_gl(ctx) && + 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->Version >= 30 + || (_mesa_is_desktop_gl(ctx) && + 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->API == API_OPENGL && + 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->API == API_OPENGL && + 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->API == API_OPENGL && + ctx->Extensions.EXT_texture_integer && + ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + + case GL_ALPHA8I_EXT: + case GL_ALPHA8UI_EXT: + case GL_ALPHA16I_EXT: + case GL_ALPHA16UI_EXT: + case GL_ALPHA32I_EXT: + case GL_ALPHA32UI_EXT: + return ctx->API == API_OPENGL && + ctx->Extensions.EXT_texture_integer && + ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + + case GL_RGB10_A2UI: + return (_mesa_is_desktop_gl(ctx) && + ctx->Extensions.ARB_texture_rgb10_a2ui) + || _mesa_is_gles3(ctx) ? GL_RGBA : 0; + + case GL_RGB565: + return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility + ? GL_RGB : 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 (_mesa_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 +1425,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; } @@ -1154,7 +1455,8 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, if (rb->InternalFormat == internalFormat && rb->Width == (GLuint) width && - rb->Height == (GLuint) height) { + rb->Height == (GLuint) height && + rb->NumSamples == samples) { /* no change in allocation needed */ return; } @@ -1167,7 +1469,7 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, ASSERT(rb->AllocStorage); if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { /* No error - check/set fields now */ - assert(rb->Format != MESA_FORMAT_NONE); + /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */ assert(rb->Width == (GLuint) width); assert(rb->Height == (GLuint) height); rb->InternalFormat = internalFormat; @@ -1184,16 +1486,13 @@ 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); + } } -#if FEATURE_OES_EGL_image void GLAPIENTRY _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) { @@ -1224,7 +1523,6 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); } -#endif /** @@ -1238,48 +1536,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; - } } @@ -1370,7 +1630,8 @@ _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); break; case GL_RENDERBUFFER_SAMPLES: - if (ctx->Extensions.ARB_framebuffer_object) { + if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) + || _mesa_is_gles3(ctx)) { *params = rb->NumSamples; break; } @@ -1408,14 +1669,12 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) GLuint i; ASSERT(ctx->Driver.RenderTexture); - if (fb->Name == 0) + if (_mesa_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 +1689,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 (_mesa_is_winsys_fbo(fb)) return; /* can't render to texture with winsys framebuffers */ if (ctx->Driver.FinishRenderTexture) { @@ -1469,7 +1728,6 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) } switch (target) { -#if FEATURE_EXT_framebuffer_blit case GL_DRAW_FRAMEBUFFER_EXT: if (!ctx->Extensions.EXT_framebuffer_blit) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); @@ -1486,7 +1744,6 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) bindDrawBuf = GL_FALSE; bindReadBuf = GL_TRUE; break; -#endif case GL_FRAMEBUFFER_EXT: bindDrawBuf = GL_TRUE; bindReadBuf = GL_TRUE; @@ -1565,11 +1822,8 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) if (bindDrawBuf) { FLUSH_VERTICES(ctx, _NEW_BUFFERS); - /* check if old read/draw buffers were render-to-texture */ - if (!bindReadBuf) - check_end_texture_render(ctx, oldReadFb); - - if (oldDrawFb != oldReadFb) + /* check if old framebuffer had any texture attachments */ + if (oldDrawFb) check_end_texture_render(ctx, oldDrawFb); /* check if newly bound framebuffer has any texture attachments */ @@ -1620,7 +1874,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 +1931,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 (_mesa_is_winsys_fbo(buffer)) { /* The window system / default framebuffer is always complete */ return GL_FRAMEBUFFER_COMPLETE_EXT; } @@ -1717,9 +1952,36 @@ _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(). + * Common code called by glFramebufferTexture1D/2D/3DEXT() and + * glFramebufferTextureLayerEXT(). + * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll + * get textarget=0 in that case. */ static void framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, @@ -1729,41 +1991,24 @@ 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; + GLenum maxLevelsTarget; 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 (_mesa_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. */ @@ -1773,14 +2018,19 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, texObj = _mesa_lookup_texture(ctx, texture); if (texObj != NULL) { if (textarget == 0) { - /* XXX what's the purpose of this? */ + /* If textarget == 0 it means we're being called by + * glFramebufferTextureLayer() and textarget is not used. + * The only legal texture types for that function are 3D and + * 1D/2D arrays textures. + */ err = (texObj->Target != GL_TEXTURE_3D) && (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); } else { + /* Make sure textarget is consistent with the texture's type */ err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !IS_CUBE_FACE(textarget) + ? !_mesa_is_cube_face(textarget) : (texObj->Target != textarget); } } @@ -1809,15 +2059,17 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { - if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { + if (zoffset < 0 || + zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(layer)", caller); return; } } - if ((level < 0) || - (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { + maxLevelsTarget = textarget ? textarget : texObj->Target; + if ((level < 0) || + (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(level)", caller); return; @@ -1835,8 +2087,42 @@ 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 && + level == fb->Attachment[BUFFER_STENCIL].TextureLevel && + _mesa_tex_target_to_face(textarget) == + fb->Attachment[BUFFER_STENCIL].CubeMapFace && + zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) { + /* 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 && + level == fb->Attachment[BUFFER_DEPTH].TextureLevel && + _mesa_tex_target_to_face(textarget) == + fb->Attachment[BUFFER_DEPTH].CubeMapFace && + zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) { + /* As above, but with depth and stencil transposed. */ + 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 +2135,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 +2154,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 +2187,39 @@ _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 = _mesa_is_gles(ctx) + || !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 = (_mesa_is_gles(ctx) && ctx->Version < 30) + || !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 +2235,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 +2268,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 +2280,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, return; } - if (fb->Name == 0) { + if (_mesa_is_winsys_fbo(fb)) { /* Can't attach new renderbuffers to a window system framebuffer */ _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); return; @@ -2036,39 +2346,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 and GLES. */ + err = _mesa_is_desktop_gl(ctx) ? 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 (_mesa_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 (!_mesa_is_desktop_gl(ctx) || !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 +2408,8 @@ _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 = _mesa_is_winsys_fbo(buffer) + ? GL_FRAMEBUFFER_DEFAULT : att->Type; return; case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: if (att->Type == GL_RENDERBUFFER_EXT) { @@ -2111,16 +2420,23 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } else { assert(att->Type == GL_NONE); - *params = 0; + if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { + *params = 0; + } else { + goto invalid_pname_enum; + } } 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)"); + goto invalid_pname_enum; } return; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: @@ -2132,13 +2448,21 @@ _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)"); + goto invalid_pname_enum; } return; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - if (att->Type == GL_TEXTURE) { + if (ctx->API == API_OPENGLES) { + goto invalid_pname_enum; + } else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } else if (att->Type == GL_TEXTURE) { if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { *params = att->Zoffset; } @@ -2147,17 +2471,20 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } } else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); + goto invalid_pname_enum; } return; case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, + if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) + && !_mesa_is_gles3(ctx)) { + goto invalid_pname_enum; + } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, "glGetFramebufferAttachmentParameterivEXT(pname)"); } else { - if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { + if (ctx->Extensions.EXT_framebuffer_sRGB) { *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); } else { @@ -2168,17 +2495,30 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } return; case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, + if ((ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) + && ctx->API != API_OPENGL_CORE + && !_mesa_is_gles3(ctx)) { + goto invalid_pname_enum; + } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; } 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); } @@ -2190,8 +2530,12 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, + if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) + && !_mesa_is_gles3(ctx)) { + goto invalid_pname_enum; + } + else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, "glGetFramebufferAttachmentParameterivEXT(pname)"); } else if (att->Texture) { @@ -2211,21 +2555,30 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, att->Renderbuffer->Format); } else { - *params = 0; + _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" + " invalid FBO attachment structure"); } return; default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; + goto invalid_pname_enum; } + + return; + +invalid_pname_enum: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameteriv(pname)"); + return; } 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); @@ -2233,14 +2586,31 @@ _mesa_GenerateMipmapEXT(GLenum target) switch (target) { case GL_TEXTURE_1D: + error = _mesa_is_gles(ctx); + break; case GL_TEXTURE_2D: + error = GL_FALSE; + break; case GL_TEXTURE_3D: + error = ctx->API == API_OPENGLES; + break; case GL_TEXTURE_CUBE_MAP: - /* OK, legal value */ + error = !ctx->Extensions.ARB_texture_cube_map; + break; + case GL_TEXTURE_1D_ARRAY: + error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array; + break; + case GL_TEXTURE_2D_ARRAY: + error = (_mesa_is_gles(ctx) && ctx->Version < 30) + || !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 +2629,24 @@ _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); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGenerateMipmap(zero size base image)"); + return; + } + + if (_mesa_is_enum_format_integer(srcImage->InternalFormat) || + _mesa_is_depthstencil_format(srcImage->InternalFormat) || + _mesa_is_stencil_format(srcImage->InternalFormat)) { + _mesa_unlock_texture(ctx, texObj); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGenerateMipmap(invalid internal format)"); + return; + } + if (target == GL_TEXTURE_CUBE_MAP) { GLuint face; for (face = 0; face < 6; face++) @@ -2273,8 +2661,6 @@ _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) @@ -2288,6 +2674,155 @@ 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; +} + + +/** + * Return the equivalent non-generic internal format. + * This is useful for comparing whether two internal formats are semantically + * equivalent. + */ +static GLenum +get_nongeneric_internalformat(GLenum format) +{ + switch (format) { + /* GL 1.1 formats. */ + case 4: + case GL_RGBA: + return GL_RGBA8; + + case 3: + case GL_RGB: + return GL_RGB8; + + case 2: + case GL_LUMINANCE_ALPHA: + return GL_LUMINANCE8_ALPHA8; + + case 1: + case GL_LUMINANCE: + return GL_LUMINANCE8; + + case GL_ALPHA: + return GL_ALPHA8; + + case GL_INTENSITY: + return GL_INTENSITY8; + + /* GL_ARB_texture_rg */ + case GL_RED: + return GL_R8; + + case GL_RG: + return GL_RG8; + + /* GL_EXT_texture_sRGB */ + case GL_SRGB: + return GL_SRGB8; + + case GL_SRGB_ALPHA: + return GL_SRGB8_ALPHA8; + + case GL_SLUMINANCE: + return GL_SLUMINANCE8; + + case GL_SLUMINANCE_ALPHA: + return GL_SLUMINANCE8_ALPHA8; + + /* GL_EXT_texture_snorm */ + case GL_RGBA_SNORM: + return GL_RGBA8_SNORM; + + case GL_RGB_SNORM: + return GL_RGB8_SNORM; + + case GL_RG_SNORM: + return GL_RG8_SNORM; + + case GL_RED_SNORM: + return GL_R8_SNORM; + + case GL_LUMINANCE_ALPHA_SNORM: + return GL_LUMINANCE8_ALPHA8_SNORM; + + case GL_LUMINANCE_SNORM: + return GL_LUMINANCE8_SNORM; + + case GL_ALPHA_SNORM: + return GL_ALPHA8_SNORM; + + case GL_INTENSITY_SNORM: + return GL_INTENSITY8_SNORM; + + default: + return format; + } +} + + +static GLboolean +compatible_resolve_formats(const struct gl_renderbuffer *colorReadRb, + const struct gl_renderbuffer *colorDrawRb) +{ + /* The simple case where we know the backing formats are the same. + */ + if (_mesa_get_srgb_format_linear(colorReadRb->Format) == + _mesa_get_srgb_format_linear(colorDrawRb->Format)) { + return GL_TRUE; + } + + /* The Mesa formats are different, so we must check whether the internal + * formats are compatible. + * + * Under some circumstances, the user may request e.g. two GL_RGBA8 + * textures and get two entirely different Mesa formats like RGBA8888 and + * ARGB8888. Drivers behaving like that should be able to cope with + * non-matching formats by themselves, because it's not the user's fault. + */ + if (get_nongeneric_internalformat(colorReadRb->InternalFormat) == + get_nongeneric_internalformat(colorDrawRb->InternalFormat)) { + return GL_TRUE; + } + + return GL_FALSE; +} + /** * Blit rectangular region, optionally from one framebuffer to another. @@ -2353,7 +2888,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; } @@ -2361,33 +2896,75 @@ _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 (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { + /* There is no need to check the stencil datatype here, because + * there is only one: GL_UNSIGNED_INT. + */ _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(stencil buffer size mismatch"); + "glBlitFramebufferEXT(stencil buffer size 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 ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) || + (_mesa_get_format_datatype(readRb->Format) != + _mesa_get_format_datatype(drawRb->Format))) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth buffer size mismatch"); + "glBlitFramebufferEXT(depth buffer format mismatch)"); return; } } @@ -2396,26 +2973,39 @@ _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; } /* extra checks for multisample copies... */ if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { /* src and dest region sizes must be the same */ - if (srcX1 - srcX0 != dstX1 - dstX0 || - srcY1 - srcY0 != dstY1 - dstY0) { + if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || + abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes"); + "glBlitFramebufferEXT(bad src/dst multisample region sizes)"); return; } /* color formats must match */ if (colorReadRb && colorDrawRb && - colorReadRb->Format != colorDrawRb->Format) { + !compatible_resolve_formats(colorReadRb, colorDrawRb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "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(bad src/dst multisample pixel formats"); + "glBlitFramebufferEXT(integer color type)"); return; } } @@ -2463,32 +3053,155 @@ _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, dstX0, dstY0, dstX1, dstY1, mask, filter); } -#endif /* FEATURE_EXT_framebuffer_blit */ -#if FEATURE_ARB_geometry_shader4 -void GLAPIENTRY -_mesa_FramebufferTextureARB(GLenum target, GLenum attachment, - GLuint texture, GLint level) + +static void +invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, + const GLenum *attachments, GLint x, GLint y, + GLsizei width, GLsizei height, const char *name) { + int i; + struct gl_framebuffer *fb; GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureARB " - "not implemented!"); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name); + return; + } + + if (numAttachments < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(numAttachments < 0)", name); + return; + } + + /* The GL_ARB_invalidate_subdata spec says: + * + * "If an attachment is specified that does not exist in the + * framebuffer bound to , it is ignored." + * + * It also says: + * + * "If contains COLOR_ATTACHMENTm and m is greater than + * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error + * INVALID_OPERATION is generated." + * + * No mention is made of GL_AUXi being out of range. Therefore, we allow + * any enum that can be allowed by the API (OpenGL ES 3.0 has a different + * set of retrictions). + */ + for (i = 0; i < numAttachments; i++) { + if (_mesa_is_winsys_fbo(fb)) { + switch (attachments[i]) { + case GL_ACCUM: + case GL_AUX0: + case GL_AUX1: + case GL_AUX2: + case GL_AUX3: + /* Accumulation buffers and auxilary buffers were removed in + * OpenGL 3.1, and they never existed in OpenGL ES. + */ + if (ctx->API != API_OPENGL) + goto invalid_enum; + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + break; + case GL_BACK_LEFT: + case GL_BACK_RIGHT: + case GL_FRONT_LEFT: + case GL_FRONT_RIGHT: + if (!_mesa_is_desktop_gl(ctx)) + goto invalid_enum; + break; + default: + goto invalid_enum; + } + } else { + switch (attachments[i]) { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + case GL_COLOR_ATTACHMENT0: + case GL_COLOR_ATTACHMENT1: + case GL_COLOR_ATTACHMENT2: + case GL_COLOR_ATTACHMENT3: + case GL_COLOR_ATTACHMENT4: + case GL_COLOR_ATTACHMENT5: + case GL_COLOR_ATTACHMENT6: + case GL_COLOR_ATTACHMENT7: + case GL_COLOR_ATTACHMENT8: + case GL_COLOR_ATTACHMENT9: + case GL_COLOR_ATTACHMENT10: + case GL_COLOR_ATTACHMENT11: + case GL_COLOR_ATTACHMENT12: + case GL_COLOR_ATTACHMENT13: + case GL_COLOR_ATTACHMENT14: + case GL_COLOR_ATTACHMENT15: { + unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0; + if (k >= ctx->Const.MaxColorAttachments) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(attachment >= max. color attachments)", name); + return; + } + } + default: + goto invalid_enum; + } + } + } + + /* We don't actually do anything for this yet. Just return after + * validating the parameters and generating the required errors. + */ + return; + +invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name); + return; } void GLAPIENTRY -_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLenum face) +_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum *attachments, GLint x, GLint y, + GLsizei width, GLsizei height) { - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureFaceARB " - "not implemented!"); + invalidate_framebuffer_storage(target, numAttachments, attachments, + x, y, width, height, + "glInvalidateSubFramebuffer"); +} + +void GLAPIENTRY +_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum *attachments) +{ + /* The GL_ARB_invalidate_subdata spec says: + * + * "The command + * + * void InvalidateFramebuffer(enum target, + * sizei numAttachments, + * const enum *attachments); + * + * is equivalent to the command InvalidateSubFramebuffer with , , + * , equal to 0, 0, , + * respectively." + */ + invalidate_framebuffer_storage(target, numAttachments, attachments, + 0, 0, MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, + "glInvalidateFramebuffer"); } -#endif /* FEATURE_ARB_geometry_shader4 */