mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-13 06:38:31 +09:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56124d931c | ||
|
|
9794c87440 |
@@ -1670,6 +1670,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
|
||||
|
||||
@@ -1427,6 +1427,69 @@ TEST_F(TextureTest, TextureStorage1DAndSubImageModifyNamedObjectOnly) {
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
// glTexImage2D used to reject every GL_COMPRESSED_* internal format with GL_INVALID_ENUM, because
|
||||
// none of them mapped to a TextureInternalFormat and the "unknown format" gate fired. They now
|
||||
// resolve to the uncompressed storage that backs them - what GL prescribes for the generic formats,
|
||||
// and a deliberate deviation for RGTC, which ES cannot compress. The (format, type) pairs below are
|
||||
// the ones KHR-GL33.packed_pixels uploads with, so this table doubles as a pin for those 480 cases.
|
||||
TEST_F(TextureTest, CompressedInternalFormatsResolveToTheirUncompressedStorage) {
|
||||
struct Case {
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
TextureInternalFormat expected;
|
||||
};
|
||||
const Case cases[] = {
|
||||
{GL_COMPRESSED_RED, GL_RED, GL_UNSIGNED_BYTE, TextureInternalFormat::R8},
|
||||
{GL_COMPRESSED_RG, GL_RG, GL_UNSIGNED_BYTE, TextureInternalFormat::RG8},
|
||||
{GL_COMPRESSED_RGB, GL_RGB, GL_UNSIGNED_BYTE, TextureInternalFormat::RGB8},
|
||||
{GL_COMPRESSED_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, TextureInternalFormat::RGBA8},
|
||||
{GL_COMPRESSED_SRGB, GL_RGB, GL_UNSIGNED_BYTE, TextureInternalFormat::SRGB8},
|
||||
{GL_COMPRESSED_SRGB_ALPHA, GL_RGBA, GL_UNSIGNED_BYTE, TextureInternalFormat::SRGB8Alpha8},
|
||||
{GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, TextureInternalFormat::R8},
|
||||
{GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, TextureInternalFormat::RG8},
|
||||
// The signed RGTC pair is uploaded as GL_BYTE and must land on SNORM storage - resolving
|
||||
// them to plain R8/RG8 would silently reinterpret negative texels.
|
||||
{GL_COMPRESSED_SIGNED_RED_RGTC1, GL_RED, GL_BYTE, TextureInternalFormat::R8Snorm},
|
||||
{GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_BYTE, TextureInternalFormat::RG8Snorm},
|
||||
};
|
||||
|
||||
MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for (const auto& c : cases) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, c.internalFormat, 4, 4, 0, c.format, c.type, nullptr);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
ASSERT_NE(textureObject, nullptr) << "internalFormat 0x" << std::hex << c.internalFormat;
|
||||
EXPECT_EQ(textureObject->GetFormat(), c.expected) << "internalFormat 0x" << std::hex << c.internalFormat;
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR) << "internalFormat 0x" << std::hex << c.internalFormat;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -255,6 +255,37 @@ namespace MobileGL {
|
||||
return TextureInternalFormat::DepthComponent;
|
||||
case GL_DEPTH_STENCIL:
|
||||
return TextureInternalFormat::DepthStencil;
|
||||
// Compressed internal formats resolve to the uncompressed storage that backs them.
|
||||
//
|
||||
// For the six generic formats this is exactly what GL prescribes: the implementation
|
||||
// picks a specific compressed format, and when none is available it falls back to the
|
||||
// corresponding base format. Nothing downstream ever sees a compressed enum, so the
|
||||
// metrics, pixel-store and backend tables keep their "one format, N bytes per texel"
|
||||
// invariant instead of each needing a compressed-aware arm.
|
||||
//
|
||||
// The four RGTC formats are a deliberate deviation: they are specific formats that GL
|
||||
// 3.3 requires, but ES exposes no RGTC compressor to hand the data to. Storing the
|
||||
// texels uncompressed keeps them renderable at the cost of the memory saving, which is
|
||||
// strictly better than the INVALID_ENUM the application used to get. Note the signed
|
||||
// variants must land on SNORM storage - CTS uploads them as GL_BYTE.
|
||||
case GL_COMPRESSED_RED:
|
||||
case GL_COMPRESSED_RED_RGTC1:
|
||||
return TextureInternalFormat::R8;
|
||||
case GL_COMPRESSED_SIGNED_RED_RGTC1:
|
||||
return TextureInternalFormat::R8Snorm;
|
||||
case GL_COMPRESSED_RG:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
return TextureInternalFormat::RG8;
|
||||
case GL_COMPRESSED_SIGNED_RG_RGTC2:
|
||||
return TextureInternalFormat::RG8Snorm;
|
||||
case GL_COMPRESSED_RGB:
|
||||
return TextureInternalFormat::RGB8;
|
||||
case GL_COMPRESSED_RGBA:
|
||||
return TextureInternalFormat::RGBA8;
|
||||
case GL_COMPRESSED_SRGB:
|
||||
return TextureInternalFormat::SRGB8;
|
||||
case GL_COMPRESSED_SRGB_ALPHA:
|
||||
return TextureInternalFormat::SRGB8Alpha8;
|
||||
case GL_ALPHA:
|
||||
case GL_RED:
|
||||
return TextureInternalFormat::Red;
|
||||
|
||||
Reference in New Issue
Block a user