mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
[Feat, Fix, Test] (ShaderTranspiler, DirectGLES): carry the seven normalized image formats as their own codes in rgba16ui
This commit is contained in:
@@ -1088,7 +1088,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
backendObj = MakeShared<BackendTextureObject>();
|
||||
}
|
||||
if (imageBindableStorageRequired) {
|
||||
backendObj->RequireImageBindableStorage();
|
||||
backendObj->RequireImageBindableStorage(textureObject);
|
||||
}
|
||||
backendObj->SyncTextureParamsToBackend(textureObject);
|
||||
backendObj->SyncBuiltinSamplerToBackend(textureObject);
|
||||
@@ -7687,9 +7687,25 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// scratch framebuffer, so the frontend's READ binding describes a different image entirely -
|
||||
// consulting it there would both miss real widenings and corrupt readbacks of ordinary
|
||||
// textures taken while some unrelated widened attachment happened to be bound.
|
||||
// The image-format widening's READ half, for the seven normalized formats whose carrier holds
|
||||
// their channels as INTEGER CODES (GL_RGBA16 stored as a GL_RGBA16UI - see
|
||||
// TextureImpl::GetImageBindableStorageWidening). Nothing else in the readback would get those
|
||||
// right: the attachment is an integer one while the application's format is normalized, so the
|
||||
// class check below would refuse the read outright, and a repack that got past it would hand
|
||||
// back 65535.0 where GL owes 1.0.
|
||||
//
|
||||
// Inactive (ChannelMax all zero) for every other read, which is all but a handful.
|
||||
struct NormalizedImageCarrierRead {
|
||||
Uint ChannelMax[4] = {0u, 0u, 0u, 0u};
|
||||
Bool SignedNormalized = false;
|
||||
|
||||
Bool Active() const { return ChannelMax[0] != 0u; }
|
||||
};
|
||||
|
||||
static Bool ReadPixelsViaFormatConversion(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, void* pixels, Bool honorPackImageParams,
|
||||
Bool applyFixedPointReadClamp, Bool forceOpaqueAlpha) {
|
||||
Bool applyFixedPointReadClamp, Bool forceOpaqueAlpha,
|
||||
const NormalizedImageCarrierRead& normalizedCarrier = {}) {
|
||||
ReadbackChannelMapping mapping{};
|
||||
if (!GetReadbackChannelMapping(format, mapping)) {
|
||||
return false;
|
||||
@@ -7712,7 +7728,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const GLenum attachmentComponentType = QueryReadAttachmentComponentType();
|
||||
const Bool integerAttachment =
|
||||
attachmentComponentType == GL_INT || attachmentComponentType == GL_UNSIGNED_INT;
|
||||
if (mapping.isInteger != integerAttachment) {
|
||||
// A normalized image carrier is EXACTLY the case where the two disagree on purpose, and
|
||||
// it is the caller - which knows the TEXTURE being read, not just the attachment - that
|
||||
// says so. An integer client format through such a carrier is not a shape GL can ask for
|
||||
// (the frontend format is normalized), so it is refused here rather than converted.
|
||||
if (normalizedCarrier.Active() && (mapping.isInteger || !integerAttachment)) {
|
||||
MGLOG_E_ONCE("Readback conversion: a normalized image carrier was read as %s, which is not a "
|
||||
"normalized client format; skipping",
|
||||
MG_Util::ConvertGLEnumToString(format).c_str());
|
||||
return true;
|
||||
}
|
||||
if (!normalizedCarrier.Active() && mapping.isInteger != integerAttachment) {
|
||||
MGLOG_E_ONCE("Readback conversion: integer-ness of format %s does not match the read buffer, skipping",
|
||||
MG_Util::ConvertGLEnumToString(format).c_str());
|
||||
return true;
|
||||
@@ -7732,7 +7758,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
};
|
||||
WideReadCandidate candidates[4];
|
||||
Int candidateCount = 0;
|
||||
if (mapping.isInteger) {
|
||||
if (normalizedCarrier.Active()) {
|
||||
// The storage IS an integer texture, whatever the application's format says, so the
|
||||
// only read that can answer is the integer one. The codes it hands back are turned
|
||||
// into the floats the client asked for below.
|
||||
candidates[candidateCount++] = {GL_RGBA_INTEGER, GL_UNSIGNED_INT};
|
||||
} else if (mapping.isInteger) {
|
||||
if (GetWideReadChannelCount(static_cast<GLenum>(implFormat)) > 0 && IsIntegerReadFormat(implFormat) &&
|
||||
(implType == GL_INT || implType == GL_UNSIGNED_INT)) {
|
||||
candidates[candidateCount++] = {static_cast<GLenum>(implFormat), static_cast<GLenum>(implType)};
|
||||
@@ -7794,6 +7825,32 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (normalizedCarrier.Active()) {
|
||||
// GL 4.6 2.3.5, the same conversion the shader-side unpack does and with the same
|
||||
// denominators, so a texel an imageStore wrote and a texel the upload seeded read back
|
||||
// identically: f = c / (2^b - 1) unsigned, f = max(c / (2^(b-1) - 1), -1) signed, with
|
||||
// the signed code recovered from the low sixteen bits of the unsigned channel.
|
||||
const SizeT pixelCount = static_cast<SizeT>(width) * static_cast<SizeT>(height);
|
||||
Vector<Uint8> floatWide(pixelCount * 4 * sizeof(Float));
|
||||
auto* dst = reinterpret_cast<Float*>(floatWide.data());
|
||||
const auto* src = reinterpret_cast<const Uint32*>(wide.data());
|
||||
for (SizeT i = 0; i < pixelCount; ++i) {
|
||||
for (SizeT channel = 0; channel < 4; ++channel) {
|
||||
const Uint32 code = src[i * 4 + channel];
|
||||
const auto denominator = static_cast<Float>(normalizedCarrier.ChannelMax[channel]);
|
||||
if (normalizedCarrier.SignedNormalized) {
|
||||
const auto signedCode = static_cast<Int16>(static_cast<Uint16>(code));
|
||||
dst[i * 4 + channel] =
|
||||
std::max(static_cast<Float>(signedCode) / denominator, -1.0f);
|
||||
} else {
|
||||
dst[i * 4 + channel] = static_cast<Float>(code) / denominator;
|
||||
}
|
||||
}
|
||||
}
|
||||
wide = Move(floatWide);
|
||||
wideType = GL_FLOAT;
|
||||
readChannels = 4;
|
||||
}
|
||||
if (wideType == GL_UNSIGNED_INT_2_10_10_10_REV) {
|
||||
// Unpack the packed words into a float wide buffer (full 10-bit precision on e.g.
|
||||
// GL_RGB10_A2 attachments, whose implementation read pair is RGBA/2_10_10_10_REV).
|
||||
@@ -8441,6 +8498,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// GL_READ_FRAMEBUFFER, so the widening question has to be asked of the texture.
|
||||
const Bool forceOpaqueAlpha =
|
||||
TextureImpl::BackendTextureFormatAddsAlpha(textureObject->GetFormat(), textureObject->GetTarget());
|
||||
// An image-bindable texture in one of the seven normalized formats has its ES storage
|
||||
// in a GL_RGBA16UI, holding the format's own channel CODES. glGetTexImage still owes
|
||||
// the application the NORMALIZED value, so the conversion has to be undone here - and
|
||||
// it can only be asked of the TEXTURE, which is why it is not derived from the
|
||||
// attachment the scratch framebuffer happens to hold.
|
||||
NormalizedImageCarrierRead normalizedCarrier;
|
||||
if (const auto imageWidening =
|
||||
TextureImpl::GetImageBindableStorageWidening(textureObject->GetFormat());
|
||||
imageWidening && imageWidening.CarriesNormalizedCodes() &&
|
||||
(*backendTextureSlot)->RequiresImageBindableStorage()) {
|
||||
for (SizeT channel = 0; channel < 4; ++channel) {
|
||||
normalizedCarrier.ChannelMax[channel] = imageWidening.ChannelMax[channel];
|
||||
}
|
||||
normalizedCarrier.SignedNormalized = imageWidening.SignedNormalized;
|
||||
}
|
||||
// GL_PACK_IMAGE_HEIGHT/GL_PACK_SKIP_IMAGES only apply to 3D/array image
|
||||
// readbacks (cube-map arrays address as arrays); 2D targets must ignore
|
||||
// them (GL 3.3 section 6.1.4). A 1D ARRAY is one of those 2D targets: GL hands it back
|
||||
@@ -8550,7 +8622,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
void* sliceDst = static_cast<Uint8*>(pixels) + sliceOffset;
|
||||
if (!ReadPixelsViaFormatConversion(0, 0, size.x(), size.y(), format, type, sliceDst,
|
||||
/*honorPackImageParams=*/false,
|
||||
/*applyFixedPointReadClamp=*/false, forceOpaqueAlpha)) {
|
||||
/*applyFixedPointReadClamp=*/false, forceOpaqueAlpha,
|
||||
normalizedCarrier)) {
|
||||
allSlicesRead = false;
|
||||
break;
|
||||
}
|
||||
@@ -8573,7 +8646,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (tempFBOComplete && ReadPixelsViaFormatConversion(0, 0, size.x(), size.y(), format, type, pixels,
|
||||
applyPackImageParams,
|
||||
/*applyFixedPointReadClamp=*/false,
|
||||
forceOpaqueAlpha)) {
|
||||
forceOpaqueAlpha, normalizedCarrier)) {
|
||||
MGLOG_D("GetTexImage: finished via client-format conversion");
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user