mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +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,
|
// 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
|
// integer-ness). Also rejects a STENCIL_INDEX readback of anything but stencil-only
|
||||||
// (not advertised by MobileGL).
|
// storage, which is the only pairing GL 4.4 / ARB_texture_stencil8 ever made legal.
|
||||||
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(
|
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(
|
||||||
textureInputFormat, textureObject->GetFormat(), texturePixelDataType)) {
|
textureInputFormat, textureObject->GetFormat(), texturePixelDataType)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -313,9 +313,13 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TexImage in core 3.3 has no stencil-only upload path (that arrived with GL 4.4).
|
// The stencil-only transfer path arrived with GL 4.4 / ARB_texture_stencil8, and only ever
|
||||||
if (format == TextureInputFormat::StencilIndex) {
|
// pairs with stencil-only storage: against a depth, depth-stencil or colour internal format
|
||||||
return recordInvalidOperation("STENCIL_INDEX is not a valid texture upload 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)) {
|
if (IsDepthLikeInputFormat(format) != IsDepthLikeInternalFormat(internalFormat)) {
|
||||||
|
|||||||
@@ -1057,6 +1057,32 @@ TEST_F(TextureTest, TexImage2DAcceptsSpecCompliantFormatCombinations) {
|
|||||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
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
|
// 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
|
// 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.
|
// feeds the named channel, the other color channels default to 0 and alpha to 1.
|
||||||
|
|||||||
@@ -253,6 +253,12 @@ namespace MobileGL {
|
|||||||
return TextureInternalFormat::Depth32FStencil8;
|
return TextureInternalFormat::Depth32FStencil8;
|
||||||
case GL_STENCIL_INDEX8:
|
case GL_STENCIL_INDEX8:
|
||||||
return TextureInternalFormat::StencilIndex8;
|
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:
|
case GL_DEPTH_COMPONENT:
|
||||||
return TextureInternalFormat::DepthComponent;
|
return TextureInternalFormat::DepthComponent;
|
||||||
case GL_DEPTH_STENCIL:
|
case GL_DEPTH_STENCIL:
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ namespace MobileGL {
|
|||||||
case TextureInternalFormat::DepthComponent32F:
|
case TextureInternalFormat::DepthComponent32F:
|
||||||
case TextureInternalFormat::Depth24Stencil8:
|
case TextureInternalFormat::Depth24Stencil8:
|
||||||
case TextureInternalFormat::Depth32FStencil8:
|
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;
|
return internalformat;
|
||||||
// probably we should assume unorm here?
|
// probably we should assume unorm here?
|
||||||
case TextureInternalFormat::RGBA: {
|
case TextureInternalFormat::RGBA: {
|
||||||
|
|||||||
@@ -138,6 +138,11 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
case TextureInternalFormat::DepthComponent32F:
|
case TextureInternalFormat::DepthComponent32F:
|
||||||
out = {1, ShadowComponent::Float32, false};
|
out = {1, ShadowComponent::Float32, false};
|
||||||
return true;
|
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::R8:
|
||||||
case TextureInternalFormat::Red: out = {1, ShadowComponent::UNorm8, false}; return true;
|
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;
|
case TextureInputFormat::BGRAInteger: out = {{2, 1, 0, 3}, 4, true}; return true;
|
||||||
// A depth value converts like a single normalized/float channel.
|
// A depth value converts like a single normalized/float channel.
|
||||||
case TextureInputFormat::DepthComponent: out = {{0, -1, -1, -1}, 1, false}; return true;
|
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:
|
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,
|
const void* inputPixel,
|
||||||
Vector<Uint8>& outputPixel) {
|
Vector<Uint8>& outputPixel) {
|
||||||
outputPixel.clear();
|
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;
|
if (inputPixel == nullptr || !IsValidUnpackPixelPair(textureInputFormat, inputDataType)) return false;
|
||||||
|
|
||||||
PixelStoreParameters params{};
|
PixelStoreParameters params{};
|
||||||
|
|||||||
Reference in New Issue
Block a user