From 6ca48e40fe2a6201145528921c2bfbef73d8bb27 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Thu, 16 Jul 2026 06:47:33 -0400 Subject: [PATCH] [Feat] (MG_State, MG_Util, MG_Impl/GLImpl, MG_Backend/DirectGLES): desktop-GL single-channel client formats GL_GREEN/GL_BLUE/GL_ALPHA and _INTEGER variants - validate and readback via wide-RGBA channel extraction (GL CTS packed_pixels rgba8_format_green/blue read with them), unpack GREEN/BLUE(_INTEGER) TexImage uploads into the named channel with 0/1 defaults per table 3.3; GL_ALPHA keeps the legacy Red upload mapping (R8 storage + 000R swizzle), its readback corrected at the backend to source channel 3 --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 10 ++ .../MG_Impl/GLImpl/Texture/Validators.cpp | 4 +- .../GLState/TextureState/TextureEnum.h | 8 ++ .../MG_Test/Framebuffer/FramebufferTest.cpp | 45 ++++++++- MobileGL/MG_Test/Texture/TextureTest.cpp | 94 +++++++++++++++++++ .../GLToMG/TextureEnumConverter.cpp | 14 +++ .../Converters/GLToStr/GLEnumConverter.cpp | 1 + .../MGToGL/TextureEnumConverter.cpp | 12 +++ .../MGToStr/TextureEnumConverter.cpp | 12 +++ .../MGToVk/TextureEnumConverter.cpp | 10 ++ MobileGL/MG_Util/Metrics/TextureMetrics.cpp | 6 ++ .../MG_Util/Texture/PixelStoreProcessor.cpp | 6 ++ 12 files changed, 220 insertions(+), 2 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index b1075234..61b98e32 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -3284,6 +3284,16 @@ namespace MobileGL::MG_Backend::DirectGLES { switch (format) { case GL_RED: outMapping = {{0, 0, 0, 0}, 1, false}; return true; case GL_RED_INTEGER: outMapping = {{0, 0, 0, 0}, 1, true}; return true; + // Desktop-GL single-channel client formats (GL CTS packed_pixels rgba8_format_green/blue): + // the destination holds one component sourced from the named channel of the wide RGBA read. + // GL_ALPHA is mapped here from the raw enum because the state layer folds it into Red for the + // legacy alpha-texture upload hack. + case GL_GREEN: outMapping = {{1, 0, 0, 0}, 1, false}; return true; + case GL_GREEN_INTEGER: outMapping = {{1, 0, 0, 0}, 1, true}; return true; + case GL_BLUE: outMapping = {{2, 0, 0, 0}, 1, false}; return true; + case GL_BLUE_INTEGER: outMapping = {{2, 0, 0, 0}, 1, true}; return true; + case GL_ALPHA: outMapping = {{3, 0, 0, 0}, 1, false}; return true; + case GL_ALPHA_INTEGER: outMapping = {{3, 0, 0, 0}, 1, true}; return true; case GL_RG: outMapping = {{0, 1, 0, 0}, 2, false}; return true; case GL_RG_INTEGER: outMapping = {{0, 1, 0, 0}, 2, true}; return true; case GL_RGB: outMapping = {{0, 1, 2, 0}, 3, false}; return true; diff --git a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp index 833c63cc..f9713609 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp @@ -178,7 +178,9 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl { static Bool IsIntegerColorInputFormat(TextureInputFormat format) { return format == TextureInputFormat::RInteger || format == TextureInputFormat::RGInteger || format == TextureInputFormat::RGBInteger || format == TextureInputFormat::BGRInteger || - format == TextureInputFormat::RGBAInteger || format == TextureInputFormat::BGRAInteger; + format == TextureInputFormat::RGBAInteger || format == TextureInputFormat::BGRAInteger || + format == TextureInputFormat::GreenInteger || format == TextureInputFormat::BlueInteger || + format == TextureInputFormat::AlphaInteger; } static Bool IsIntegerColorInternalFormat(TextureInternalFormat internalFormat) { diff --git a/MobileGL/MG_State/GLState/TextureState/TextureEnum.h b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h index 7e777493..945d1b59 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureEnum.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h @@ -76,6 +76,14 @@ namespace MobileGL { BGRInteger, RGBAInteger, BGRAInteger, + // Desktop-GL single-channel client formats (table 3.3): the data holds one component that + // feeds the G, B or A channel; the remaining channels default to 0 (color) / 1 (alpha). + Green, + Blue, + Alpha, + GreenInteger, + BlueInteger, + AlphaInteger, StencilIndex, DepthComponent, DepthStencil, diff --git a/MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp b/MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp index 919f06b5..2d38e379 100644 --- a/MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp +++ b/MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp @@ -32,6 +32,8 @@ namespace { Int g_clearNamedFramebufferfvCallCount = 0; Int g_clearNamedFramebufferfiCallCount = 0; Int g_readPixelsCallCount = 0; + GLenum g_lastReadPixelsFormat = GL_NONE; + GLenum g_lastReadPixelsType = GL_NONE; void RecordBlitNamedFramebuffer(const SharedPtr& readFramebuffer, const SharedPtr& drawFramebuffer, @@ -66,8 +68,10 @@ namespace { ++g_clearNamedFramebufferfiCallCount; } - void RecordReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*) { + void RecordReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum format, GLenum type, void*) { ++g_readPixelsCallCount; + g_lastReadPixelsFormat = format; + g_lastReadPixelsType = type; } } // namespace @@ -97,6 +101,8 @@ protected: g_clearNamedFramebufferfvCallCount = 0; g_clearNamedFramebufferfiCallCount = 0; g_readPixelsCallCount = 0; + g_lastReadPixelsFormat = GL_NONE; + g_lastReadPixelsType = GL_NONE; MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer = nullptr; MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv = nullptr; MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi = nullptr; @@ -255,6 +261,43 @@ TEST_F(FramebufferTest, ReadPixelsRejectsMismatchedPackedTypeFormatPairs) { EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); } +TEST_F(FramebufferTest, ReadPixelsForwardsSingleChannelDesktopClientFormats) { + GLuint framebuffer = 0; + GLuint texture = 0; + MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer); + MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture); + MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 4, 4); + MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, texture, 0); + MG_Impl::GLImpl::BindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); + + MG_Backend::gBackendFunctionsTable.GL.ReadPixels = RecordReadPixels; + Uint8 pixelStorage[4 * 4 * 4] = {}; + + // Desktop GL treats GL_GREEN/GL_BLUE/GL_ALPHA as valid ReadPixels client formats (GL CTS + // packed_pixels rgba8_format_green failed with GL_INVALID_ENUM before). The state layer must + // validate them and forward the raw enum to the backend, which extracts the source channel + // from a wide RGBA read. + const GLenum singleChannelFormats[] = {GL_GREEN, GL_BLUE, GL_ALPHA}; + Int expectedCallCount = 0; + for (const GLenum format : singleChannelFormats) { + MG_Impl::GLImpl::ReadPixels(0, 0, 4, 4, format, GL_UNSIGNED_BYTE, pixelStorage); + EXPECT_EQ(g_readPixelsCallCount, ++expectedCallCount); + EXPECT_EQ(g_lastReadPixelsFormat, format); + EXPECT_EQ(g_lastReadPixelsType, static_cast(GL_UNSIGNED_BYTE)); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + } + + // Packed-type pairing still applies: packed RGB/RGBA types never pair with single-channel formats. + MG_Impl::GLImpl::ReadPixels(0, 0, 4, 4, GL_GREEN, GL_UNSIGNED_SHORT_5_6_5, pixelStorage); + EXPECT_EQ(g_readPixelsCallCount, expectedCallCount); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); + + // Integer client formats reject floating-point types. + MG_Impl::GLImpl::ReadPixels(0, 0, 4, 4, GL_GREEN_INTEGER, GL_FLOAT, pixelStorage); + EXPECT_EQ(g_readPixelsCallCount, expectedCallCount); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); +} + TEST_F(FramebufferTest, NamedRenderbufferStorageAndFramebufferAttachDoNotChangeBindings) { GLuint framebuffer = 0; GLuint renderbuffer = 0; diff --git a/MobileGL/MG_Test/Texture/TextureTest.cpp b/MobileGL/MG_Test/Texture/TextureTest.cpp index a9374109..c3039273 100644 --- a/MobileGL/MG_Test/Texture/TextureTest.cpp +++ b/MobileGL/MG_Test/Texture/TextureTest.cpp @@ -329,6 +329,100 @@ TEST_F(TextureTest, TexImage2DAcceptsSpecCompliantFormatCombinations) { EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); } +// 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. +TEST_F(TextureTest, BoundTexImage2DUnpacksGreenAndBlueIntoRgba8Channels) { + GLuint greenTexture = 0; + MG_Impl::GLImpl::GenTextures(1, &greenTexture); + MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, greenTexture); + + const Uint8 pixels[] = { + 10, 20, + 30, 40, + }; + MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 1); + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_GREEN, GL_UNSIGNED_BYTE, pixels); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + + const auto* storedGreen = GetBoundTexture2DLevelBytes(greenTexture); + const Uint8 expectedGreen[] = { + 0, 10, 0, 255, + 0, 20, 0, 255, + 0, 30, 0, 255, + 0, 40, 0, 255, + }; + for (SizeT i = 0; i < sizeof(expectedGreen); ++i) { + EXPECT_EQ(storedGreen[i], expectedGreen[i]) << "byte " << i; + } + + GLuint blueTexture = 0; + MG_Impl::GLImpl::GenTextures(1, &blueTexture); + MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, blueTexture); + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_BLUE, GL_UNSIGNED_BYTE, pixels); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + + const auto* storedBlue = GetBoundTexture2DLevelBytes(blueTexture); + const Uint8 expectedBlue[] = { + 0, 0, 10, 255, + 0, 0, 20, 255, + 0, 0, 30, 255, + 0, 0, 40, 255, + }; + for (SizeT i = 0; i < sizeof(expectedBlue); ++i) { + EXPECT_EQ(storedBlue[i], expectedBlue[i]) << "byte " << i; + } + MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 4); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); +} + +TEST_F(TextureTest, BoundTexImage2DUnpacksGreenIntegerIntoRgba8UiChannels) { + GLuint texture = 0; + MG_Impl::GLImpl::GenTextures(1, &texture); + MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture); + + const Uint8 pixels[] = { + 10, 20, + 30, 40, + }; + MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 1); + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 2, 2, 0, GL_GREEN_INTEGER, GL_UNSIGNED_BYTE, pixels); + MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 4); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + + const auto* stored = GetBoundTexture2DLevelBytes(texture); + // Missing integer channels default to R=0, B=0, A=1. + const Uint8 expected[] = { + 0, 10, 0, 1, + 0, 20, 0, 1, + 0, 30, 0, 1, + 0, 40, 0, 1, + }; + for (SizeT i = 0; i < sizeof(expected); ++i) { + EXPECT_EQ(stored[i], expected[i]) << "byte " << i; + } +} + +TEST_F(TextureTest, TexImage2DSingleChannelFormatsKeepIntegerNessRules) { + GLuint texture = 0; + MG_Impl::GLImpl::GenTextures(1, &texture); + MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture); + + // Integer-ness of format and internal format must match (both directions). + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_GREEN_INTEGER, GL_UNSIGNED_BYTE, nullptr); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 2, 2, 0, GL_BLUE, GL_UNSIGNED_BYTE, nullptr); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); + + // Integer formats reject floating-point types. + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 2, 2, 0, GL_BLUE_INTEGER, GL_FLOAT, nullptr); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); + + // Packed types never pair with single-channel formats. + MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_GREEN, GL_UNSIGNED_SHORT_5_6_5, nullptr); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION); +} + TEST_F(TextureTest, TexImage3DRejectsDepthFormatsForThreeDimensionalTarget) { GLuint texture = 0; MG_Impl::GLImpl::GenTextures(1, &texture); diff --git a/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp index f8785806..42ad434f 100644 --- a/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp @@ -58,9 +58,17 @@ namespace MobileGL { TextureInputFormat ConvertGLEnumToTextureInputFormat(GLenum format) { switch (format) { + // Legacy carve-out: GL_ALPHA stays mapped to Red so alpha-texture uploads keep landing in + // the R channel of the R8-backed storage (TexImage*_State pairs this with a 0,0,0,R + // swizzle). Readback of GL_ALPHA is corrected at the backend, which maps the raw enum to + // source channel 3 (DirectGLES GetReadbackChannelMapping). case GL_ALPHA: case GL_RED: return TextureInputFormat::Red; + case GL_GREEN: + return TextureInputFormat::Green; + case GL_BLUE: + return TextureInputFormat::Blue; case GL_RG: return TextureInputFormat::RG; case GL_RGB: @@ -73,6 +81,12 @@ namespace MobileGL { return TextureInputFormat::BGRA; case GL_RED_INTEGER: return TextureInputFormat::RInteger; + case GL_GREEN_INTEGER: + return TextureInputFormat::GreenInteger; + case GL_BLUE_INTEGER: + return TextureInputFormat::BlueInteger; + case GL_ALPHA_INTEGER: + return TextureInputFormat::AlphaInteger; case GL_RG_INTEGER: return TextureInputFormat::RGInteger; case GL_RGB_INTEGER: diff --git a/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp index 07cb4400..a9bb6334 100644 --- a/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp @@ -535,6 +535,7 @@ namespace MobileGL { CASE(GL_RED_INTEGER) CASE(GL_GREEN_INTEGER) CASE(GL_BLUE_INTEGER) + CASE(GL_ALPHA_INTEGER) CASE(GL_RGB_INTEGER) CASE(GL_RGBA_INTEGER) CASE(GL_BGR_INTEGER) diff --git a/MobileGL/MG_Util/Converters/MGToGL/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToGL/TextureEnumConverter.cpp index 864cf6de..f97b37bc 100644 --- a/MobileGL/MG_Util/Converters/MGToGL/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToGL/TextureEnumConverter.cpp @@ -67,6 +67,18 @@ namespace MobileGL { return GL_RGBA_INTEGER; case TextureInputFormat::BGRAInteger: return GL_BGRA_INTEGER; + case TextureInputFormat::Green: + return GL_GREEN; + case TextureInputFormat::Blue: + return GL_BLUE; + case TextureInputFormat::Alpha: + return GL_ALPHA; + case TextureInputFormat::GreenInteger: + return GL_GREEN_INTEGER; + case TextureInputFormat::BlueInteger: + return GL_BLUE_INTEGER; + case TextureInputFormat::AlphaInteger: + return GL_ALPHA_INTEGER; case TextureInputFormat::StencilIndex: return GL_STENCIL_INDEX; case TextureInputFormat::DepthComponent: diff --git a/MobileGL/MG_Util/Converters/MGToStr/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToStr/TextureEnumConverter.cpp index e43f6e20..92b9efb6 100644 --- a/MobileGL/MG_Util/Converters/MGToStr/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToStr/TextureEnumConverter.cpp @@ -67,6 +67,18 @@ namespace MobileGL { return "RGBAInteger"; case TextureInputFormat::BGRAInteger: return "BGRAInteger"; + case TextureInputFormat::Green: + return "Green"; + case TextureInputFormat::Blue: + return "Blue"; + case TextureInputFormat::Alpha: + return "Alpha"; + case TextureInputFormat::GreenInteger: + return "GreenInteger"; + case TextureInputFormat::BlueInteger: + return "BlueInteger"; + case TextureInputFormat::AlphaInteger: + return "AlphaInteger"; case TextureInputFormat::StencilIndex: return "StencilIndex"; case TextureInputFormat::DepthComponent: diff --git a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp index cb6802d8..66e45902 100644 --- a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp @@ -65,6 +65,16 @@ namespace MobileGL { return VK_FORMAT_R8G8B8A8_UINT; case TextureInputFormat::BGRAInteger: return VK_FORMAT_B8G8R8A8_UINT; + // Single-channel desktop client formats: the client memory holds one component per pixel, + // matching the R8 layouts (the channel it feeds is a pixel-transfer concern, not a layout one). + case TextureInputFormat::Green: + case TextureInputFormat::Blue: + case TextureInputFormat::Alpha: + return VK_FORMAT_R8_UNORM; + case TextureInputFormat::GreenInteger: + case TextureInputFormat::BlueInteger: + case TextureInputFormat::AlphaInteger: + return VK_FORMAT_R8_UINT; case TextureInputFormat::StencilIndex: return VK_FORMAT_S8_UINT; case TextureInputFormat::DepthComponent: diff --git a/MobileGL/MG_Util/Metrics/TextureMetrics.cpp b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp index 4bf7da45..c345ec3d 100644 --- a/MobileGL/MG_Util/Metrics/TextureMetrics.cpp +++ b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp @@ -113,6 +113,12 @@ namespace MobileGL { switch (format) { case TextureInputFormat::Red: case TextureInputFormat::RInteger: + case TextureInputFormat::Green: + case TextureInputFormat::GreenInteger: + case TextureInputFormat::Blue: + case TextureInputFormat::BlueInteger: + case TextureInputFormat::Alpha: + case TextureInputFormat::AlphaInteger: return 1; case TextureInputFormat::RG: case TextureInputFormat::RGInteger: diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp index 41fabf01..a667765c 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp @@ -201,6 +201,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { switch (format) { case TextureInputFormat::Red: out = {{0, -1, -1, -1}, 1, false}; return true; case TextureInputFormat::RInteger: out = {{0, -1, -1, -1}, 1, true}; return true; + case TextureInputFormat::Green: out = {{-1, 0, -1, -1}, 1, false}; return true; + case TextureInputFormat::GreenInteger: out = {{-1, 0, -1, -1}, 1, true}; return true; + case TextureInputFormat::Blue: out = {{-1, -1, 0, -1}, 1, false}; return true; + case TextureInputFormat::BlueInteger: out = {{-1, -1, 0, -1}, 1, true}; return true; + case TextureInputFormat::Alpha: out = {{-1, -1, -1, 0}, 1, false}; return true; + case TextureInputFormat::AlphaInteger: out = {{-1, -1, -1, 0}, 1, true}; return true; case TextureInputFormat::RG: out = {{0, 1, -1, -1}, 2, false}; return true; case TextureInputFormat::RGInteger: out = {{0, 1, -1, -1}, 2, true}; return true; case TextureInputFormat::RGB: out = {{0, 1, 2, -1}, 3, false}; return true;