From: Marek Olšák <marek.ol...@amd.com> - relax FBO completeness rules - validate sample counts --- src/mesa/main/fbobject.c | 96 ++++++++++++++++++++++++++++++------- src/mesa/main/multisample.c | 52 ++++++++++++++++++++ 2 files changed, 131 insertions(+), 17 deletions(-)
diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 3ed303b51ab..c14c9f4047b 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -962,21 +962,23 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, * Also update the framebuffer's Width and Height fields if the * framebuffer is complete. */ void _mesa_test_framebuffer_completeness(struct gl_context *ctx, struct gl_framebuffer *fb) { GLuint numImages; GLenum intFormat = GL_NONE; /* color buffers' internal format */ GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; - GLint numSamples = -1; + GLint numColorSamples = -1; + GLint numColorStorageSamples = -1; + GLint numDepthSamples = -1; GLint fixedSampleLocations = -1; GLint i; GLuint j; /* Covers max_layer_count, is_layered, and layer_tex_target */ bool layer_info_valid = false; GLuint max_layer_count = 0, att_layer_count; bool is_layered = false; GLenum layer_tex_target = 0; bool has_depth_attachment = false; bool has_stencil_attachment = false; @@ -1039,87 +1041,102 @@ _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(ctx, "color attachment incomplete", i); return; } } /* get width, height, format of the renderbuffer/texture */ + unsigned attNumSamples, attNumStorageSamples; + if (att->Type == GL_TEXTURE) { const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; att_tex_target = att->Texture->Target; minWidth = MIN2(minWidth, texImg->Width); maxWidth = MAX2(maxWidth, texImg->Width); minHeight = MIN2(minHeight, texImg->Height); maxHeight = MAX2(maxHeight, texImg->Height); f = texImg->_BaseFormat; attFormat = texImg->TexFormat; numImages++; if (!is_format_color_renderable(ctx, attFormat, texImg->InternalFormat) && !is_legal_depth_format(ctx, f) && f != GL_STENCIL_INDEX) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 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; } + + attNumSamples = texImg->NumSamples; + attNumStorageSamples = texImg->NumSamples; } else if (att->Type == GL_RENDERBUFFER_EXT) { minWidth = MIN2(minWidth, att->Renderbuffer->Width); maxWidth = MAX2(minWidth, att->Renderbuffer->Width); minHeight = MIN2(minHeight, att->Renderbuffer->Height); maxHeight = MAX2(minHeight, att->Renderbuffer->Height); 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; } + + attNumSamples = att->Renderbuffer->NumSamples; + attNumStorageSamples = att->Renderbuffer->NumStorageSamples; } else { assert(att->Type == GL_NONE); continue; } + if (i >= 0) { + /* Color buffers. */ + if (numColorSamples < 0) { + assert(numColorStorageSamples < 0); + numColorSamples = attNumSamples; + numColorStorageSamples = attNumStorageSamples; + } else if (numColorSamples != attNumSamples || + numColorStorageSamples != attNumStorageSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } else { + /* Depth/stencil buffers. */ + if (numDepthSamples < 0) { + numDepthSamples = attNumSamples; + } else if (numDepthSamples != attNumSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } + /* Update flags describing color buffer datatypes */ if (i >= 0) { GLenum type = _mesa_get_format_datatype(attFormat); /* check if integer color */ if (_mesa_is_format_integer_color(attFormat)) fb->_IntegerBuffers |= (1 << i); fb->_AllColorBuffersFixedPoint = fb->_AllColorBuffersFixedPoint && @@ -1211,20 +1228,65 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, * * "If image has multiple samples, its sample count is less than or equal * to the value of the implementation-dependent limit * MAX_FRAMEBUFFER_SAMPLES." * * The same requirements are also in place for GL 4.5, * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311 */ } + if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { + /* See if non-matching sample counts are supported. */ + if (numColorSamples >= 0 && numDepthSamples >= 0) { + bool found = false; + + assert(numColorStorageSamples != -1); + + numColorSamples = MAX2(numColorSamples, 1); + numColorStorageSamples = MAX2(numColorStorageSamples, 1); + numDepthSamples = MAX2(numDepthSamples, 1); + + if (numColorSamples == 1 && numColorStorageSamples == 1 && + numDepthSamples == 1) { + found = true; + } else { + for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) { + GLint *counts = + &ctx->Const.SupportedMultisampleModes[i].NumColorSamples; + + if (counts[0] == numColorSamples && + counts[1] == numColorStorageSamples && + counts[2] == numDepthSamples) { + found = true; + break; + } + } + } + + if (!found) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "unsupported sample counts", -1); + return; + } + } + } else { + /* If the extension is unsupported, all sample counts must be equal. */ + if (numColorSamples >= 0 && + (numColorSamples != numColorStorageSamples || + (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } + fb->MaxNumLayers = max_layer_count; if (numImages == 0) { fb->_HasAttachments = false; if (!ctx->Extensions.ARB_framebuffer_no_attachments) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; fbo_incomplete(ctx, "no attachments", -1); return; } diff --git a/src/mesa/main/multisample.c b/src/mesa/main/multisample.c index 4341a5918e4..8beb1d839ec 100644 --- a/src/mesa/main/multisample.c +++ b/src/mesa/main/multisample.c @@ -219,20 +219,72 @@ _mesa_check_sample_count(struct gl_context *ctx, GLenum target, * is greater than zero, then the error INVALID_OPERATION is generated." * * This restriction is relaxed for OpenGL ES 3.1. */ if ((ctx->API == API_OPENGLES2 && ctx->Version == 30) && _mesa_is_enum_format_integer(internalFormat) && samples > 0) { return GL_INVALID_OPERATION; } + if (ctx->Extensions.AMD_framebuffer_multisample_advanced && + target == GL_RENDERBUFFER) { + if (!_mesa_is_depth_or_stencil_format(internalFormat)) { + /* From the AMD_framebuffer_multisample_advanced spec: + * + * "An INVALID_OPERATION error is generated if <internalformat> + * is a color format and <storageSamples> is greater than + * the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_- + * STORAGE_SAMPLES_AMD." + */ + if (samples > ctx->Const.MaxColorFramebufferSamples) + return GL_INVALID_OPERATION; + + /* From the AMD_framebuffer_multisample_advanced spec: + * + * "An INVALID_OPERATION error is generated if <internalformat> + * is a color format and <storageSamples> is greater than + * the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_- + * STORAGE_SAMPLES_AMD." + */ + if (storageSamples > ctx->Const.MaxColorFramebufferStorageSamples) + return GL_INVALID_OPERATION; + + /* From the AMD_framebuffer_multisample_advanced spec: + * + * "An INVALID_OPERATION error is generated if <storageSamples> is + * greater than <samples>." + */ + if (storageSamples > samples) + return GL_INVALID_OPERATION; + + /* Color renderbuffer sample counts are now fully validated + * according to AMD_framebuffer_multisample_advanced. + */ + return GL_NO_ERROR; + } else { + /* From the AMD_framebuffer_multisample_advanced spec: + * + * "An INVALID_OPERATION error is generated if <internalformat> is + * a depth or stencil format and <storageSamples> is not equal to + * <samples>." + */ + if (storageSamples != samples) + return GL_INVALID_OPERATION; + } + } else { + /* If the extension is unsupported, it's not possible to set + * storageSamples differently. + */ + assert(samples == storageSamples); + } + /* If ARB_internalformat_query is supported, then treat its highest * returned sample count as the absolute maximum for this format; it is * allowed to exceed MAX_SAMPLES. * * From the ARB_internalformat_query spec: * * "If <samples is greater than the maximum number of samples supported * for <internalformat> then the error INVALID_OPERATION is generated." */ if (ctx->Extensions.ARB_internalformat_query) { -- 2.17.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev