X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=9dd71612f97de095359fdf572d3f252802a35159;hb=5f76bc37abe39bad8ad99a51864f8beda0f6d3d7;hp=891ec5dcefb3af502ea41fa168bb88186c2a21cc;hpb=91ca053714957aca5205122e8478002c62cc4344;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 891ec5dcefb..9dd71612f97 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 7.1 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. @@ -18,9 +17,10 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ @@ -42,7 +42,7 @@ #include "glformats.h" #include "hash.h" #include "macros.h" -#include "mfeatures.h" +#include "multisample.h" #include "mtypes.h" #include "renderbuffer.h" #include "state.h" @@ -78,7 +78,7 @@ static struct gl_framebuffer IncompleteFramebuffer; static void -delete_dummy_renderbuffer(struct gl_renderbuffer *rb) +delete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { /* no op */ } @@ -222,7 +222,7 @@ _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, } return &fb->Attachment[BUFFER_COLOR0 + i]; case GL_DEPTH_STENCIL_ATTACHMENT: - if (!_mesa_is_desktop_gl(ctx)) + if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) return NULL; /* fall-through */ case GL_DEPTH_ATTACHMENT_EXT: @@ -245,6 +245,25 @@ _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, { assert(_mesa_is_winsys_fbo(fb)); + if (_mesa_is_gles3(ctx)) { + assert(attachment == GL_BACK || + attachment == GL_DEPTH || + attachment == GL_STENCIL); + switch (attachment) { + case GL_BACK: + /* Since there is no stereo rendering in ES 3.0, only return the + * LEFT bits. + */ + if (ctx->DrawBuffer->Visual.doubleBufferMode) + return &fb->Attachment[BUFFER_BACK_LEFT]; + return &fb->Attachment[BUFFER_FRONT_LEFT]; + case GL_DEPTH: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL: + return &fb->Attachment[BUFFER_STENCIL]; + } + } + switch (attachment) { case GL_FRONT_LEFT: return &fb->Attachment[BUFFER_FRONT_LEFT]; @@ -303,12 +322,14 @@ void _mesa_remove_attachment(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) { + struct gl_renderbuffer *rb = att->Renderbuffer; + + /* tell driver that we're done rendering to this texture. */ + if (rb && rb->NeedsFinishRenderTexture) + ctx->Driver.FinishRenderTexture(ctx, rb); + if (att->Type == GL_TEXTURE) { ASSERT(att->Texture); - if (ctx->Driver.FinishRenderTexture) { - /* tell driver that we're done rendering to this texture. */ - ctx->Driver.FinishRenderTexture(ctx, att); - } _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ ASSERT(!att->Texture); } @@ -321,6 +342,81 @@ _mesa_remove_attachment(struct gl_context *ctx, att->Complete = GL_TRUE; } +/** + * Verify a couple error conditions that will lead to an incomplete FBO and + * may cause problems for the driver's RenderTexture path. + */ +static bool +driver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att) +{ + const struct gl_texture_image *const texImage = + att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + + if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) + return false; + + if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY + && att->Zoffset >= texImage->Height) + || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY + && att->Zoffset >= texImage->Depth)) + return false; + + return true; +} + +/** + * Create a renderbuffer which will be set up by the driver to wrap the + * texture image slice. + * + * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get + * to share most of their framebuffer rendering code between winsys, + * renderbuffer, and texture attachments. + * + * The allocated renderbuffer uses a non-zero Name so that drivers can check + * it for determining vertical orientation, but we use ~0 to make it fairly + * unambiguous with actual user (non-texture) renderbuffers. + */ +void +_mesa_update_texture_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att) +{ + struct gl_texture_image *texImage; + struct gl_renderbuffer *rb; + + texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + + rb = att->Renderbuffer; + if (!rb) { + rb = ctx->Driver.NewRenderbuffer(ctx, ~0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); + return; + } + _mesa_reference_renderbuffer(&att->Renderbuffer, rb); + + /* This can't get called on a texture renderbuffer, so set it to NULL + * for clarity compared to user renderbuffers. + */ + rb->AllocStorage = NULL; + + rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL; + } + + if (!texImage) + return; + + rb->_BaseFormat = texImage->_BaseFormat; + rb->Format = texImage->TexFormat; + rb->InternalFormat = texImage->InternalFormat; + rb->Width = texImage->Width2; + rb->Height = texImage->Height2; + rb->NumSamples = texImage->NumSamples; + rb->TexImage = texImage; + + if (driver_RenderTexture_is_safe(att)) + ctx->Driver.RenderTexture(ctx, fb, att); +} /** * Bind a texture object to an attachment point. @@ -331,35 +427,35 @@ _mesa_set_texture_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att, struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset) + GLenum texTarget, GLuint level, GLuint zoffset, + GLboolean layered) { + struct gl_renderbuffer *rb = att->Renderbuffer; + + if (rb && rb->NeedsFinishRenderTexture) + ctx->Driver.FinishRenderTexture(ctx, rb); + if (att->Texture == texObj) { /* re-attaching same texture */ ASSERT(att->Type == GL_TEXTURE); - if (ctx->Driver.FinishRenderTexture) - ctx->Driver.FinishRenderTexture(ctx, att); } else { /* new attachment */ - if (ctx->Driver.FinishRenderTexture && att->Texture) - ctx->Driver.FinishRenderTexture(ctx, att); _mesa_remove_attachment(ctx, att); att->Type = GL_TEXTURE; assert(!att->Texture); _mesa_reference_texobj(&att->Texture, texObj); } + invalidate_framebuffer(fb); /* always update these fields */ att->TextureLevel = level; att->CubeMapFace = _mesa_tex_target_to_face(texTarget); att->Zoffset = zoffset; + att->Layered = layered; att->Complete = GL_FALSE; - if (_mesa_get_attachment_teximage(att)) { - ctx->Driver.RenderTexture(ctx, fb, att); - } - - invalidate_framebuffer(fb); + _mesa_update_texture_renderbuffer(ctx, fb, att); } @@ -454,6 +550,32 @@ _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) } +/** + * Return true if the framebuffer has a combined depth/stencil + * renderbuffer attached. + */ +GLboolean +_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb) +{ + const struct gl_renderbuffer_attachment *depth = + &fb->Attachment[BUFFER_DEPTH]; + const struct gl_renderbuffer_attachment *stencil = + &fb->Attachment[BUFFER_STENCIL]; + + if (depth->Type == stencil->Type) { + if (depth->Type == GL_RENDERBUFFER_EXT && + depth->Renderbuffer == stencil->Renderbuffer) + return GL_TRUE; + + if (depth->Type == GL_TEXTURE && + depth->Texture == stencil->Texture) + return GL_TRUE; + } + + return GL_FALSE; +} + + /** * For debug only. */ @@ -470,8 +592,15 @@ att_incomplete(const char *msg) * For debug only. */ static void -fbo_incomplete(const char *msg, int index) +fbo_incomplete(struct gl_context *ctx, const char *msg, int index) { + static GLuint msg_id; + + _mesa_gl_debug(ctx, &msg_id, + MESA_DEBUG_TYPE_OTHER, + MESA_DEBUG_SEVERITY_MEDIUM, + "FBO incomplete: %s [%d]\n", msg, index); + if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); } @@ -492,7 +621,8 @@ _mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) case GL_LUMINANCE_ALPHA: case GL_INTENSITY: case GL_ALPHA: - return ctx->Extensions.ARB_framebuffer_object; + return ctx->API == API_OPENGL_COMPAT && + ctx->Extensions.ARB_framebuffer_object; case GL_RED: case GL_RG: return ctx->Extensions.ARB_texture_rg; @@ -502,6 +632,50 @@ _mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) } +/** + * Is the given base format a legal format for a color renderbuffer? + */ +static GLboolean +is_format_color_renderable(const struct gl_context *ctx, gl_format format, GLenum internalFormat) +{ + const GLenum baseFormat = + _mesa_get_format_base_format(format); + GLboolean valid; + + valid = _mesa_is_legal_color_format(ctx, baseFormat); + if (!valid || _mesa_is_desktop_gl(ctx)) { + return valid; + } + + /* Reject additional cases for GLES */ + switch (internalFormat) { + case GL_RGBA8_SNORM: + case GL_RGB32F: + case GL_RGB32I: + case GL_RGB32UI: + case GL_RGB16F: + case GL_RGB16I: + case GL_RGB16UI: + case GL_RGB8_SNORM: + case GL_RGB8I: + case GL_RGB8UI: + case GL_SRGB8: + case GL_RGB9_E5: + case GL_RG8_SNORM: + case GL_R8_SNORM: + return GL_FALSE; + default: + break; + } + + if (format == MESA_FORMAT_ARGB2101010 && internalFormat != GL_RGB10_A2) { + return GL_FALSE; + } + + return GL_TRUE; +} + + /** * Is the given base format a legal format for a depth/stencil renderbuffer? */ @@ -553,15 +727,39 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, } if (texImage->Width < 1 || texImage->Height < 1) { att_incomplete("teximage width/height=0"); - printf("texobj = %u\n", texObj->Name); - printf("level = %d\n", att->TextureLevel); att->Complete = GL_FALSE; return; } - if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { - att_incomplete("bad z offset"); - att->Complete = GL_FALSE; - return; + + switch (texObj->Target) { + case GL_TEXTURE_3D: + if (att->Zoffset >= texImage->Depth) { + att_incomplete("bad z offset"); + att->Complete = GL_FALSE; + return; + } + break; + case GL_TEXTURE_1D_ARRAY: + if (att->Zoffset >= texImage->Height) { + att_incomplete("bad 1D-array layer"); + att->Complete = GL_FALSE; + return; + } + break; + case GL_TEXTURE_2D_ARRAY: + if (att->Zoffset >= texImage->Depth) { + att_incomplete("bad 2D-array layer"); + att->Complete = GL_FALSE; + return; + } + break; + case GL_TEXTURE_CUBE_MAP_ARRAY: + if (att->Zoffset >= texImage->Depth) { + att_incomplete("bad cube-array layer"); + att->Complete = GL_FALSE; + return; + } + break; } baseFormat = _mesa_get_format_base_format(texImage->TexFormat); @@ -681,8 +879,11 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, GLenum intFormat = GL_NONE; /* color buffers' internal format */ GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; GLint numSamples = -1; + GLint fixedSampleLocations = -1; GLint i; GLuint j; + bool layer_count_valid = false; + GLuint layer_count = 0, att_layer_count; assert(_mesa_is_user_fbo(fb)); @@ -692,6 +893,8 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, numImages = 0; fb->Width = 0; fb->Height = 0; + fb->_AllColorBuffersFixedPoint = GL_TRUE; + fb->_HasSNormOrFloatColorBuffer = GL_FALSE; /* Start at -2 to more easily loop over all attachment points. * -2: depth buffer @@ -715,7 +918,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, test_attachment_completeness(ctx, GL_DEPTH, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("depth attachment incomplete", -1); + fbo_incomplete(ctx, "depth attachment incomplete", -1); return; } } @@ -724,7 +927,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, test_attachment_completeness(ctx, GL_STENCIL, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("stencil attachment incomplete", -1); + fbo_incomplete(ctx, "stencil attachment incomplete", -1); return; } } @@ -733,7 +936,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, test_attachment_completeness(ctx, GL_COLOR, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("color attachment incomplete", i); + fbo_incomplete(ctx, "color attachment incomplete", i); return; } } @@ -741,8 +944,7 @@ _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 = - _mesa_get_attachment_teximage(att); + const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; minWidth = MIN2(minWidth, texImg->Width); maxWidth = MAX2(maxWidth, texImg->Width); minHeight = MIN2(minHeight, texImg->Height); @@ -750,10 +952,27 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, f = texImg->_BaseFormat; attFormat = texImg->TexFormat; numImages++; - if (!_mesa_is_legal_color_format(ctx, f) && + + if (!is_format_color_renderable(ctx, attFormat, texImg->InternalFormat) && !is_legal_depth_format(ctx, f)) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - fbo_incomplete("texture attachment incomplete", -1); + fbo_incomplete(ctx, "texture attachment incomplete", -1); + return; + } + + if (numSamples < 0) + numSamples = texImg->NumSamples; + else if (numSamples != texImg->NumSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample count", -1); + return; + } + + if (fixedSampleLocations < 0) + fixedSampleLocations = texImg->FixedSampleLocations; + else if (fixedSampleLocations != texImg->FixedSampleLocations) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); return; } } @@ -765,24 +984,48 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, f = att->Renderbuffer->InternalFormat; attFormat = att->Renderbuffer->Format; numImages++; + + if (numSamples < 0) + numSamples = att->Renderbuffer->NumSamples; + else if (numSamples != att->Renderbuffer->NumSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample count", -1); + return; + } + + /* RENDERBUFFER has fixedSampleLocations implicitly true */ + if (fixedSampleLocations < 0) + fixedSampleLocations = GL_TRUE; + else if (fixedSampleLocations != GL_TRUE) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); + return; + } } else { assert(att->Type == GL_NONE); continue; } - if (att->Renderbuffer && numSamples < 0) { - /* first buffer */ - numSamples = att->Renderbuffer->NumSamples; - } - /* check if integer color */ fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); - /* Error-check width, height, format, samples - */ + /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */ + if (i >= 0) { + GLenum type = _mesa_get_format_datatype(attFormat); + + fb->_AllColorBuffersFixedPoint = + fb->_AllColorBuffersFixedPoint && + (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); + + fb->_HasSNormOrFloatColorBuffer = + fb->_HasSNormOrFloatColorBuffer || + type == GL_SIGNED_NORMALIZED || type == GL_FLOAT; + } + + /* Error-check width, height, format */ if (numImages == 1) { - /* save format, num samples */ + /* save format */ if (i >= 0) { intFormat = f; } @@ -792,22 +1035,16 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, /* check that width, height, format are same */ if (minWidth != maxWidth || minHeight != maxHeight) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; - fbo_incomplete("width or height mismatch", -1); + fbo_incomplete(ctx, "width or height mismatch", -1); return; } /* 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); + fbo_incomplete(ctx, "format mismatch", -1); return; } } - if (att->Renderbuffer && - att->Renderbuffer->NumSamples != numSamples) { - 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) @@ -815,11 +1052,29 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, if (att->Type == GL_RENDERBUFFER && att->Renderbuffer->Format == MESA_FORMAT_NONE) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; - fbo_incomplete("unsupported renderbuffer format", i); + fbo_incomplete(ctx, "unsupported renderbuffer format", i); + return; + } + + /* Check that layered rendering is consistent. */ + att_layer_count = att->Layered ? att->Renderbuffer->Depth : 0; + if (!layer_count_valid) { + layer_count = att_layer_count; + layer_count_valid = true; + } else if (layer_count != att_layer_count) { + if (layer_count == 0 || att_layer_count == 0) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; + fbo_incomplete(ctx, "framebuffer attachment layer mode is inconsistent", i); + } else { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB; + fbo_incomplete(ctx, "framebuffer attachment layer count is inconsistent", i); + } return; } } + fb->Layered = layer_count > 0; + 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++) { @@ -829,7 +1084,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; - fbo_incomplete("missing drawbuffer", j); + fbo_incomplete(ctx, "missing drawbuffer", j); return; } } @@ -842,7 +1097,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; - fbo_incomplete("missing readbuffer", -1); + fbo_incomplete(ctx, "missing readbuffer", -1); return; } } @@ -850,7 +1105,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, if (numImages == 0) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; - fbo_incomplete("no attachments", -1); + fbo_incomplete(ctx, "no attachments", -1); return; } @@ -864,7 +1119,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, if (ctx->Driver.ValidateFramebuffer) { ctx->Driver.ValidateFramebuffer(ctx, fb); if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - fbo_incomplete("driver marked FBO as incomplete", -1); + fbo_incomplete(ctx, "driver marked FBO as incomplete", -1); } } @@ -897,14 +1152,12 @@ _mesa_IsRenderbuffer(GLuint renderbuffer) } -void GLAPIENTRY -_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) +static void +bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) { struct gl_renderbuffer *newRb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (target != GL_RENDERBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); return; @@ -920,7 +1173,7 @@ _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) /* ID was reserved, but no real renderbuffer object made yet */ newRb = NULL; } - else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { + else if (!newRb && !allow_user_names) { /* All RB IDs must be Gen'd */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); return; @@ -947,25 +1200,68 @@ _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); } +void GLAPIENTRY +_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + GET_CURRENT_CONTEXT(ctx); + + /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same + * entry point, but they allow the use of user-generated names. + */ + bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx)); +} + +void GLAPIENTRY +_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) +{ + /* This function should not be in the dispatch table for core profile / + * OpenGL 3.1, so execution should never get here in those cases -- no + * need for an explicit test. + */ + bind_renderbuffer(target, renderbuffer, true); +} + /** - * If the given renderbuffer is anywhere attached to the framebuffer, detach - * the renderbuffer. - * This is used when a renderbuffer object is deleted. - * The spec calls for unbinding. + * Remove the specified renderbuffer or texture from any attachment point in + * the framebuffer. + * + * \returns + * \c true if the renderbuffer was detached from an attachment point. \c + * false otherwise. */ -static void -detach_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - struct gl_renderbuffer *rb) +bool +_mesa_detach_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + const void *att) { - GLuint i; + unsigned i; + bool progress = false; + for (i = 0; i < BUFFER_COUNT; i++) { - if (fb->Attachment[i].Renderbuffer == rb) { + if (fb->Attachment[i].Texture == att + || fb->Attachment[i].Renderbuffer == att) { _mesa_remove_attachment(ctx, &fb->Attachment[i]); + progress = true; } } - invalidate_framebuffer(fb); + + /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer + * Completeness," of the OpenGL 3.1 spec says: + * + * "Performing any of the following actions may change whether the + * framebuffer is considered complete or incomplete: + * + * ... + * + * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object + * containing an image that is attached to a framebuffer object + * that is bound to the framebuffer." + */ + if (progress) + invalidate_framebuffer(fb); + + return progress; } @@ -975,7 +1271,6 @@ _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) GLint i; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_BUFFERS); for (i = 0; i < n; i++) { @@ -990,12 +1285,29 @@ _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0); } + /* Section 4.4.2 (Attaching Images to Framebuffer Objects), + * subsection "Attaching Renderbuffer Images to a Framebuffer," of + * the OpenGL 3.1 spec says: + * + * "If a renderbuffer object is deleted while its image is + * attached to one or more attachment points in the currently + * bound framebuffer, then it is as if FramebufferRenderbuffer + * had been called, with a renderbuffer of 0, for each + * attachment point to which this image was attached in the + * currently bound framebuffer. In other words, this + * renderbuffer image is first detached from all attachment + * points in the currently bound framebuffer. Note that the + * renderbuffer image is specifically not detached from any + * non-bound framebuffers. Detaching the image from any + * non-bound framebuffers is the responsibility of the + * application. + */ if (_mesa_is_user_fbo(ctx->DrawBuffer)) { - detach_renderbuffer(ctx, ctx->DrawBuffer, rb); + _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb); } if (_mesa_is_user_fbo(ctx->ReadBuffer) && ctx->ReadBuffer != ctx->DrawBuffer) { - detach_renderbuffer(ctx, ctx->ReadBuffer, rb); + _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb); } /* Remove from hash table immediately, to free the ID. @@ -1021,8 +1333,6 @@ _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) GLuint first; GLint i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); return; @@ -1072,14 +1382,14 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: - return ctx->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + return ctx->API == API_OPENGL_COMPAT && 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->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE4_ALPHA4: @@ -1088,14 +1398,14 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_LUMINANCE12_ALPHA4: case GL_LUMINANCE12_ALPHA12: case GL_LUMINANCE16_ALPHA16: - return ctx->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + return ctx->API == API_OPENGL_COMPAT && 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->API == API_OPENGL && ctx->Extensions.ARB_framebuffer_object + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; case GL_RGB8: return GL_RGB; @@ -1108,7 +1418,7 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGB16: return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; case GL_SRGB8_EXT: - return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGB : 0; + return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: @@ -1146,11 +1456,11 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) ? GL_DEPTH_STENCIL_EXT : 0; case GL_DEPTH_COMPONENT32F: return ctx->Version >= 30 - || (ctx->API == API_OPENGL && ctx->Extensions.ARB_depth_buffer_float) + || (ctx->API == API_OPENGL_COMPAT && 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) + || (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float) ? GL_DEPTH_STENCIL : 0; case GL_RED: case GL_R16: @@ -1167,111 +1477,84 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) 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_R8_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_RG8_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_RGB8_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_RGBA8_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 && + return ctx->API == API_OPENGL_COMPAT && 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; + return ((_mesa_is_desktop_gl(ctx) && + ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float) || + _mesa_is_gles3(ctx) /* EXT_color_buffer_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; + return ((_mesa_is_desktop_gl(ctx) && + ctx->Extensions.ARB_texture_rg && + ctx->Extensions.ARB_texture_float) || + _mesa_is_gles3(ctx) /* EXT_color_buffer_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) + return ((_mesa_is_desktop_gl(ctx) && + ctx->Extensions.ARB_texture_float) || + _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) ? GL_RGBA : 0; case GL_ALPHA16F_ARB: case GL_ALPHA32F_ARB: - return ctx->API == API_OPENGL && + return ctx->API == API_OPENGL_COMPAT && 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 && + return ctx->API == API_OPENGL_COMPAT && 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 && + return ctx->API == API_OPENGL_COMPAT && 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 && + return ctx->API == API_OPENGL_COMPAT && 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; + ? 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; + return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) || + _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) + ? GL_RGB : 0; case GL_RGBA8UI_EXT: case GL_RGBA16UI_EXT: @@ -1289,10 +1572,8 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) 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; - + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer + ? GL_RGB : 0; case GL_R8UI: case GL_R8I: case GL_R16UI: @@ -1321,7 +1602,7 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_INTENSITY16UI_EXT: case GL_INTENSITY32I_EXT: case GL_INTENSITY32UI_EXT: - return ctx->API == API_OPENGL && + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; @@ -1331,7 +1612,7 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_LUMINANCE16UI_EXT: case GL_LUMINANCE32I_EXT: case GL_LUMINANCE32UI_EXT: - return ctx->API == API_OPENGL && + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; @@ -1341,7 +1622,7 @@ _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->API == API_OPENGL && + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; @@ -1351,7 +1632,7 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_ALPHA16UI_EXT: case GL_ALPHA32I_EXT: case GL_ALPHA32UI_EXT: - return ctx->API == API_OPENGL && + return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_texture_integer && ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; @@ -1408,12 +1689,26 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei samples) { const char *func = samples == NO_SAMPLES ? - "glRenderbufferStorage" : "RenderbufferStorageMultisample"; + "glRenderbufferStorage" : "glRenderbufferStorageMultisample"; struct gl_renderbuffer *rb; GLenum baseFormat; + GLenum sample_count_error; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); + if (MESA_VERBOSE & VERBOSE_API) { + if (samples == NO_SAMPLES) + _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n", + func, + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(internalFormat), + width, height); + else + _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n", + func, + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(internalFormat), + width, height, samples); + } if (target != GL_RENDERBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); @@ -1422,7 +1717,8 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, baseFormat = _mesa_base_fbo_format(ctx, internalFormat); if (baseFormat == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)", + func, _mesa_lookup_enum_by_nr(internalFormat)); return; } @@ -1440,10 +1736,16 @@ renderbuffer_storage(GLenum target, GLenum internalFormat, /* NumSamples == 0 indicates non-multisampling */ samples = 0; } - else if (samples > (GLsizei) ctx->Const.MaxSamples) { - /* note: driver may choose to use more samples than what's requested */ - _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); - return; + else { + /* check the sample count; + * note: driver may choose to use more samples than what's requested + */ + sample_count_error = _mesa_check_sample_count(ctx, target, + internalFormat, samples); + if (sample_count_error != GL_NO_ERROR) { + _mesa_error(ctx, sample_count_error, "%s(samples)", func); + return; + } } rb = ctx->CurrentRenderbuffer; @@ -1499,7 +1801,6 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) { struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); if (!ctx->Extensions.OES_EGL_image) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -1593,8 +1894,6 @@ _mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (target != GL_RENDERBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetRenderbufferParameterivEXT(target)"); @@ -1675,7 +1974,8 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; - if (att->Texture && _mesa_get_attachment_teximage(att)) { + if (att->Texture && att->Renderbuffer->TexImage + && driver_RenderTexture_is_safe(att)) { ctx->Driver.RenderTexture(ctx, fb, att); } } @@ -1697,16 +1997,17 @@ check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) GLuint i; for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; - if (att->Texture && att->Renderbuffer) { - ctx->Driver.FinishRenderTexture(ctx, att); + struct gl_renderbuffer *rb = att->Renderbuffer; + if (rb && rb->NeedsFinishRenderTexture) { + ctx->Driver.FinishRenderTexture(ctx, rb); } } } } -void GLAPIENTRY -_mesa_BindFramebuffer(GLenum target, GLuint framebuffer) +static void +bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) { struct gl_framebuffer *newDrawFb, *newReadFb; struct gl_framebuffer *oldDrawFb, *oldReadFb; @@ -1715,19 +2016,10 @@ _mesa_BindFramebuffer(GLenum target, GLuint framebuffer) #ifdef DEBUG if (ctx->Extensions.ARB_framebuffer_object) { - ASSERT(ctx->Extensions.EXT_framebuffer_object); ASSERT(ctx->Extensions.EXT_framebuffer_blit); } #endif - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.EXT_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindFramebufferEXT(unsupported)"); - return; - } - switch (target) { case GL_DRAW_FRAMEBUFFER_EXT: if (!ctx->Extensions.EXT_framebuffer_blit) { @@ -1761,7 +2053,7 @@ _mesa_BindFramebuffer(GLenum target, GLuint framebuffer) /* ID was reserved, but no real framebuffer object made yet */ newDrawFb = NULL; } - else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { + else if (!newDrawFb && !allow_user_names) { /* All FBO IDs must be Gen'd */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); return; @@ -1838,6 +2130,26 @@ _mesa_BindFramebuffer(GLenum target, GLuint framebuffer) } } +void GLAPIENTRY +_mesa_BindFramebuffer(GLenum target, GLuint framebuffer) +{ + GET_CURRENT_CONTEXT(ctx); + + /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry + * point, but they allow the use of user-generated names. + */ + bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx)); +} + +void GLAPIENTRY +_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) +{ + /* This function should not be in the dispatch table for core profile / + * OpenGL 3.1, so execution should never get here in those cases -- no + * need for an explicit test. + */ + bind_framebuffer(target, framebuffer, true); +} void GLAPIENTRY _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) @@ -1845,7 +2157,6 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) GLint i; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_BUFFERS); for (i = 0; i < n; i++) { @@ -1900,8 +2211,6 @@ _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) GLuint first; GLint i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); return; @@ -1932,6 +2241,10 @@ _mesa_CheckFramebufferStatus(GLenum target) ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", + _mesa_lookup_enum_by_nr(target)); + buffer = get_framebuffer_target(ctx, target); if (!buffer) { _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); @@ -1939,8 +2252,12 @@ _mesa_CheckFramebufferStatus(GLenum target) } if (_mesa_is_winsys_fbo(buffer)) { - /* The window system / default framebuffer is always complete */ - return GL_FRAMEBUFFER_COMPLETE_EXT; + /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */ + if (buffer != &IncompleteFramebuffer) { + return GL_FRAMEBUFFER_COMPLETE_EXT; + } else { + return GL_FRAMEBUFFER_UNDEFINED; + } } /* No need to flush here */ @@ -1987,15 +2304,13 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, static void framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset) + GLint level, GLint zoffset, GLboolean layered) { struct gl_renderbuffer_attachment *att; struct gl_texture_object *texObj = NULL; struct gl_framebuffer *fb; GLenum maxLevelsTarget; - ASSERT_OUTSIDE_BEGIN_END(ctx); - fb = get_framebuffer_target(ctx, target); if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, @@ -2027,7 +2342,8 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, err = (texObj->Target != GL_TEXTURE_3D) && (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) && - (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY); + (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) && + (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY); } else { /* Make sure textarget is consistent with the texture's type */ @@ -2061,7 +2377,8 @@ 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) || - (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY)) { + (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) || + (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { if (zoffset < 0 || zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -2114,7 +2431,7 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, BUFFER_DEPTH); } else { _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, - level, zoffset); + level, zoffset, layered); 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 @@ -2180,7 +2497,7 @@ _mesa_FramebufferTexture1D(GLenum target, GLenum attachment, } framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, - level, 0); + level, 0, GL_FALSE); } @@ -2213,6 +2530,11 @@ _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, error = (_mesa_is_gles(ctx) && ctx->Version < 30) || !ctx->Extensions.EXT_texture_array; break; + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + error = _mesa_is_gles(ctx) + || !ctx->Extensions.ARB_texture_multisample; + break; default: error = GL_TRUE; } @@ -2226,7 +2548,7 @@ _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, } framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, - level, 0); + level, 0, GL_FALSE); } @@ -2244,7 +2566,7 @@ _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, } framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, - level, zoffset); + level, zoffset, GL_FALSE); } @@ -2255,7 +2577,23 @@ _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, GET_CURRENT_CONTEXT(ctx); framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, - level, layer); + level, layer, GL_FALSE); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture(GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if (_mesa_has_geometry_shaders(ctx)) { + framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, + level, 0, GL_TRUE); + } else { + _mesa_error(ctx, GL_INVALID_OPERATION, + "unsupported function (glFramebufferTexture) called"); + } } @@ -2269,8 +2607,6 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - fb = get_framebuffer_target(ctx, target); if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)"); @@ -2352,8 +2688,6 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum err; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - /* The error differs in GL and GLES. */ err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; @@ -2375,11 +2709,19 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, * OES_framebuffer_object spec refers to the EXT_framebuffer_object * spec. */ - if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) { + if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) + && !_mesa_is_gles3(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); return; } + + if (_mesa_is_gles3(ctx) && attachment != GL_BACK && + attachment != GL_DEPTH && attachment != GL_STENCIL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFramebufferAttachmentParameteriv(attachment)"); + return; + } /* the default / window-system FBO */ att = _mesa_get_fb0_attachment(ctx, buffer, attachment); } @@ -2498,7 +2840,7 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, } return; case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if ((ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) + if ((ctx->API != API_OPENGL_COMPAT || !ctx->Extensions.ARB_framebuffer_object) && ctx->API != API_OPENGL_CORE && !_mesa_is_gles3(ctx)) { goto invalid_pname_enum; @@ -2509,6 +2851,22 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, } else { gl_format format = att->Renderbuffer->Format; + + /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES + * 3.0.1 spec says: + * + * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If + * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and + * generate an INVALID_OPERATION error. + */ + if (_mesa_is_gles3(ctx) && attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFramebufferAttachmentParameteriv(cannot query " + "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " + "GL_DEPTH_STENCIL_ATTACHMENT"); + return; + } + if (format == MESA_FORMAT_S8) { /* special cases */ *params = GL_INDEX; @@ -2584,8 +2942,7 @@ _mesa_GenerateMipmap(GLenum target) GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); + FLUSH_VERTICES(ctx, 0); switch (target) { case GL_TEXTURE_1D: @@ -2716,127 +3073,16 @@ compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat) } -/** - * 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 GLenum -get_linear_internalformat(GLenum format) -{ - switch (format) { - case GL_SRGB: - return GL_RGB; - - case GL_SRGB_ALPHA: - return GL_RGBA; - - case GL_SRGB8: - return GL_RGB8; - - case GL_SRGB8_ALPHA8: - return GL_RGBA8; - - case GL_SLUMINANCE: - return GL_LUMINANCE8; - - case GL_SLUMINANCE_ALPHA: - return GL_LUMINANCE8_ALPHA8; - - default: - return format; - } -} - - static GLboolean -compatible_resolve_formats(const struct gl_renderbuffer *colorReadRb, - const struct gl_renderbuffer *colorDrawRb) +compatible_resolve_formats(const struct gl_renderbuffer *readRb, + const struct gl_renderbuffer *drawRb) { GLenum readFormat, drawFormat; /* The simple case where we know the backing Mesa formats are the same. */ - if (_mesa_get_srgb_format_linear(colorReadRb->Format) == - _mesa_get_srgb_format_linear(colorDrawRb->Format)) { + if (_mesa_get_srgb_format_linear(readRb->Format) == + _mesa_get_srgb_format_linear(drawRb->Format)) { return GL_TRUE; } @@ -2850,10 +3096,10 @@ compatible_resolve_formats(const struct gl_renderbuffer *colorReadRb, * * Blits between linear and sRGB formats are also allowed. */ - readFormat = get_nongeneric_internalformat(colorReadRb->InternalFormat); - drawFormat = get_nongeneric_internalformat(colorDrawRb->InternalFormat); - readFormat = get_linear_internalformat(readFormat); - drawFormat = get_linear_internalformat(drawFormat); + readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat); + drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat); + readFormat = _mesa_get_linear_internalformat(readFormat); + drawFormat = _mesa_get_linear_internalformat(drawFormat); if (readFormat == drawFormat) { return GL_TRUE; @@ -2862,6 +3108,20 @@ compatible_resolve_formats(const struct gl_renderbuffer *colorReadRb, return GL_FALSE; } +static GLboolean +is_valid_blit_filter(const struct gl_context *ctx, GLenum filter) +{ + switch (filter) { + case GL_NEAREST: + case GL_LINEAR: + return true; + case GL_SCALED_RESOLVE_FASTEST_EXT: + case GL_SCALED_RESOLVE_NICEST_EXT: + return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled; + default: + return false; + } +} /** * Blit rectangular region, optionally from one framebuffer to another. @@ -2878,11 +3138,9 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); const struct gl_framebuffer *readFb, *drawFb; - const struct gl_renderbuffer *colorReadRb, *colorDrawRb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); + FLUSH_VERTICES(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, @@ -2913,8 +3171,17 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, return; } - if (filter != GL_NEAREST && filter != GL_LINEAR) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); + if (!is_valid_blit_filter(ctx, filter)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)", + _mesa_lookup_enum_by_nr(filter)); + return; + } + + if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT || + filter == GL_SCALED_RESOLVE_NICEST_EXT) && + (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)", + _mesa_lookup_enum_by_nr(filter)); return; } @@ -2933,8 +3200,10 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, /* get color read/draw renderbuffers */ if (mask & GL_COLOR_BUFFER_BIT) { - colorReadRb = readFb->_ColorReadBuffer; - colorDrawRb = drawFb->_ColorDrawBuffers[0]; + const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers; + const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; + const struct gl_renderbuffer *colorDrawRb = NULL; + GLuint i; /* From the EXT_framebuffer_object spec: * @@ -2942,20 +3211,62 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * the read and draw framebuffers, the corresponding bit is silently * ignored." */ - if ((colorReadRb == NULL) || (colorDrawRb == NULL)) { - colorReadRb = colorDrawRb = NULL; - mask &= ~GL_COLOR_BUFFER_BIT; + if (!colorReadRb || numColorDrawBuffers == 0) { + 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 { + for (i = 0; i < numColorDrawBuffers; i++) { + colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; + if (!colorDrawRb) + continue; + + /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL + * ES 3.0.1 spec says: + * + * "If the source and destination buffers are identical, an + * INVALID_OPERATION error is generated. Different mipmap + * levels of a texture, different layers of a three- + * dimensional texture or two-dimensional array texture, and + * different faces of a cube map texture do not constitute + * identical buffers." + */ + if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebuffer(source and destination color " + "buffer cannot be the same)"); + return; + } + + if (!compatible_color_datatypes(colorReadRb->Format, + colorDrawRb->Format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(color buffer datatypes mismatch)"); + return; + } + /* extra checks for multisample copies... */ + if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { + /* color formats must match */ + if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(bad src/dst multisample pixel formats)"); + return; + } + } + } + if (filter != GL_NEAREST) { + /* From EXT_framebuffer_multisample_blit_scaled specification: + * "Calling BlitFramebuffer will result in an INVALID_OPERATION error + * if filter is not NEAREST 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; + } + } } } - else { - colorReadRb = colorDrawRb = NULL; - } if (mask & GL_STENCIL_BUFFER_BIT) { struct gl_renderbuffer *readRb = @@ -2972,14 +3283,42 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 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)"); - return; + else { + int read_z_bits, draw_z_bits; + + if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebuffer(source and destination stencil " + "buffer cannot be the same)"); + return; + } + + 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, + "glBlitFramebuffer(stencil attachment format mismatch)"); + return; + } + + read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS); + draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS); + + /* If both buffers also have depth data, the depth formats must match + * as well. If one doesn't have depth, it's not blitted, so we should + * ignore the depth format check. + */ + if (read_z_bits > 0 && draw_z_bits > 0 && + (read_z_bits != draw_z_bits || + _mesa_get_format_datatype(readRb->Format) != + _mesa_get_format_datatype(drawRb->Format))) { + + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" + "(stencil attachment depth format mismatch)"); + return; + } } } @@ -2998,55 +3337,93 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 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 format mismatch)"); - return; + else { + int read_s_bit, draw_s_bit; + + if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebuffer(source and destination depth " + "buffer cannot be the same)"); + return; + } + + 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, + "glBlitFramebuffer(depth attachment format mismatch)"); + return; + } + + read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS); + draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS); + + /* If both buffers also have stencil data, the stencil formats must + * match as well. If one doesn't have stencil, it's not blitted, so + * we should ignore the stencil format check. + */ + if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" + "(depth attachment stencil bits mismatch)"); + return; + } } } - if (readFb->Visual.samples > 0 && - drawFb->Visual.samples > 0 && - readFb->Visual.samples != drawFb->Visual.samples) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "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 (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || - abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { + if (_mesa_is_gles3(ctx)) { + /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES + * 3.0.1 spec says: + * + * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero, + * an INVALID_OPERATION error is generated." + */ + if (drawFb->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes)"); + "glBlitFramebuffer(destination samples must be 0)"); return; } - /* color formats must match */ - if (colorReadRb && - colorDrawRb && - !compatible_resolve_formats(colorReadRb, colorDrawRb)) { + /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES + * 3.0.1 spec says: + * + * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero, + * no copy is performed and an INVALID_OPERATION error is generated + * if the formats of the read and draw framebuffers are not + * identical or if the source and destination rectangles are not + * defined with the same (X0, Y0) and (X1, Y1) bounds." + * + * The format check was made above because desktop OpenGL has the same + * requirement. + */ + if (readFb->Visual.samples > 0 + && (srcX0 != dstX0 || srcY0 != dstY0 + || srcX1 != dstX1 || srcY1 != dstY1)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample pixel formats)"); + "glBlitFramebuffer(bad src/dst multisample region)"); 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) { + } else { + if (readFb->Visual.samples > 0 && + drawFb->Visual.samples > 0 && + readFb->Visual.samples != drawFb->Visual.samples) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(integer color type)"); + "glBlitFramebufferEXT(mismatched samples)"); return; } + + /* extra checks for multisample copies... */ + if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) && + (filter == GL_NEAREST || filter == GL_LINEAR)) { + /* src and dest region sizes must be the same */ + 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; + } + } } if (!ctx->Extensions.EXT_framebuffer_blit) { @@ -3056,6 +3433,10 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, /* Debug code */ if (DEBUG_BLIT) { + const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; + const struct gl_renderbuffer *colorDrawRb = NULL; + GLuint i = 0; + printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," " 0x%x, 0x%x)\n", srcX0, srcY0, srcX1, srcY1, @@ -3077,22 +3458,31 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, } printf("\n"); - att = find_attachment(drawFb, colorDrawRb); - printf(" Dst FBO %u RB %u (%dx%d) ", - drawFb->Name, colorDrawRb->Name, - colorDrawRb->Width, colorDrawRb->Height); - if (att && att->Texture) { - printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); + /* Print all active color render buffers */ + for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { + colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; + if (!colorDrawRb) + continue; + + att = find_attachment(drawFb, colorDrawRb); + printf(" Dst FBO %u RB %u (%dx%d) ", + drawFb->Name, colorDrawRb->Name, + colorDrawRb->Width, colorDrawRb->Height); + if (att && att->Texture) { + printf("Tex %u tgt 0x%x level %u face %u", + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); + } + printf("\n"); } - printf("\n"); } } - if (!mask) { + if (!mask || + (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 || + (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) { return; } @@ -3113,8 +3503,6 @@ invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, struct gl_framebuffer *fb; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - fb = get_framebuffer_target(ctx, target); if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name); @@ -3153,7 +3541,7 @@ invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, /* Accumulation buffers and auxilary buffers were removed in * OpenGL 3.1, and they never existed in OpenGL ES. */ - if (ctx->API != API_OPENGL) + if (ctx->API != API_OPENGL_COMPAT) goto invalid_enum; break; case GL_COLOR: @@ -3197,6 +3585,7 @@ invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, "%s(attachment >= max. color attachments)", name); return; } + break; } default: goto invalid_enum; @@ -3244,3 +3633,56 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, 0, 0, MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, "glInvalidateFramebuffer"); } + +void GLAPIENTRY +_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, + const GLenum *attachments) +{ + struct gl_framebuffer *fb; + GLint i; + + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glDiscardFramebufferEXT(target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } + + if (numAttachments < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDiscardFramebufferEXT(numAttachments < 0)"); + return; + } + + for (i = 0; i < numAttachments; i++) { + switch (attachments[i]) { + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (_mesa_is_user_fbo(fb)) + goto invalid_enum; + break; + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + if (_mesa_is_winsys_fbo(fb)) + goto invalid_enum; + break; + default: + goto invalid_enum; + } + } + + if (ctx->Driver.DiscardFramebuffer) + ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments); + + return; + +invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, + "glDiscardFramebufferEXT(attachment %s)", + _mesa_lookup_enum_by_nr(attachments[i])); +}