[Fix] (GL): raise INVALID_OPERATION from glTextureParameter* for sampler state on a multisample texture

This commit is contained in:
2026-10-12 08:22:14 -04:00
parent 6e43ff8ccc
commit d4501e0c23
2 changed files with 66 additions and 5 deletions
+31 -5
View File
@@ -100,6 +100,26 @@ namespace MobileGL::MG_Impl::GLImpl {
return true;
}
// GL 4.6 core 8.10 gives the multisample-target sampler-state rejection a different error
// per entry point: glTexParameter* raises INVALID_ENUM, glTextureParameter* INVALID_OPERATION.
// The by-name setters share the bound-target code (directly or through
// WithTemporarilyBoundNamedTexture), so they mark the call for its duration instead of
// threading a flag through every TexParameter*_State signature.
thread_local Bool g_inNamedTextureParameterCall = false;
class ScopedNamedTextureParameterCall {
public:
ScopedNamedTextureParameterCall() : m_previous(g_inNamedTextureParameterCall) {
g_inNamedTextureParameterCall = true;
}
~ScopedNamedTextureParameterCall() { g_inNamedTextureParameterCall = m_previous; }
ScopedNamedTextureParameterCall(const ScopedNamedTextureParameterCall&) = delete;
ScopedNamedTextureParameterCall& operator=(const ScopedNamedTextureParameterCall&) = delete;
private:
Bool m_previous;
};
Bool ValidateMaxAnisotropy(Float maxAnisotropy, const char* caller) {
if (maxAnisotropy >= 1.0f) return true;
@@ -1223,12 +1243,12 @@ namespace MobileGL::MG_Impl::GLImpl {
pname == GL_TEXTURE_MAX_LOD || pname == GL_TEXTURE_LOD_BIAS || pname == GL_TEXTURE_COMPARE_MODE ||
pname == GL_TEXTURE_COMPARE_FUNC || pname == GL_TEXTURE_BORDER_COLOR ||
pname == GL_TEXTURE_MAX_ANISOTROPY_EXT)) {
// GL 4.6 core 8.10: a multisample target simply does not ACCEPT these pnames, which is
// an INVALID_ENUM - not the INVALID_OPERATION the two BASE_LEVEL gates above report.
// Those really are operation errors (the pname is accepted, the value is not), which is
// presumably how the wrong class got copied down here.
// GL 4.6 core 8.10: through glTexParameter* a multisample target simply does not ACCEPT
// these pnames, which is an INVALID_ENUM. The by-name glTextureParameter* spelling of
// the same rejection is an INVALID_OPERATION instead (the texture object, not the enum,
// is what is wrong there).
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
g_inNamedTextureParameterCall ? ErrorCode::InvalidOperation : ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
"Multisample textures do not accept sampler-state pnames."));
return false;
@@ -6376,12 +6396,14 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void TextureParameteri(GLuint texture, GLenum pname, GLint param) {
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!ValidateNamedTextureParameterTarget(textureObject, __func__)) return;
TextureParameterObject_State(textureObject, pname, param, __func__);
}
void TextureParameterf(GLuint texture, GLenum pname, GLfloat param) {
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!ValidateNamedTextureParameterTarget(textureObject, __func__)) return;
TextureParameterObjectf_State(textureObject, pname, param, __func__);
@@ -6389,18 +6411,21 @@ namespace MobileGL::MG_Impl::GLImpl {
void TextureParameterfv(GLuint texture, GLenum pname, const GLfloat* params) {
if (!params) return;
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) { TexParameterfv_State(target, pname, params); });
}
void TextureParameteriv(GLuint texture, GLenum pname, const GLint* params) {
if (!params) return;
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) { TexParameteriv_State(target, pname, params); });
}
void TextureParameterIiv(GLuint texture, GLenum pname, const GLint* params) {
if (!params) return;
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) {
TexParameterIiv_State(target, pname, params);
@@ -6409,6 +6434,7 @@ namespace MobileGL::MG_Impl::GLImpl {
void TextureParameterIuiv(GLuint texture, GLenum pname, const GLuint* params) {
if (!params) return;
ScopedNamedTextureParameterCall namedCall;
auto textureObject = GetTextureObjectByName(texture, __func__);
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) {
TexParameterIuiv_State(target, pname, params);
+35
View File
@@ -945,6 +945,41 @@ TEST_F(TextureTest, MultisampleSamplerStateIsInvalidEnumWhileNonZeroBaseLevelIsI
DrainPendingGlErrors();
}
// The by-name spelling of the same rejection is INVALID_OPERATION (GL 4.6 core 8.10), for every
// glTextureParameter* form - including the vector ones that re-enter the bound-target code - while the
// bound-target spelling right after it stays INVALID_ENUM.
TEST_F(TextureTest, NamedMultisampleSamplerStateIsInvalidOperation) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &texture);
ASSERT_NE(texture, 0u);
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
MG_Impl::GLImpl::TextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1.0f);
ExpectSingleGlError(GL_INVALID_OPERATION);
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
ExpectSingleGlError(GL_INVALID_OPERATION);
const GLfloat lodBias = 1.0f;
MG_Impl::GLImpl::TextureParameterfv(texture, GL_TEXTURE_LOD_BIAS, &lodBias);
ExpectSingleGlError(GL_INVALID_OPERATION);
const GLint wrap = GL_REPEAT;
MG_Impl::GLImpl::TextureParameteriv(texture, GL_TEXTURE_WRAP_S, &wrap);
ExpectSingleGlError(GL_INVALID_OPERATION);
MG_Impl::GLImpl::TextureParameterIiv(texture, GL_TEXTURE_WRAP_T, &wrap);
ExpectSingleGlError(GL_INVALID_OPERATION);
const GLuint borderColor[4] = {0u, 0u, 0u, 0u};
MG_Impl::GLImpl::TextureParameterIuiv(texture, GL_TEXTURE_BORDER_COLOR, borderColor);
ExpectSingleGlError(GL_INVALID_OPERATION);
// The flag must not outlive the by-name call.
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
MG_Impl::GLImpl::TexParameterf(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_LOD_BIAS, 1.0f);
ExpectSingleGlError(GL_INVALID_ENUM);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
MG_Impl::GLImpl::DeleteTextures(1, &texture);
DrainPendingGlErrors();
}
// The whole (pname x entry-point) matrix, because the sampler getters funnel three spellings through
// one void* function and used to write a FIXED destination type per pname regardless of which
// spelling called. That returned the other type's bit pattern: 10497 punned into a GLfloat reads