[Fix] (MG_Impl/GLImpl): reject the RGTC internal formats on 3D texture targets - RGTC compresses 4x4 blocks of a 2D image and has no 3D form, and the check must run on the raw enum because RGTC now resolves to plain R8/RG8 storage

This commit is contained in:
2026-07-20 21:05:57 -04:00
parent e526f8e8ac
commit 6eb5ff51c5
2 changed files with 37 additions and 0 deletions
@@ -1724,6 +1724,21 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
// RGTC is a 2D-only compression scheme, so a 3D target rejects it. This has to be tested on
// the raw enum: the RGTC formats resolve to plain R8/RG8/SNORM storage on the way in (see
// GLToMG's TextureEnumConverter), so once the internal format is converted there is nothing
// left to distinguish them from an ordinary one- or two-channel upload.
if ((textureUploadTarget == TextureUploadTarget::Texture3D ||
textureUploadTarget == TextureUploadTarget::ProxyTexture3D) &&
(internalformat == GL_COMPRESSED_RED_RGTC1 || internalformat == GL_COMPRESSED_SIGNED_RED_RGTC1 ||
internalformat == GL_COMPRESSED_RG_RGTC2 || internalformat == GL_COMPRESSED_SIGNED_RG_RGTC2)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"RGTC compressed formats are invalid for 3D texture targets"));
return;
}
// TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the
// GL_PIXEL_UNPACK_BUFFER target and the buffer object's data store is currently mapped.
// GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER
+22
View File
@@ -1557,6 +1557,28 @@ TEST_F(TextureTest, CompressedInternalFormatsResolveToTheirUncompressedStorage)
}
}
// RGTC compresses 4x4 blocks of a 2D image and has no 3D form, so glTexImage3D must reject it even
// though the same enum is accepted on a 2D target. The generic compressed formats carry no such
// restriction and stay legal in 3D.
TEST_F(TextureTest, RgtcInternalFormatsAreRejectedOnThreeDimensionalTargets) {
const GLenum rgtc[] = {GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_SIGNED_RED_RGTC1, GL_COMPRESSED_RG_RGTC2,
GL_COMPRESSED_SIGNED_RG_RGTC2};
for (const GLenum internalFormat : rgtc) {
GLuint texture = 0;
MG_Impl::GLImpl::GenTextures(1, &texture);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_3D, texture);
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_3D, 0, internalFormat, 4, 4, 4, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION)
<< "internalFormat 0x" << std::hex << internalFormat;
}
GLuint generic = 0;
MG_Impl::GLImpl::GenTextures(1, &generic);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_3D, generic);
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_3D, 0, GL_COMPRESSED_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, TextureStorage3DAndSubImageModifyNamedObjectOnly) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_3D, 1, &texture);