mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Fix, Test] (TextureUtil, GLImpl): accept GL_STENCIL_INDEX as a stencil-only texture internal format
This commit is contained in:
@@ -4303,8 +4303,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
// Shared format/type/internal-format matrix (packed-type pairing, depth-vs-color mismatch,
|
||||
// integer-ness). Also rejects STENCIL_INDEX readback, which needs GL_ARB_texture_stencil8
|
||||
// (not advertised by MobileGL).
|
||||
// integer-ness). Also rejects a STENCIL_INDEX readback of anything but stencil-only
|
||||
// storage, which is the only pairing GL 4.4 / ARB_texture_stencil8 ever made legal.
|
||||
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(
|
||||
textureInputFormat, textureObject->GetFormat(), texturePixelDataType)) {
|
||||
return false;
|
||||
|
||||
@@ -313,9 +313,13 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TexImage in core 3.3 has no stencil-only upload path (that arrived with GL 4.4).
|
||||
if (format == TextureInputFormat::StencilIndex) {
|
||||
return recordInvalidOperation("STENCIL_INDEX is not a valid texture upload format");
|
||||
// The stencil-only transfer path arrived with GL 4.4 / ARB_texture_stencil8, and only ever
|
||||
// pairs with stencil-only storage: against a depth, depth-stencil or colour internal format
|
||||
// STENCIL_INDEX keeps the pre-4.4 answer (GL CTS packed_pixels feeds exactly that pairing
|
||||
// and expects INVALID_OPERATION).
|
||||
if (format == TextureInputFormat::StencilIndex &&
|
||||
internalFormat != TextureInternalFormat::StencilIndex8) {
|
||||
return recordInvalidOperation("STENCIL_INDEX requires a stencil-only internal format");
|
||||
}
|
||||
|
||||
if (IsDepthLikeInputFormat(format) != IsDepthLikeInternalFormat(internalFormat)) {
|
||||
|
||||
@@ -1057,6 +1057,32 @@ TEST_F(TextureTest, TexImage2DAcceptsSpecCompliantFormatCombinations) {
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
// GL_STENCIL_INDEX is the unsized base format for stencil-only storage, and refusing it as an
|
||||
// internal format killed the ARB_clear_texture stencil case in its own setup - before it could
|
||||
// reach the calls it actually tests. The stencil-only transfer format stays paired with
|
||||
// stencil-only storage in both directions, which is what keeps those clears erroring.
|
||||
TEST_F(TextureTest, StencilIndexIsATextureInternalFormatPairedOnlyWithStencilStorage) {
|
||||
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, GL_STENCIL_INDEX, 4, 4, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
|
||||
nullptr);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
ASSERT_NE(textureObject, nullptr);
|
||||
EXPECT_EQ(textureObject->GetFormat(), TextureInternalFormat::StencilIndex8);
|
||||
|
||||
// A colour transfer format against stencil storage is still INVALID_OPERATION, so the clear
|
||||
// the conformance case makes next fails the way it is supposed to.
|
||||
MG_Impl::GLImpl::ClearTexImage(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
ExpectSingleGlError(GL_INVALID_OPERATION);
|
||||
|
||||
// ...and the other direction: GL_STENCIL_INDEX against colour storage stays illegal.
|
||||
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, nullptr);
|
||||
ExpectSingleGlError(GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// Desktop GL table 3.3 lists GREEN and BLUE as TexImage client formats (GL CTS packed_pixels
|
||||
// rgba8_format_green/blue upload with them and verify the readback): the single input component
|
||||
// feeds the named channel, the other color channels default to 0 and alpha to 1.
|
||||
|
||||
@@ -253,6 +253,12 @@ namespace MobileGL {
|
||||
return TextureInternalFormat::Depth32FStencil8;
|
||||
case GL_STENCIL_INDEX8:
|
||||
return TextureInternalFormat::StencilIndex8;
|
||||
// The unsized stencil base format resolves to the only stencil storage there is, the
|
||||
// same way the unsized colour and depth base formats below resolve to theirs. Returning
|
||||
// Unknown made glTexImage2D(GL_STENCIL_INDEX) an error, which killed the negative
|
||||
// clear-texture cases in their own setup before they could reach the call they test.
|
||||
case GL_STENCIL_INDEX:
|
||||
return TextureInternalFormat::StencilIndex8;
|
||||
case GL_DEPTH_COMPONENT:
|
||||
return TextureInternalFormat::DepthComponent;
|
||||
case GL_DEPTH_STENCIL:
|
||||
|
||||
@@ -124,6 +124,9 @@ namespace MobileGL {
|
||||
case TextureInternalFormat::DepthComponent32F:
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
// Already sized: both GL_STENCIL_INDEX8 and the unsized GL_STENCIL_INDEX resolve here,
|
||||
// and there is only one stencil storage to infer.
|
||||
case TextureInternalFormat::StencilIndex8:
|
||||
return internalformat;
|
||||
// probably we should assume unorm here?
|
||||
case TextureInternalFormat::RGBA: {
|
||||
|
||||
@@ -138,6 +138,11 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
||||
case TextureInternalFormat::DepthComponent32F:
|
||||
out = {1, ShadowComponent::Float32, false};
|
||||
return true;
|
||||
// Stencil is the one single-channel INTEGER shadow that is not a colour format: eight
|
||||
// bits, held as an unsigned index rather than a normalized value.
|
||||
case TextureInternalFormat::StencilIndex8:
|
||||
out = {1, ShadowComponent::UInt8, true};
|
||||
return true;
|
||||
|
||||
case TextureInternalFormat::R8:
|
||||
case TextureInternalFormat::Red: out = {1, ShadowComponent::UNorm8, false}; return true;
|
||||
@@ -336,8 +341,13 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
||||
case TextureInputFormat::BGRAInteger: out = {{2, 1, 0, 3}, 4, true}; return true;
|
||||
// A depth value converts like a single normalized/float channel.
|
||||
case TextureInputFormat::DepthComponent: out = {{0, -1, -1, -1}, 1, false}; return true;
|
||||
// A stencil index is a single INTEGER channel (GL 4.6 core 8.4.4.3). Without this the
|
||||
// upload fell to the raw-memcpy branch, which copies the client element width into the
|
||||
// one-byte STENCIL_INDEX8 shadow verbatim - right for GL_UNSIGNED_BYTE and wrong for
|
||||
// every wider type. The state layer keeps this paired with stencil-only storage.
|
||||
case TextureInputFormat::StencilIndex: out = {{0, -1, -1, -1}, 1, true}; return true;
|
||||
default:
|
||||
return false; // stencil / packed depth-stencil / unknown
|
||||
return false; // packed depth-stencil / unknown
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,6 +1008,11 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
||||
const void* inputPixel,
|
||||
Vector<Uint8>& outputPixel) {
|
||||
outputPixel.clear();
|
||||
// A stencil index became a transferable format when STENCIL_INDEX8 texture storage did (see
|
||||
// GetUnpackChannelMapping), but this helper serves glClearBufferData, whose internal formats
|
||||
// are all colour (GL 4.6 core table 8.20): a stencil pattern would otherwise pass the size
|
||||
// check and land silently in an equally-sized colour store.
|
||||
if (textureInputFormat == TextureInputFormat::StencilIndex) return false;
|
||||
if (inputPixel == nullptr || !IsValidUnpackPixelPair(textureInputFormat, inputDataType)) return false;
|
||||
|
||||
PixelStoreParameters params{};
|
||||
|
||||
Reference in New Issue
Block a user