Files
MobileGL/MobileGL/MG_Util/Metrics/TextureMetrics.cpp
T
BZLZHH 45d506545e [Fix] (MG_Util, DirectVulkan): tolerate storage-less attachments in component-size queries
GetComponentSizesForInternalFormat asserted on TextureInternalFormat::Unknown,
which framebuffer-parameter queries legitimately reach for attachments that
have no storage yet (KHR-GL33.packed_depth_stencil.validate_errors.initial_state
aborted there). Answer with all-zero sizes and keep a warning for genuinely
unhandled formats. Also include the image dimensions in the texture
vmaCreateImage failure report.
2026-07-31 16:35:03 -04:00

521 lines
20 KiB
C++

// MobileGL - MobileGL/MG_Util/Metrics/TextureMetrics.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include "TextureMetrics.h"
#include "Defines.h"
#include "MG_Util/Math/VectorTypes.h"
namespace MobileGL {
namespace MG_Util {
SizeT GetSizedInternalFormatSizeInBytes(TextureInternalFormat internal) {
switch (internal) {
case TextureInternalFormat::R8:
case TextureInternalFormat::Red: // UNorm8 shadow layout
case TextureInternalFormat::R8Snorm:
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
return 1;
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R16F:
case TextureInternalFormat::RG8:
case TextureInternalFormat::RG: // UNorm8x2 shadow layout
case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::DepthComponent16:
return 2;
case TextureInternalFormat::R3G3B2: // UNorm8x3 shadow layout
case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB: // UNorm8x3 shadow layout
case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::DepthComponent24:
return 3;
case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGB5A1:
case TextureInternalFormat::RGBA: // UNorm8x4 shadow layout
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
case TextureInternalFormat::R32F:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::DepthStencil:
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG16F:
return 4;
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB10: // UNorm16x3 shadow layout
case TextureInternalFormat::RGB12: // UNorm16x3 shadow layout
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
return 6;
case TextureInternalFormat::RGBA12:
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::RGBA16Snorm:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA16F:
case TextureInternalFormat::RG32F:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
// Shadow bytes hold the GL_FLOAT_32_UNSIGNED_INT_24_8_REV wire format
// (float depth + a word whose low 8 bits are stencil), 8 bytes/texel.
case TextureInternalFormat::Depth32FStencil8:
return 8;
case TextureInternalFormat::RGB32F:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
return 12;
case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
return 16;
case TextureInternalFormat::R11FG11FB10F:
case TextureInternalFormat::RGB9E5:
return 4;
default:
return 0;
}
}
SizeT GetBaseInputFormatComponentCount(TextureInputFormat format) {
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:
return 2;
case TextureInputFormat::RGB:
case TextureInputFormat::BGR:
case TextureInputFormat::RGBInteger:
case TextureInputFormat::BGRInteger:
return 3;
case TextureInputFormat::RGBA:
case TextureInputFormat::BGRA:
case TextureInputFormat::RGBAInteger:
case TextureInputFormat::BGRAInteger:
return 4;
case TextureInputFormat::StencilIndex:
case TextureInputFormat::DepthComponent:
case TextureInputFormat::DepthStencil:
return 1;
default:
MGLOG_D("%s: Unknown input format!", __func__);
return 0;
}
}
SizeT GetBaseInternalFormatComponentCount(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::DepthStencil:
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
// Depth stencil is actually 2 components
// tho real formats always gives byte size in whole
// so we count this as one here
case TextureInternalFormat::Red:
case TextureInternalFormat::R8:
case TextureInternalFormat::R8Snorm:
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R16F:
case TextureInternalFormat::R32F:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
return 1;
case TextureInternalFormat::RG:
case TextureInternalFormat::RG8:
case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG16F:
case TextureInternalFormat::RG32F:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
return 2;
case TextureInternalFormat::RGB:
case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGB32F:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
case TextureInternalFormat::R11FG11FB10F:
case TextureInternalFormat::RGB9E5:
return 3;
case TextureInternalFormat::RGBA:
case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGBA12:
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::RGBA16Snorm:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA16F:
case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
return 4;
default:
return 0;
}
}
SizeT GetSizedTexturePixelDataTypeSize(TexturePixelDataType type) {
switch (type) {
case TexturePixelDataType::UnsignedByte332:
case TexturePixelDataType::UnsignedByte233Rev:
return 1;
case TexturePixelDataType::UnsignedShort565:
case TexturePixelDataType::UnsignedShort565Rev:
case TexturePixelDataType::UnsignedShort4444:
case TexturePixelDataType::UnsignedShort4444Rev:
case TexturePixelDataType::UnsignedShort5551:
case TexturePixelDataType::UnsignedShort1555Rev:
return 2;
case TexturePixelDataType::UnsignedInt8888:
case TexturePixelDataType::UnsignedInt8888Rev:
case TexturePixelDataType::UnsignedInt1010102:
case TexturePixelDataType::UnsignedInt2101010Rev:
case TexturePixelDataType::UnsignedInt101111Rev:
case TexturePixelDataType::UnsignedInt5999Rev:
case TexturePixelDataType::UnsignedInt248:
case TexturePixelDataType::Float32UnsignedInt248Rev:
return 4;
default:
return 0;
}
}
SizeT GetBaseTexturePixelDataTypeSize(TexturePixelDataType type) {
switch (type) {
case TexturePixelDataType::UnsignedByte:
case TexturePixelDataType::Byte:
return 1;
case TexturePixelDataType::UnsignedShort:
case TexturePixelDataType::HalfFloat:
case TexturePixelDataType::Short:
return 2;
case TexturePixelDataType::UnsignedInt:
case TexturePixelDataType::Float:
case TexturePixelDataType::Int:
return 4;
default:
return 0;
}
}
SizeT GetTexturePixelDataTypeSize(TexturePixelDataType type) {
SizeT sizedPixelFormatSize = GetSizedTexturePixelDataTypeSize(type);
if (sizedPixelFormatSize > 0) return sizedPixelFormatSize;
return GetBaseTexturePixelDataTypeSize(type);
}
SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type) {
SizeT sizedTextureFormatSize = GetSizedInternalFormatSizeInBytes(internalformat);
if (sizedTextureFormatSize > 0) return sizedTextureFormatSize;
SizeT sizedPixelFormatSize = GetSizedTexturePixelDataTypeSize(type);
if (sizedPixelFormatSize > 0) return sizedPixelFormatSize;
SizeT chCount = GetBaseInternalFormatComponentCount(internalformat);
SizeT bytesPerChannel = GetBaseTexturePixelDataTypeSize(type);
return chCount * bytesPerChannel;
}
SizeT GetInputBytesPerPixel(TextureInputFormat inputFormat, TexturePixelDataType type) {
SizeT sizedPixelFormatSize = GetSizedTexturePixelDataTypeSize(type);
if (sizedPixelFormatSize > 0) return sizedPixelFormatSize;
SizeT bytesPerChannel = GetBaseTexturePixelDataTypeSize(type);
SizeT chCount = GetBaseInputFormatComponentCount(inputFormat);
return chCount * bytesPerChannel;
}
SizeT CalculateInputTextureImageSize(TextureInputFormat inputFormat, TexturePixelDataType pixelDataType,
IntVec3 size) {
return GetInputBytesPerPixel(inputFormat, pixelDataType) * size.x() * size.y() * size.z();
}
ComponentSizes GetComponentSizesForInternalFormat(TextureInternalFormat internal) {
ComponentSizes s = {};
switch (internal) {
case TextureInternalFormat::R8:
case TextureInternalFormat::Red:
case TextureInternalFormat::R8Snorm:
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
s.Red = 8;
break;
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R16F:
s.Red = 16;
break;
case TextureInternalFormat::RG8:
case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG:
s.Red = 8;
s.Green = 8;
break;
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG16F:
s.Red = 16;
s.Green = 16;
break;
case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB:
s.Red = 8;
s.Green = 8;
s.Blue = 8;
break;
case TextureInternalFormat::RGB10:
s.Red = 10;
s.Green = 10;
s.Blue = 10;
break;
case TextureInternalFormat::RGB12:
s.Red = 12;
s.Green = 12;
s.Blue = 12;
break;
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
s.Red = 16;
s.Green = 16;
s.Blue = 16;
break;
case TextureInternalFormat::R3G3B2:
s.Red = 3;
s.Green = 3;
s.Blue = 2;
break;
case TextureInternalFormat::RGBA2:
s.Red = 2;
s.Green = 2;
s.Blue = 2;
s.Alpha = 2;
break;
case TextureInternalFormat::RGBA4:
s.Red = 4;
s.Green = 4;
s.Blue = 4;
s.Alpha = 4;
break;
case TextureInternalFormat::RGB5A1:
s.Red = 5;
s.Green = 5;
s.Blue = 5;
s.Alpha = 1;
break;
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGBA:
s.Red = 8;
s.Green = 8;
s.Blue = 8;
s.Alpha = 8;
break;
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
s.Red = 10;
s.Green = 10;
s.Blue = 10;
s.Alpha = 2;
break;
case TextureInternalFormat::R32F:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
s.Red = 32;
break;
case TextureInternalFormat::RG32F:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
s.Red = 32;
s.Green = 32;
break;
case TextureInternalFormat::RGBA12:
s.Red = 12;
s.Green = 12;
s.Blue = 12;
s.Alpha = 12;
break;
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::RGBA16Snorm:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA16F:
s.Red = 16;
s.Green = 16;
s.Blue = 16;
s.Alpha = 16;
break;
case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
s.Red = 16;
s.Green = 16;
s.Blue = 16;
break;
case TextureInternalFormat::RGB32F:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
s.Red = 32;
s.Green = 32;
s.Blue = 32;
break;
case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
s.Red = 32;
s.Green = 32;
s.Blue = 32;
s.Alpha = 32;
break;
case TextureInternalFormat::R11FG11FB10F:
s.Red = 11;
s.Green = 11;
s.Blue = 10;
break;
case TextureInternalFormat::RGB9E5:
s.Red = 9;
s.Green = 9;
s.Blue = 9;
break;
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent16:
s.Depth = 16;
break;
case TextureInternalFormat::DepthComponent24:
s.Depth = 24;
break;
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
s.Depth = 32;
break;
case TextureInternalFormat::DepthStencil:
case TextureInternalFormat::Depth24Stencil8:
s.Depth = 24;
s.Stencil = 8;
break;
case TextureInternalFormat::Depth32FStencil8:
s.Depth = 32;
s.Stencil = 8;
break;
case TextureInternalFormat::Unknown:
// Queried for attachments that have no storage yet (e.g. framebuffer
// parameter queries on the initial state); every size stays 0.
break;
default:
MGLOG_W("Unimplemented internal format in GetComponentSizesForInternalFormat: %d",
static_cast<Int>(internal));
break;
}
return s;
}
} // namespace MG_Util
} // namespace MobileGL