[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_archive: tools/trace_replay/fixtures/minecraft-1.21.4-fabric-iris-bsl-in-world.tgz
trace_file: trace.trace trace_file: trace.trace
golden: tools/trace_replay/fixtures/minecraft-1.21.4-fabric-iris-bsl-in-world.0000110725.png 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 target_call: 110725
width: 854 width: 854
height: 480 height: 480
@@ -744,7 +744,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendObj->SyncToBackend(currentProgram); backendObj->SyncToBackend(currentProgram);
} else { } else {
if (!backendObj->GetBackendProgramId() || if (!backendObj->GetBackendProgramId() ||
backendObj->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask) { backendObj->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask ||
backendObj->GetUnormFallbackClampOutputMask() != g_unormFallbackClampOutputMask) {
backendObj->SyncToBackend(currentProgram); 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( static Bool IsSnormFallbackAttachment(
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject) { const MG_State::GLState::FramebufferAttachmentObject& attachmentObject) {
if (attachmentObject.IsTexture()) { if (attachmentObject.IsTexture()) {
@@ -1348,6 +1360,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
return false; 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( void BackendFramebufferObject::SyncToBackend(
const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) { const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -1399,7 +1427,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
if (asTarget == FramebufferTarget::Draw) { 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) { for (Uint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS && i < 32; ++i) {
const auto frontendBuf = stateDrawBuffers[i]; const auto frontendBuf = stateDrawBuffers[i];
if (frontendBuf < FramebufferAttachmentType::Color0 || if (frontendBuf < FramebufferAttachmentType::Color0 ||
@@ -1408,10 +1437,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
const auto& attachmentObject = stateFBOObject->GetAttachment(frontendBuf); const auto& attachmentObject = stateFBOObject->GetAttachment(frontendBuf);
if (IsSnormFallbackAttachment(attachmentObject)) { 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 // 2. Remap read buffer
@@ -1527,6 +1559,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace PrgramImpl { namespace PrgramImpl {
Uint32 g_snormFallbackClampOutputMask = 0; Uint32 g_snormFallbackClampOutputMask = 0;
Uint32 g_unormFallbackClampOutputMask = 0;
StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects; StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects;
BackendProgramObjectImpl::BackendProgramObjectImpl() { BackendProgramObjectImpl::BackendProgramObjectImpl() {
@@ -1572,6 +1605,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing program to backend. State program ID: %u, Backend ID: %u", MGLOG_D("Syncing program to backend. State program ID: %u, Backend ID: %u",
stateProgramObject->GetExternalIndex(), m_backendProgramId); stateProgramObject->GetExternalIndex(), m_backendProgramId);
m_snormFallbackClampOutputMask = g_snormFallbackClampOutputMask; m_snormFallbackClampOutputMask = g_snormFallbackClampOutputMask;
m_unormFallbackClampOutputMask = g_unormFallbackClampOutputMask;
// Detach all existing shaders // Detach all existing shaders
GLint attachedCount = 0; GLint attachedCount = 0;
@@ -1647,8 +1681,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = ForceFlatIntegerVaryings(source, glShaderType); source = ForceFlatIntegerVaryings(source, glShaderType);
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType); source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
source = ForceSupporterOutput(source); source = ForceSupporterOutput(source);
source = ClampSnormFallbackOutputs(std::move(source), glShaderType, source = ClampNormFallbackOutputs(std::move(source), glShaderType,
m_snormFallbackClampOutputMask); m_snormFallbackClampOutputMask,
m_unormFallbackClampOutputMask);
// Patch for Photon compiler precision issue // Patch for Photon compiler precision issue
String findStr = "1000000.0"; String findStr = "1000000.0";
@@ -285,16 +285,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint GetBackendProgramId() const { return m_backendProgramId; } Uint GetBackendProgramId() const { return m_backendProgramId; }
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; } Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
Uint32 GetSnormFallbackClampOutputMask() const { return m_snormFallbackClampOutputMask; } Uint32 GetSnormFallbackClampOutputMask() const { return m_snormFallbackClampOutputMask; }
Uint32 GetUnormFallbackClampOutputMask() const { return m_unormFallbackClampOutputMask; }
private: private:
Uint m_backendProgramId = 0; Uint m_backendProgramId = 0;
Uint m_backendGlobalUBOId = 0; Uint m_backendGlobalUBOId = 0;
Int m_baseInstanceUniformLocation = -1; Int m_baseInstanceUniformLocation = -1;
Uint32 m_snormFallbackClampOutputMask = 0; Uint32 m_snormFallbackClampOutputMask = 0;
Uint32 m_unormFallbackClampOutputMask = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
extern Uint32 g_snormFallbackClampOutputMask; extern Uint32 g_snormFallbackClampOutputMask;
extern Uint32 g_unormFallbackClampOutputMask;
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
g_backendProgramObjects; g_backendProgramObjects;
} // namespace PrgramImpl } // namespace PrgramImpl
+14 -7
View File
@@ -214,10 +214,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
return result; return result;
} }
String ClampSnormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 outputMask) { String ClampNormFallbackOutputs(String glslCode, GLenum shaderType, Uint32 snormOutputMask,
Uint32 unormOutputMask) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
const Uint32 outputMask = snormOutputMask | unormOutputMask;
if (shaderType != GL_FRAGMENT_SHADER || outputMask == 0) { if (shaderType != GL_FRAGMENT_SHADER || outputMask == 0) {
return glslCode; 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*;)"); 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 outputIt(glslCode.begin(), glslCode.end(), outputPattern);
std::sregex_iterator outputEnd; std::sregex_iterator outputEnd;
Vector<String> outputNames; struct OutputClamp {
String Name;
Bool Signed;
};
Vector<OutputClamp> outputClamps;
for (; outputIt != outputEnd; ++outputIt) { for (; outputIt != outputEnd; ++outputIt) {
const Uint location = static_cast<Uint>(std::stoul((*outputIt)[1].str())); const Uint location = static_cast<Uint>(std::stoul((*outputIt)[1].str()));
if (location < 32 && (outputMask & (1u << location))) { 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; return glslCode;
} }
@@ -252,9 +258,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
--depth; --depth;
if (depth == 0) { if (depth == 0) {
String clampLine; String clampLine;
for (const String& outputName : outputNames) { for (const OutputClamp& outputClamp : outputClamps) {
clampLine += "\n " + outputName + " = clamp(" + outputName + const String minValue = outputClamp.Signed ? "-1.0" : "0.0";
", vec4(-1.0), vec4(1.0));"; clampLine += "\n " + outputClamp.Name + " = clamp(" + outputClamp.Name +
", vec4(" + minValue + "), vec4(1.0));";
} }
clampLine += "\n"; clampLine += "\n";
glslCode.insert(pos, clampLine); glslCode.insert(pos, clampLine);
+2 -1
View File
@@ -48,7 +48,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode); String ProcessOutColorLocations(const String& glslCode);
String ForceSupporterOutput(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 ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType);
String RemoveLayoutBinding(const String& glslCode); String RemoveLayoutBinding(const String& glslCode);
} // namespace PrgramImpl } // namespace PrgramImpl