mesa/main: contain mutlisample advanced limitations

The AMD_framebuffer_multisample_advanced extension interacts kinda badly
with ARB_internalformat_query and GLES 3. The problem is that
ARB_internalformat_query etc untangles MAX_SAMPLES and
per-internalformat sample limits, but the multisample advanced spec
explicitly requires that we can't go above the global maximum.

This isn't the biggest problem in the world; one could just deal with
these limitations for the multisample_advanced functions... if it wasn't
for the fact that we by mistake apply the multisample_advanced
limitations for functions where they shouldn't be taken into account.
Whoops. So let's make sure we don't do that.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34455>
This commit is contained in:
Erik Faye-Lund 2025-04-11 16:52:01 +02:00 committed by Marge Bot
parent 273689bc49
commit 139f2c6629
4 changed files with 98 additions and 62 deletions

View file

@ -2759,8 +2759,12 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
if (samples != 0) {
assert(samples > 0);
assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER,
internalFormat, samples,
storageSamples) == GL_NO_ERROR);
internalFormat, samples) == GL_NO_ERROR);
}
if (samples != storageSamples) {
assert(_mesa_check_storage_sample_count(ctx,
internalFormat, samples,
storageSamples) == GL_NO_ERROR);
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
@ -2850,7 +2854,7 @@ renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
* note: driver may choose to use more samples than what's requested
*/
sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER,
internalFormat, samples, storageSamples);
internalFormat, samples);
/* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16:
*
@ -2951,7 +2955,6 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat,
height, samples, storageSamples, func);
}
void GLAPIENTRY
_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
{
@ -3037,6 +3040,17 @@ _mesa_RenderbufferStorageMultisampleAdvancedAMD(
GLenum target, GLsizei samples, GLsizei storageSamples,
GLenum internalFormat, GLsizei width, GLsizei height)
{
GET_CURRENT_CONTEXT(ctx);
GLenum sample_count_error =
_mesa_check_storage_sample_count(ctx, internalFormat, samples,
storageSamples);
if (sample_count_error != GL_NO_ERROR) {
_mesa_error(ctx, sample_count_error,
"glRenderbufferStorageMultisampleAdvancedAMD(samples=%d)",
samples);
return;
}
renderbuffer_storage_target(target, internalFormat, width, height,
samples, storageSamples,
"glRenderbufferStorageMultisampleAdvancedAMD");
@ -3113,6 +3127,17 @@ _mesa_NamedRenderbufferStorageMultisampleAdvancedAMD(
GLuint renderbuffer, GLsizei samples, GLsizei storageSamples,
GLenum internalformat, GLsizei width, GLsizei height)
{
GET_CURRENT_CONTEXT(ctx);
GLenum sample_count_error =
_mesa_check_storage_sample_count(ctx, internalformat, samples,
storageSamples);
if (sample_count_error != GL_NO_ERROR) {
_mesa_error(ctx, sample_count_error,
"glNamedRenderbufferStorageMultisampleAdvancedAMD(samples=%d)",
samples);
return;
}
renderbuffer_storage_named(renderbuffer, internalformat, width, height,
samples, storageSamples,
"glNamedRenderbufferStorageMultisampleAdvancedAMD");
@ -4043,7 +4068,7 @@ check_samples(struct gl_context *ctx, struct gl_texture_object *texObj,
assert(texImage);
GLenum sample_count_error =
_mesa_check_sample_count(ctx, target, texImage->InternalFormat,
samples, samples);
samples);
if (sample_count_error != GL_NO_ERROR) {
_mesa_error(ctx, sample_count_error, "%s(samples=%d)", caller,
samples);

View file

@ -231,8 +231,7 @@ _mesa_MinSampleShading(GLclampf value)
*/
GLenum
_mesa_check_sample_count(struct gl_context *ctx, GLenum target,
GLenum internalFormat, GLsizei samples,
GLsizei storageSamples)
GLenum internalFormat, GLsizei samples)
{
/* Section 4.4 (Framebuffer objects), page 198 of the OpenGL ES 3.0.0
* specification says:
@ -248,58 +247,6 @@ _mesa_check_sample_count(struct gl_context *ctx, GLenum target,
return GL_INVALID_OPERATION;
}
if (_mesa_has_AMD_framebuffer_multisample_advanced(ctx) &&
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.
@ -374,6 +321,67 @@ _mesa_check_sample_count(struct gl_context *ctx, GLenum target,
? GL_INVALID_VALUE : GL_NO_ERROR;
}
/**
* Helper for checking a requested sample count against the limit
* for a particular (target, internalFormat) pair. The limit imposed,
* and the error generated, both depend on which extensions are supported.
*
* Returns a GL error enum, or GL_NO_ERROR if the requested sample count is
* acceptable.
*/
GLenum
_mesa_check_storage_sample_count(struct gl_context *ctx, GLenum internalFormat,
GLsizei samples, GLsizei storageSamples)
{
assert(_mesa_has_AMD_framebuffer_multisample_advanced(ctx));
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;
}
return GL_NO_ERROR;
}
void GLAPIENTRY
_mesa_AlphaToCoverageDitherControlNV_no_error(GLenum mode)
{

View file

@ -39,7 +39,10 @@ _mesa_init_multisample(struct gl_context *ctx);
extern GLenum
_mesa_check_sample_count(struct gl_context *ctx, GLenum target,
GLenum internalFormat, GLsizei samples,
GLsizei storageSamples);
GLenum internalFormat, GLsizei samples);
extern GLenum
_mesa_check_storage_sample_count(struct gl_context *ctx, GLenum internalFormat,
GLsizei samples, GLsizei storageSamples);
#endif

View file

@ -7131,7 +7131,7 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
}
sample_count_error = _mesa_check_sample_count(ctx, target,
internalformat, samples, samples);
internalformat, samples);
samplesOK = sample_count_error == GL_NO_ERROR;
/* Page 254 of OpenGL 4.4 spec says: