From 1bf12be278379414631509693a4486ed83f4c271 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 5 May 2026 12:58:36 +0800 Subject: [PATCH] [Fix] (MG_Util/ShaderTranspiler): add preprocessing to remove name-collided glsl functions --- .../ShaderSourceProcessor.cpp | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp index f1ff29f1..1c5602be 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp @@ -8,6 +8,89 @@ #include "ShaderSourceProcessor.h" +#include + +namespace { + using MobileGL::SizeT; + + bool IsIdentifierChar(char ch) { + return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_'; + } + + bool HasSingleLineFunctionDefinition(const MobileGL::String& source, const MobileGL::String& functionName) { + SizeT lineStart = 0; + while (lineStart < source.size()) { + SizeT lineEnd = source.find('\n', lineStart); + if (lineEnd == MobileGL::String::npos) { + lineEnd = source.size(); + } + + SizeT functionPos = source.find(functionName, lineStart); + while (functionPos != MobileGL::String::npos && functionPos < lineEnd) { + const bool hasLeftBoundary = functionPos == 0 || !IsIdentifierChar(source[functionPos - 1]); + const SizeT functionEnd = functionPos + functionName.size(); + const bool hasRightBoundary = + functionEnd >= source.size() || !IsIdentifierChar(source[functionEnd]); + if (hasLeftBoundary && hasRightBoundary) { + SizeT probe = functionEnd; + while (probe < lineEnd && std::isspace(static_cast(source[probe]))) { + probe++; + } + if (probe < lineEnd && source[probe] == '(') { + const SizeT closingParen = source.find(')', probe); + if (closingParen != MobileGL::String::npos && closingParen < lineEnd) { + probe = closingParen + 1; + while (probe < lineEnd && std::isspace(static_cast(source[probe]))) { + probe++; + } + if (probe < lineEnd && source[probe] == '{') { + return true; + } + } + } + } + + functionPos = source.find(functionName, functionPos + functionName.size()); + } + + lineStart = lineEnd + 1; + } + + return false; + } + + void RenameFunctionInvocations(MobileGL::String& source, const MobileGL::String& from, const MobileGL::String& to) { + SizeT pos = 0; + while ((pos = source.find(from, pos)) != MobileGL::String::npos) { + const bool hasLeftBoundary = pos == 0 || !IsIdentifierChar(source[pos - 1]); + const SizeT end = pos + from.size(); + const bool hasRightBoundary = end >= source.size() || !IsIdentifierChar(source[end]); + + SizeT probe = end; + while (probe < source.size() && std::isspace(static_cast(source[probe]))) { + probe++; + } + + if (hasLeftBoundary && hasRightBoundary && probe < source.size() && source[probe] == '(') { + source.replace(pos, from.size(), to); + pos += to.size(); + continue; + } + + pos = end; + } + } + + void RenameBuiltinShadowingFunction(MobileGL::String& source, const char* from, const char* to) { + const MobileGL::String fromName = from; + if (!HasSingleLineFunctionDefinition(source, fromName)) { + return; + } + + RenameFunctionInvocations(source, fromName, to); + } +} // namespace + namespace MobileGL { namespace MG_Util { namespace ShaderTranspiler { @@ -75,6 +158,10 @@ namespace MobileGL { source = replacement; } } + + // Some shader packs define helpers with built-in GLSL names such as round(). + // These may pass OpenGL-style validation but fail when recompiled for Vulkan/SPIR-V generation. + RenameBuiltinShadowingFunction(source, "round", "mg_round"); } } // namespace ShaderTranspiler