[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 5331150cb9
commit fe7a5ee1b2
5 changed files with 258 additions and 71 deletions
+31 -11
View File
@@ -1357,6 +1357,18 @@ namespace MobileGL::MG_Impl::GLImpl {
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
// 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
@@ -2648,17 +2660,25 @@ namespace MobileGL::MG_Impl::GLImpl {
}
}
// Special case for depth/stencil
if (textureInputFormat == TextureInputFormat::StencilIndex) {
if (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",
"No stencil buffer for stencil index format"));
return false;
}
// 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).
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(
textureInputFormat, textureObject->GetFormat(), texturePixelDataType)) {
return false;
}
// GetTexImage-specific: DEPTH_STENCIL readback needs a depth-stencil texture (a depth-only
// 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;
+108 -37
View File
@@ -175,61 +175,132 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
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,
TextureInternalFormat internalFormat,
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 ||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
type == TexturePixelDataType::UnsignedInt101111Rev) {
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev) {
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) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type"));
return false;
return recordInvalidOperation("Packed float RGB type requires RGB format");
}
}
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev ||
type == TexturePixelDataType::UnsignedInt5999Rev) {
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type"));
return false;
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev) {
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA &&
format != TextureInputFormat::RGBAInteger && format != TextureInputFormat::BGRAInteger) {
return recordInvalidOperation("Packed RGBA type requires RGBA/BGRA (integer) format");
}
}
if (internalFormat == TextureInternalFormat::DepthComponent ||
internalFormat == TextureInternalFormat::DepthComponent16 ||
internalFormat == TextureInternalFormat::DepthComponent24 ||
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 (type == TexturePixelDataType::UnsignedInt248 || type == TexturePixelDataType::Float32UnsignedInt248Rev) {
if (format != TextureInputFormat::DepthStencil) {
return recordInvalidOperation("Packed depth-stencil type requires DEPTH_STENCIL format");
}
}
if (format == TextureInputFormat::DepthComponent &&
(internalFormat != TextureInternalFormat::DepthComponent &&
internalFormat != TextureInternalFormat::DepthComponent16 &&
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 (format == TextureInputFormat::DepthStencil && type != TexturePixelDataType::UnsignedInt248 &&
type != TexturePixelDataType::Float32UnsignedInt248Rev) {
return recordInvalidOperation("DEPTH_STENCIL format requires a packed depth-stencil type");
}
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;
}