[Fix] (MG_Impl/GLImpl, MG_State, MG_Backend/DirectGLES): eliminate packed_pixels SIGTRAPs - complete TexImage format/type/internalformat validation matrix (depth-stencil family, integer-ness, packed-type pairing, 3D depth rejection), fix inverted UpdateSubData assert with clamped copy, demote unimplemented readback asserts to logged no-ops

This commit is contained in:
2026-07-16 02:23:18 -04:00
parent 3a40778c4b
commit 273c7ebcf0
5 changed files with 258 additions and 71 deletions
+28 -21
View File
@@ -3266,17 +3266,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("ReadPixels: x=%d y=%d w=%d h=%d format=%s type=%s pixels=%p", x, y, width, height, MGLOG_D("ReadPixels: x=%d y=%d w=%d h=%d format=%s type=%s pixels=%p", x, y, width, height,
MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(type).c_str(), pixels); MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(type).c_str(), pixels);
MOBILEGL_ASSERT(format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_RED || // Unimplemented readback formats degrade to a logged no-op instead of killing the process;
format == GL_RED_INTEGER || format == GL_DEPTH_COMPONENT || format == GL_STENCIL_INDEX, // spec-invalid combinations are already rejected with GL errors at the state layer.
"Only GL_RGBA, GL_RGBA_INTEGER, GL_RED, GL_RED_INTEGER, GL_DEPTH_COMPONENT and " if (format != GL_RGBA && format != GL_RGBA_INTEGER && format != GL_RED && format != GL_RED_INTEGER &&
"GL_STENCIL_INDEX are supported currently, " format != GL_DEPTH_COMPONENT && format != GL_STENCIL_INDEX) {
"while requested %s.", MGLOG_E("ReadPixels: format %s is not implemented yet, skipping readback",
MG_Util::ConvertGLEnumToString(format).c_str()); MG_Util::ConvertGLEnumToString(format).c_str());
MOBILEGL_ASSERT(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT || type == GL_UNSIGNED_INT_2_10_10_10_REV || return;
type == GL_INT || type == GL_FLOAT, }
"Only GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_UNSIGNED_INT_2_10_10_10_REV, " if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_INT_2_10_10_10_REV &&
"GL_INT and GL_FLOAT are supported currently, while requested %s.", type != GL_INT && type != GL_FLOAT) {
MG_Util::ConvertGLEnumToString(type).c_str()); MGLOG_E("ReadPixels: type %s is not implemented yet, skipping readback",
MG_Util::ConvertGLEnumToString(type).c_str());
return;
}
MGLOG_D("ReadPixels: SyncNeccessaryTextures()"); MGLOG_D("ReadPixels: SyncNeccessaryTextures()");
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
@@ -3362,16 +3365,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertGLEnumToString(target).c_str(), level, MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(target).c_str(), level, MG_Util::ConvertGLEnumToString(format).c_str(),
MG_Util::ConvertGLEnumToString(type).c_str(), pixels); MG_Util::ConvertGLEnumToString(type).c_str(), pixels);
MOBILEGL_ASSERT(format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_BGRA, // Unimplemented readback formats degrade to a logged no-op instead of killing the process;
"Only GL_RGBA, GL_RGBA_INTEGER and GL_BGRA are supported currently, while requested %s.", // spec-invalid combinations are already rejected with GL errors at the state layer.
MG_Util::ConvertGLEnumToString(format).c_str()); if (format != GL_RGBA && format != GL_RGBA_INTEGER && format != GL_BGRA) {
MOBILEGL_ASSERT(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT || type == GL_UNSIGNED_INT_2_10_10_10_REV || MGLOG_E("GetTexImage: format %s is not implemented yet, skipping readback",
type == GL_INT || type == GL_FLOAT || type == GL_UNSIGNED_INT_8_8_8_8 || MG_Util::ConvertGLEnumToString(format).c_str());
type == GL_UNSIGNED_INT_8_8_8_8_REV || type == GL_HALF_FLOAT, return;
"Only GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_UNSIGNED_INT_2_10_10_10_REV, " }
"GL_INT, GL_FLOAT, GL_HALF_FLOAT, GL_UNSIGNED_INT_8_8_8_8 and GL_UNSIGNED_INT_8_8_8_8_REV " if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_INT_2_10_10_10_REV &&
"are supported currently, while requested %s.", type != GL_INT && type != GL_FLOAT && type != GL_UNSIGNED_INT_8_8_8_8 &&
MG_Util::ConvertGLEnumToString(type).c_str()); type != GL_UNSIGNED_INT_8_8_8_8_REV && type != GL_HALF_FLOAT) {
MGLOG_E("GetTexImage: type %s is not implemented yet, skipping readback",
MG_Util::ConvertGLEnumToString(type).c_str());
return;
}
GLenum esFormat = format, esType = type; GLenum esFormat = format, esType = type;
if (esFormat == GL_BGRA) esFormat = GL_RGBA; if (esFormat == GL_BGRA) esFormat = GL_RGBA;
+31 -11
View File
@@ -1357,6 +1357,18 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadTarget, level)) return; if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadTarget, level)) return;
// Depth and depth-stencil formats are not three-dimensional in core GL (2D-array targets are fine).
if ((textureUploadTarget == TextureUploadTarget::Texture3D ||
textureUploadTarget == TextureUploadTarget::ProxyTexture3D) &&
(textureInputFormat == TextureInputFormat::DepthComponent ||
textureInputFormat == TextureInputFormat::DepthStencil)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Depth 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 // 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_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 // GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER
@@ -2648,17 +2660,25 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
} }
// Special case for depth/stencil // Shared format/type/internal-format matrix (packed-type pairing, depth-vs-color mismatch,
if (textureInputFormat == TextureInputFormat::StencilIndex) { // integer-ness). Also rejects STENCIL_INDEX readback, which needs GL_ARB_texture_stencil8
if (textureObject->GetFormat() != TextureInternalFormat::DepthStencil && // (not advertised by MobileGL).
textureObject->GetFormat() != TextureInternalFormat::Depth24Stencil8 && if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(
textureObject->GetFormat() != TextureInternalFormat::Depth32FStencil8) { textureInputFormat, textureObject->GetFormat(), texturePixelDataType)) {
MG_State::pGLContext->RecordError( return false;
ErrorCode::InvalidOperation, }
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No stencil buffer for stencil index format")); // GetTexImage-specific: DEPTH_STENCIL readback needs a depth-stencil texture (a depth-only
return false; // texture has no stencil data to return).
} if (textureInputFormat == TextureInputFormat::DepthStencil &&
textureObject->GetFormat() != TextureInternalFormat::DepthStencil &&
textureObject->GetFormat() != TextureInternalFormat::Depth24Stencil8 &&
textureObject->GetFormat() != TextureInternalFormat::Depth32FStencil8) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"DEPTH_STENCIL readback requires a depth-stencil texture"));
return false;
} }
return true; return true;
+108 -37
View File
@@ -175,61 +175,132 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
return true; return true;
} }
static Bool IsIntegerColorInputFormat(TextureInputFormat format) {
return format == TextureInputFormat::RInteger || format == TextureInputFormat::RGInteger ||
format == TextureInputFormat::RGBInteger || format == TextureInputFormat::BGRInteger ||
format == TextureInputFormat::RGBAInteger || format == TextureInputFormat::BGRAInteger;
}
static Bool IsIntegerColorInternalFormat(TextureInternalFormat internalFormat) {
switch (internalFormat) {
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
case TextureInternalFormat::RGB10A2UI:
return true;
default:
return false;
}
}
static Bool IsDepthLikeInternalFormat(TextureInternalFormat internalFormat) {
switch (internalFormat) {
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32: // not core, kept for Minecraft 1.21.5+
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return true;
default:
return false;
}
}
static Bool IsDepthLikeInputFormat(TextureInputFormat format) {
return format == TextureInputFormat::DepthComponent || format == TextureInputFormat::DepthStencil ||
format == TextureInputFormat::StencilIndex;
}
// Mirrors the desktop-GL validity matrix used by GL CTS packed_pixels (glcPackedPixelsTests
// isFormatValid, INPUT_TEXIMAGE): packed-type/format pairing, depth-vs-color mismatch, and
// integer-ness matching all raise GL_INVALID_OPERATION instead of reaching the upload path.
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
TextureInternalFormat internalFormat, TextureInternalFormat internalFormat,
TexturePixelDataType type) { TexturePixelDataType type) {
const auto recordInvalidOperation = [](const char* message) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
message));
return false;
};
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev || if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev || type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev) {
type == TexturePixelDataType::UnsignedInt101111Rev) { if (format != TextureInputFormat::RGB && format != TextureInputFormat::RGBInteger) {
return recordInvalidOperation("Packed RGB type requires RGB or RGB_INTEGER format");
}
}
if (type == TexturePixelDataType::UnsignedInt101111Rev || type == TexturePixelDataType::UnsignedInt5999Rev) {
if (format != TextureInputFormat::RGB) { if (format != TextureInputFormat::RGB) {
MG_State::pGLContext->RecordError( return recordInvalidOperation("Packed float RGB type requires RGB format");
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type"));
return false;
} }
} }
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev || if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev || type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev || type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev || type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev) {
type == TexturePixelDataType::UnsignedInt5999Rev) { if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA &&
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) { format != TextureInputFormat::RGBAInteger && format != TextureInputFormat::BGRAInteger) {
MG_State::pGLContext->RecordError( return recordInvalidOperation("Packed RGBA type requires RGBA/BGRA (integer) format");
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type"));
return false;
} }
} }
if (internalFormat == TextureInternalFormat::DepthComponent || if (type == TexturePixelDataType::UnsignedInt248 || type == TexturePixelDataType::Float32UnsignedInt248Rev) {
internalFormat == TextureInternalFormat::DepthComponent16 || if (format != TextureInputFormat::DepthStencil) {
internalFormat == TextureInternalFormat::DepthComponent24 || return recordInvalidOperation("Packed depth-stencil type requires DEPTH_STENCIL format");
internalFormat == TextureInternalFormat::DepthComponent32F) {
if (format != TextureInputFormat::DepthComponent) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for depth component internal format"));
return false;
} }
} }
if (format == TextureInputFormat::DepthComponent && if (format == TextureInputFormat::DepthStencil && type != TexturePixelDataType::UnsignedInt248 &&
(internalFormat != TextureInternalFormat::DepthComponent && type != TexturePixelDataType::Float32UnsignedInt248Rev) {
internalFormat != TextureInternalFormat::DepthComponent16 && return recordInvalidOperation("DEPTH_STENCIL format requires a packed depth-stencil type");
internalFormat != TextureInternalFormat::DepthComponent24 &&
internalFormat != TextureInternalFormat::DepthComponent32F &&
internalFormat != TextureInternalFormat::DepthComponent32 // workaround for Minecraft 1.21.5+
)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid internal format for depth component format"));
return false;
} }
if (IsIntegerColorInputFormat(format) &&
(type == TexturePixelDataType::Float || type == TexturePixelDataType::HalfFloat)) {
return recordInvalidOperation("Integer format cannot be used with a floating-point type");
}
// 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");
}
if (IsDepthLikeInputFormat(format) != IsDepthLikeInternalFormat(internalFormat)) {
return recordInvalidOperation("Depth/stencil-ness of format and internal format must match");
}
if (IsIntegerColorInputFormat(format) != IsIntegerColorInternalFormat(internalFormat)) {
return recordInvalidOperation("Integer-ness of format and internal format must match");
}
return true; return true;
} }
@@ -31,11 +31,12 @@ namespace MobileGL {
auto& targetData = m_data; auto& targetData = m_data;
MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range"); MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range");
auto& levelData = targetData[level]; auto& levelData = targetData[level];
MOBILEGL_ASSERT(levelData.size() <= input.size, "UpdateSubData: input data larger than allocated"); MOBILEGL_ASSERT(input.size <= levelData.size(), "UpdateSubData: input data larger than allocated");
if (input.data && input.size > 0) { if (input.data && input.size > 0) {
const Uint8* src = static_cast<const Uint8*>(input.data); const Uint8* src = static_cast<const Uint8*>(input.data);
Memcpy(levelData.data(), src, input.size); // Clamp so a size mismatch can never write past the allocation.
Memcpy(levelData.data(), src, std::min(input.size, levelData.size()));
m_isDirty[level] = true; m_isDirty[level] = true;
} }
} }
+88
View File
@@ -257,6 +257,94 @@ TEST_F(TextureTest, BoundTexImage2DUnpacksPackedBgra8888ToRgba8WithPixelStoreSki
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
} }
// GL CTS packed_pixels feeds every format/type/internalformat combination to TexImage and expects
// GL_INVALID_OPERATION for the invalid ones; these used to slip through validation and SIGTRAP in
// the shadow-storage upload path.
TEST_F(TextureTest, TexImage2DRejectsMismatchedFormatCombinations) {
GLuint texture = 0;
MG_Impl::GLImpl::GenTextures(1, &texture);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
// Depth-stencil internal format with a color format.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 2, 2, 0, GL_BGR, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// Color internal format with a depth format.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// Stencil-only uploads do not exist in core 3.3.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 2, 2, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// Packed depth-stencil type with a color format.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_INT_24_8, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// DEPTH_STENCIL format requires one of the two packed depth-stencil types.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 2, 2, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE,
nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// 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_RGBA_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_RGBA, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// Integer formats cannot be paired with floating-point types.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 2, 2, 0, GL_RGBA_INTEGER, GL_FLOAT, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// UNSIGNED_INT_5_9_9_9_REV pairs with RGB only.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB9_E5, 2, 2, 0, GL_RGBA, GL_UNSIGNED_INT_5_9_9_9_REV, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
}
TEST_F(TextureTest, TexImage2DAcceptsSpecCompliantFormatCombinations) {
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_DEPTH24_STENCIL8, 2, 2, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
// Depth-component internal format accepts DEPTH_STENCIL input (stencil bits are dropped).
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 2, 2, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 2, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
// Packed RGB types allow the integer variant of the RGB format.
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, 2, 2, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE_3_3_2,
nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB9_E5, 2, 2, 0, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, TexImage3DRejectsDepthFormatsForThreeDimensionalTarget) {
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, GL_DEPTH24_STENCIL8, 2, 2, 2, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
// 2D-array targets remain valid for depth formats.
GLuint arrayTexture = 0;
MG_Impl::GLImpl::GenTextures(1, &arrayTexture);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, 2, 2, 2, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, BoundTexSubImage2DUnpacksPackedBgra8888RevToRgba8) { TEST_F(TextureTest, BoundTexSubImage2DUnpacksPackedBgra8888RevToRgba8) {
GLuint texture = 0; GLuint texture = 0;
MG_Impl::GLImpl::GenTextures(1, &texture); MG_Impl::GLImpl::GenTextures(1, &texture);