X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=0758d55574a886bf6ff76ea5023265a4fd49dc06;hb=406df38a6673cb7d19ce652f71fac1047b2279d0;hp=bcebf12400158e00deb491b05a0d884508e4e688;hpb=d8ba30af11f1894fcdd9138a8bc71ff054932bb6;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index bcebf124001..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,34 +76,6 @@ static struct gl_renderbuffer DummyRenderbuffer; static struct gl_framebuffer IncompleteFramebuffer; -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 delete_dummy_renderbuffer(struct gl_renderbuffer *rb) { @@ -194,10 +164,10 @@ 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 + return ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx) ? ctx->DrawBuffer : NULL; case GL_READ_FRAMEBUFFER: - return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL + return ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx) ? ctx->ReadBuffer : NULL; case GL_FRAMEBUFFER_EXT: return ctx->DrawBuffer; @@ -221,7 +191,7 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, { GLuint i; - assert(is_user_fbo(fb)); + assert(_mesa_is_user_fbo(fb)); switch (attachment) { case GL_COLOR_ATTACHMENT0_EXT: @@ -251,7 +221,7 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, } return &fb->Attachment[BUFFER_COLOR0 + i]; case GL_DEPTH_STENCIL_ATTACHMENT: - if (ctx->API != API_OPENGL) + if (!_mesa_is_desktop_gl(ctx)) return NULL; /* fall-through */ case GL_DEPTH_ATTACHMENT_EXT: @@ -272,7 +242,7 @@ static struct gl_renderbuffer_attachment * _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, GLenum attachment) { - assert(is_winsys_fbo(fb)); + assert(_mesa_is_winsys_fbo(fb)); switch (attachment) { case GL_FRONT_LEFT: @@ -489,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); + } } @@ -503,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); + } } @@ -718,7 +683,10 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, GLint i; GLuint j; - assert(is_user_fbo(fb)); + assert(_mesa_is_user_fbo(fb)); + + /* we're changing framebuffer fields here */ + FLUSH_VERTICES(ctx, _NEW_BUFFERS); numImages = 0; fb->Width = 0; @@ -826,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); @@ -838,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 && !ctx->Extensions.ARB_ES2_compatibility) { + 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) { @@ -871,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; @@ -1017,10 +989,10 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } - if (is_user_fbo(ctx->DrawBuffer)) { + if (_mesa_is_user_fbo(ctx->DrawBuffer)) { detach_renderbuffer(ctx, ctx->DrawBuffer, rb); } - if (is_user_fbo(ctx->ReadBuffer) + if (_mesa_is_user_fbo(ctx->ReadBuffer) && ctx->ReadBuffer != ctx->DrawBuffer) { detach_renderbuffer(ctx, ctx->ReadBuffer, rb); } @@ -1099,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: @@ -1113,139 +1087,190 @@ _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: + 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: - if (ctx->Extensions.ARB_depth_buffer_float) - return GL_DEPTH_COMPONENT; - else - return 0; + return ctx->Version >= 30 + || (ctx->API == API_OPENGL && ctx->Extensions.ARB_depth_buffer_float) + ? GL_DEPTH_COMPONENT : 0; case GL_DEPTH32F_STENCIL8: - if (ctx->Extensions.ARB_depth_buffer_float) - return GL_DEPTH_STENCIL; - else - return 0; + 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; + 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_RED_SNORM: 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 ctx->Extensions.EXT_texture_snorm ? GL_RED : 0; - case GL_RG_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 ctx->Extensions.EXT_texture_snorm ? GL_RG : 0; - case GL_RGB_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 ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0; - case GL_RGBA_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 ctx->Extensions.EXT_texture_snorm ? GL_RGBA : 0; + 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->Extensions.EXT_texture_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->Extensions.EXT_texture_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->Extensions.EXT_texture_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->Extensions.EXT_texture_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->Extensions.ARB_texture_rg && - ctx->Extensions.ARB_texture_float ? GL_RED : 0; + 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->Extensions.ARB_texture_rg && - ctx->Extensions.ARB_texture_float ? GL_RG : 0; + 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 ctx->Extensions.ARB_texture_float ? GL_RGB : 0; + 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 ctx->Extensions.ARB_texture_float ? GL_RGBA : 0; + 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->Extensions.ARB_texture_float && + 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->Extensions.ARB_texture_float && + 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->Extensions.ARB_texture_float && + 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->Extensions.ARB_texture_float && + return ctx->API == API_OPENGL && + 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; + 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 ctx->Extensions.EXT_packed_float ? GL_RGB : 0; + 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: @@ -1253,7 +1278,9 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGBA8I_EXT: case GL_RGBA16I_EXT: case GL_RGBA32I_EXT: - return ctx->Extensions.EXT_texture_integer ? GL_RGBA : 0; + 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: @@ -1261,7 +1288,9 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGB8I_EXT: case GL_RGB16I_EXT: case GL_RGB32I_EXT: - return ctx->Extensions.EXT_texture_integer ? GL_RGB : 0; + return ctx->Version >= 30 + || (_mesa_is_desktop_gl(ctx) && + ctx->Extensions.EXT_texture_integer) ? GL_RGB : 0; case GL_R8UI: case GL_R8I: @@ -1269,8 +1298,10 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_R16I: case GL_R32UI: case GL_R32I: - return ctx->Extensions.ARB_texture_rg && - ctx->Extensions.EXT_texture_integer ? GL_RED : 0; + 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: @@ -1278,16 +1309,19 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RG16I: case GL_RG32UI: case GL_RG32I: - return ctx->Extensions.ARB_texture_rg && - ctx->Extensions.EXT_texture_integer ? GL_RG : 0; - + 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->Extensions.EXT_texture_integer && + return ctx->API == API_OPENGL && + ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; case GL_LUMINANCE8I_EXT: @@ -1296,7 +1330,8 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_LUMINANCE16UI_EXT: case GL_LUMINANCE32I_EXT: case GL_LUMINANCE32UI_EXT: - return ctx->Extensions.EXT_texture_integer && + return ctx->API == API_OPENGL && + ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; case GL_LUMINANCE_ALPHA8I_EXT: @@ -1305,8 +1340,28 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_LUMINANCE_ALPHA16UI_EXT: case GL_LUMINANCE_ALPHA32I_EXT: case GL_LUMINANCE_ALPHA32UI_EXT: - return ctx->Extensions.EXT_texture_integer && + 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; } @@ -1323,7 +1378,7 @@ invalidate_rb(GLuint key, void *data, void *userData) struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; /* If this is a user-created FBO */ - if (is_user_fbo(fb)) { + if (_mesa_is_user_fbo(fb)) { GLuint i; for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; @@ -1400,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; } @@ -1413,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; @@ -1437,7 +1493,6 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, } -#if FEATURE_OES_EGL_image void GLAPIENTRY _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) { @@ -1468,7 +1523,6 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); } -#endif /** @@ -1482,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; - } } @@ -1614,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; } @@ -1652,7 +1669,7 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) GLuint i; ASSERT(ctx->Driver.RenderTexture); - if (is_winsys_fbo(fb)) + if (_mesa_is_winsys_fbo(fb)) return; /* can't render to texture with winsys framebuffers */ for (i = 0; i < BUFFER_COUNT; i++) { @@ -1672,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 (is_winsys_fbo(fb)) + if (_mesa_is_winsys_fbo(fb)) return; /* can't render to texture with winsys framebuffers */ if (ctx->Driver.FinishRenderTexture) { @@ -1711,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)"); @@ -1728,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; @@ -1807,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 */ @@ -1862,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 */ @@ -1925,7 +1937,7 @@ _mesa_CheckFramebufferStatusEXT(GLenum target) return 0; } - if (is_winsys_fbo(buffer)) { + if (_mesa_is_winsys_fbo(buffer)) { /* The window system / default framebuffer is always complete */ return GL_FRAMEBUFFER_COMPLETE_EXT; } @@ -1940,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, @@ -1952,6 +1991,7 @@ 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; + GLenum maxLevelsTarget; ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1963,13 +2003,12 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } /* check framebuffer binding */ - if (is_winsys_fbo(fb)) { + 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. */ @@ -1979,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); } } @@ -2015,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; @@ -2041,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. @@ -2055,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); @@ -2111,7 +2195,8 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, error = GL_FALSE; break; case GL_TEXTURE_RECTANGLE: - error = !ctx->Extensions.NV_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: @@ -2122,7 +2207,8 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, error = !ctx->Extensions.ARB_texture_cube_map; break; case GL_TEXTURE_2D_ARRAY: - error = !ctx->Extensions.EXT_texture_array; + error = (_mesa_is_gles(ctx) && ctx->Version < 30) + || !ctx->Extensions.EXT_texture_array; break; default: error = GL_TRUE; @@ -2194,7 +2280,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, return; } - if (is_winsys_fbo(fb)) { + if (_mesa_is_winsys_fbo(fb)) { /* Can't attach new renderbuffers to a window system framebuffer */ _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); return; @@ -2265,8 +2351,8 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, ASSERT_OUTSIDE_BEGIN_END(ctx); - /* The error differs in GL andd GLES. */ - err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + /* 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) { @@ -2275,7 +2361,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, return; } - if (is_winsys_fbo(buffer)) { + if (_mesa_is_winsys_fbo(buffer)) { /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec * says: * @@ -2286,7 +2372,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, * OES_framebuffer_object spec refers to the EXT_framebuffer_object * spec. */ - if (ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) { + if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); return; @@ -2322,7 +2408,8 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = is_winsys_fbo(buffer) ? 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) { @@ -2333,11 +2420,10 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } else { assert(att->Type == GL_NONE); - if (ctx->API == API_OPENGL) { + if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { *params = 0; } else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); + goto invalid_pname_enum; } } return; @@ -2350,8 +2436,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, "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: @@ -2368,12 +2453,16 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, "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; } @@ -2381,26 +2470,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_COLOR_ENCODING: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); + 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 { @@ -2411,10 +2495,10 @@ _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, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; + 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, @@ -2446,9 +2530,9 @@ _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, - "glGetFramebufferAttachmentParameterivEXT(pname)"); + 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, @@ -2476,10 +2560,15 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } 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; } @@ -2497,16 +2586,23 @@ _mesa_GenerateMipmapEXT(GLenum target) switch (target) { case GL_TEXTURE_1D: + error = _mesa_is_gles(ctx); + break; case GL_TEXTURE_2D: - case GL_TEXTURE_3D: error = GL_FALSE; break; + case GL_TEXTURE_3D: + error = ctx->API == API_OPENGLES; + break; case GL_TEXTURE_CUBE_MAP: 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 = !ctx->Extensions.EXT_texture_array; + error = (_mesa_is_gles(ctx) && ctx->Version < 30) + || !ctx->Extensions.EXT_texture_array; break; default: error = GL_TRUE; @@ -2537,6 +2633,17 @@ _mesa_GenerateMipmapEXT(GLenum target) 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; } @@ -2554,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) @@ -2569,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. @@ -2653,14 +2907,22 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 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; + struct gl_renderbuffer *readRb = + readFb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer *drawRb = + drawFb->Attachment[BUFFER_STENCIL].Renderbuffer; /* From the EXT_framebuffer_object spec: * @@ -2669,11 +2931,13 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * 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)) { + /* 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)"); return; @@ -2681,8 +2945,10 @@ _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; + struct gl_renderbuffer *readRb = + readFb->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *drawRb = + drawFb->Attachment[BUFFER_DEPTH].Renderbuffer; /* From the EXT_framebuffer_object spec: * @@ -2691,13 +2957,14 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * 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)) { + 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; } } @@ -2706,15 +2973,15 @@ _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)"); return; @@ -2723,13 +2990,26 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, /* 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(integer color type)"); + return; + } + } + if (!ctx->Extensions.EXT_framebuffer_blit) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); return; @@ -2783,26 +3063,145 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint 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 */