mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[Feat, Test] (ShaderTranspiler, DirectGLES): carry rgb10_a2ui storage images in rgba16ui and split its packed upload
This commit is contained in:
@@ -2901,19 +2901,63 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return widenedData.data();
|
||||
}
|
||||
|
||||
// The rgb10_a2 / rgb10_a2ui shadow split into the four GL_UNSIGNED_SHORT channel CODES its
|
||||
// GL_RGBA16UI carrier is uploaded as. GL_UNSIGNED_INT_2_10_10_10_REV puts the FIRST
|
||||
// component in the LOW bits (that is what REV means), so red is bits 0-9, green 10-19,
|
||||
// blue 20-29 and alpha 30-31.
|
||||
//
|
||||
// The same split serves both formats: an rgb10_a2ui channel's code IS its value, and an
|
||||
// rgb10_a2 channel's code is the numerator of value = code / (2^b - 1) that the shader-side
|
||||
// unpack divides out. Neither is scaled here - the carrier holds the format's own bits.
|
||||
//
|
||||
// Sized from the LEVEL, not the source, for the reason PrepareChannelWidenedUpload is: the
|
||||
// driver reads a full width*height*depth*4 shorts for the transfer it was handed.
|
||||
const void* PreparePackedIntWidenedUpload(const IntVec3& texelSize, const void* data,
|
||||
SizeT byteSize, Vector<Uint8>& widenedData) {
|
||||
constexpr SizeT kSourceTexelBytes = sizeof(Uint32);
|
||||
if (data == nullptr || byteSize < kSourceTexelBytes) {
|
||||
return data;
|
||||
}
|
||||
const SizeT texelCount = static_cast<SizeT>(std::max(texelSize.x(), 0)) *
|
||||
static_cast<SizeT>(std::max(texelSize.y(), 0)) *
|
||||
static_cast<SizeT>(std::max(texelSize.z(), 1));
|
||||
if (texelCount == 0) {
|
||||
return data;
|
||||
}
|
||||
const SizeT copyTexelCount = std::min(texelCount, byteSize / kSourceTexelBytes);
|
||||
|
||||
widenedData.assign(texelCount * 4u * sizeof(Uint16), 0);
|
||||
const auto* src = static_cast<const Uint8*>(data);
|
||||
auto* dst = reinterpret_cast<Uint16*>(widenedData.data());
|
||||
for (SizeT i = 0; i < texelCount; ++i, dst += 4) {
|
||||
Uint32 packed = 0;
|
||||
if (i < copyTexelCount) {
|
||||
// Through a memcpy rather than a Uint32 read of `src`: the shadow is a byte
|
||||
// buffer with no alignment promise of its own.
|
||||
Memcpy(&packed, src + i * kSourceTexelBytes, sizeof(packed));
|
||||
}
|
||||
dst[0] = static_cast<Uint16>(packed & 0x3FFu);
|
||||
dst[1] = static_cast<Uint16>((packed >> 10u) & 0x3FFu);
|
||||
dst[2] = static_cast<Uint16>((packed >> 20u) & 0x3FFu);
|
||||
dst[3] = static_cast<Uint16>((packed >> 30u) & 0x3u);
|
||||
}
|
||||
return widenedData.data();
|
||||
}
|
||||
|
||||
// The transfer half of the image-format widening: an image-bindable texture whose ES
|
||||
// storage was widened to a core carrier is described to the driver as a four-component
|
||||
// transfer, so its narrower client data has to be repacked the same way the three-channel
|
||||
// colour-renderable widening repacks its own.
|
||||
//
|
||||
// Two shapes, because the carriers come in two kinds. Seventeen of the eighteen keep the
|
||||
// frontend format's component TYPE and only add channels, so padding the shadow out to
|
||||
// four components is the whole conversion. r11f_g11f_b10f does not: its shadow is one
|
||||
// PACKED 32-bit word per texel and its carrier is GL_RGBA16F, so the word has to be
|
||||
// DECODED into four floats. Reading it as three components of the carrier's type - what
|
||||
// the repack below would do - would take twelve bytes from a four-byte texel and shear
|
||||
// the level, which is what the allFormats LOAD walkers see and the STORE ones do not (a
|
||||
// store overwrites every texel the upload got wrong).
|
||||
// Three shapes, because the carriers come in three kinds. Most of them keep the frontend
|
||||
// format's component TYPE and only add channels, so padding the shadow out to four
|
||||
// components is the whole conversion. The two PACKED formats do not: their shadow is one
|
||||
// 32-bit word per texel, so the word has to be split - into four floats for
|
||||
// r11f_g11f_b10f's GL_RGBA16F, into four shorts for rgb10_a2ui's GL_RGBA16UI. Reading such
|
||||
// a word as components of the carrier's type - what the repack below would do - takes
|
||||
// twelve or sixteen bytes from a four-byte texel and shears the level, which is what the
|
||||
// allFormats LOAD walkers see and the STORE ones do not (a store overwrites every texel
|
||||
// the upload got wrong).
|
||||
//
|
||||
// Composes with PrepareFallbackUpload rather than replacing it, and the composition is a
|
||||
// no-op by construction: none of the widened formats is one GetWidenableClientComponentCount
|
||||
@@ -2926,8 +2970,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (!widening || widening.SourceChannels == 0 || widening.SourceChannels > 4) {
|
||||
return data;
|
||||
}
|
||||
if (widening.PackedFloatSource) {
|
||||
switch (widening.SourceEncoding) {
|
||||
case TextureImpl::ImageWidenSourceEncoding::PackedFloat11f11f10f:
|
||||
return PreparePackedFloatWidenedUpload(texelSize, data, byteSize, widenedData);
|
||||
case TextureImpl::ImageWidenSourceEncoding::PackedInt2101010Rev:
|
||||
return PreparePackedIntWidenedUpload(texelSize, data, byteSize, widenedData);
|
||||
case TextureImpl::ImageWidenSourceEncoding::Components:
|
||||
break;
|
||||
}
|
||||
if (widening.SourceChannels == 4) {
|
||||
return data;
|
||||
@@ -5395,6 +5444,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// here whose carrier has a different per-channel layout. See
|
||||
// WidenImageFormatsPass.h.
|
||||
case glslang::ElfR11fG11fB10f: return 0x8C3A; // GL_R11F_G11F_B10F
|
||||
// 10/10/10/2 unsigned INTEGER channels in an rgba16ui: same component type, same
|
||||
// channel count, every value representable. Only the transfer is re-encoded.
|
||||
case glslang::ElfRgb10a2ui: return 0x906F; // GL_RGB10_A2UI
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user