[Fix] (MG_Backend/DirectGLES): clamp UNORM fallback writes

This commit is contained in:
2026-06-27 20:46:02 +08:00
parent 8fd25acbb6
commit f68c7296a6
7 changed files with 65 additions and 14 deletions
+1
View File
@@ -216,6 +216,7 @@ jobs:
trace_archive: tools/trace_replay/fixtures/minecraft-1.21.4-fabric-iris-bsl-in-world.tgz
trace_file: trace.trace
golden: tools/trace_replay/fixtures/minecraft-1.21.4-fabric-iris-bsl-in-world.0000110725.png
alternate_golden: tools/trace_replay/fixtures/minecraft-1.21.4-fabric-iris-bsl-in-world.0000110725-mali.png
target_call: 110725
width: 854
height: 480
@@ -744,7 +744,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendObj->SyncToBackend(currentProgram);
} else {
if (!backendObj->GetBackendProgramId() ||
backendObj->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask) {
backendObj->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask ||
backendObj->GetUnormFallbackClampOutputMask() != g_unormFallbackClampOutputMask) {
backendObj->SyncToBackend(currentProgram);
}
}
+40 -5
View File
@@ -1332,6 +1332,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
}
static Bool IsUnormFormat(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::R16:
case TextureInternalFormat::RG16:
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGBA16:
return true;
default:
return false;
}
}
static Bool IsSnormFallbackAttachment(
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject) {
if (attachmentObject.IsTexture()) {
@@ -1348,6 +1360,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
return false;
}
static Bool IsUnormFallbackAttachment(
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject) {
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
return textureObject && IsUnormFormat(textureObject->GetFormat()) &&
TextureImpl::ShouldUseCaveatTextureFormat(textureObject->GetFormat(), textureObject->GetTarget());
}
if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
return renderbufferObject &&
IsUnormFormat(renderbufferObject->GetInternalFormat()) &&
TextureImpl::ShouldUseCaveatRenderbufferFormat(renderbufferObject->GetInternalFormat());
}
return false;
}
void BackendFramebufferObject::SyncToBackend(
const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE
@@ -1399,7 +1427,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
if (asTarget == FramebufferTarget::Draw) {
Uint32 clampOutputMask = 0;
Uint32 snormClampOutputMask = 0;
Uint32 unormClampOutputMask = 0;
for (Uint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS && i < 32; ++i) {
const auto frontendBuf = stateDrawBuffers[i];
if (frontendBuf < FramebufferAttachmentType::Color0 ||
@@ -1408,10 +1437,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
const auto& attachmentObject = stateFBOObject->GetAttachment(frontendBuf);
if (IsSnormFallbackAttachment(attachmentObject)) {
clampOutputMask |= (1u << i);
snormClampOutputMask |= (1u << i);
} else if (IsUnormFallbackAttachment(attachmentObject)) {
unormClampOutputMask |= (1u << i);
}
}
PrgramImpl::g_snormFallbackClampOutputMask = clampOutputMask;
PrgramImpl::g_snormFallbackClampOutputMask = snormClampOutputMask;
PrgramImpl::g_unormFallbackClampOutputMask = unormClampOutputMask;
}
// 2. Remap read buffer
@@ -1527,6 +1559,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace PrgramImpl {
Uint32 g_snormFallbackClampOutputMask = 0;
Uint32 g_unormFallbackClampOutputMask = 0;
StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects;
BackendProgramObjectImpl::BackendProgramObjectImpl() {
@@ -1572,6 +1605,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing program to backend. State program ID: %u, Backend ID: %u",
stateProgramObject->GetExternalIndex(), m_backendProgramId);
m_snormFallbackClampOutputMask = g_snormFallbackClampOutputMask;
m_unormFallbackClampOutputMask = g_unormFallbackClampOutputMask;
// Detach all existing shaders
GLint attachedCount = 0;
@@ -1647,8 +1681,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = ForceFlatIntegerVaryings(source, glShaderType);
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
source = ForceSupporterOutput(source);
source = ClampSnormFallbackOutputs(std::move(source), glShaderType,
m_snormFallbackClampOutputMask);
source = ClampNormFallbackOutputs(std::move(source), glShaderType,
m_snormFallbackClampOutputMask,
m_unormFallbackClampOutputMask);
// Patch for Photon compiler precision issue
String findStr = "1000000.0";
@@ -285,16 +285,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint GetBackendProgramId() const { return m_backendProgramId; }
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
Uint32 GetSnormFallbackClampOutputMask() const { return m_snormFallbackClampOutputMask; }
Uint32 GetUnormFallbackClampOutputMask() const { return m_unormFallbackClampOutputMask; }
private:
Uint m_backendProgramId = 0;
Uint m_backendGlobalUBOId = 0;
Int m_baseInstanceUniformLocation = -1;
Uint32 m_snormFallbackClampOutputMask = 0;
Uint32 m_unormFallbackClampOutputMask = 0;
Bool m_isInitialized = false;
};
extern Uint32 g_snormFallbackClampOutputMask;
extern Uint32 g_unormFallbackClampOutputMask;
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
g_backendProgramObjects;
} // namespace PrgramImpl
+14 -7
View File
@@ -214,10 +214,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
return result;
}
String ClampSnormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 outputMask) {
String ClampNormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 snormOutputMask,
Uint32 unormOutputMask) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
const Uint32 outputMask = snormOutputMask | unormOutputMask;
if (shaderType != GL_FRAGMENT_SHADER || outputMask == 0) {
return glslCode;
}
@@ -226,14 +228,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
R"(layout\s*\(\s*location\s*=\s*([0-9]+)\s*\)\s*out\s+(?:(?:lowp|mediump|highp)\s+)?vec4\s+([A-Za-z_][A-Za-z0-9_]*)\s*;)");
std::sregex_iterator outputIt(glslCode.begin(), glslCode.end(), outputPattern);
std::sregex_iterator outputEnd;
Vector<String> outputNames;
struct OutputClamp {
String Name;
Bool Signed;
};
Vector<OutputClamp> outputClamps;
for (; outputIt != outputEnd; ++outputIt) {
const Uint location = static_cast<Uint>(std::stoul((*outputIt)[1].str()));
if (location < 32 && (outputMask & (1u << location))) {
outputNames.push_back((*outputIt)[2].str());
outputClamps.push_back({(*outputIt)[2].str(), static_cast<Bool>(snormOutputMask & (1u << location))});
}
}
if (outputNames.empty()) {
if (outputClamps.empty()) {
return glslCode;
}
@@ -252,9 +258,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
--depth;
if (depth == 0) {
String clampLine;
for (const String& outputName : outputNames) {
clampLine += "\n " + outputName + " = clamp(" + outputName +
", vec4(-1.0), vec4(1.0));";
for (const OutputClamp& outputClamp : outputClamps) {
const String minValue = outputClamp.Signed ? "-1.0" : "0.0";
clampLine += "\n " + outputClamp.Name + " = clamp(" + outputClamp.Name +
", vec4(" + minValue + "), vec4(1.0));";
}
clampLine += "\n";
glslCode.insert(pos, clampLine);
+2 -1
View File
@@ -48,7 +48,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode);
String ForceSupporterOutput(const String& glslCode);
String ClampSnormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 outputMask);
String ClampNormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 snormOutputMask,
Uint32 unormOutputMask);
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType);
String RemoveLayoutBinding(const String& glslCode);
} // namespace PrgramImpl