[Fix] (MG_Util/ShaderTranspiler): add preprocessing to remove name-collided glsl functions

This commit is contained in:
2026-05-05 12:58:36 +08:00
parent 99b753be9a
commit 1bf12be278
@@ -8,6 +8,89 @@
#include "ShaderSourceProcessor.h"
#include <cctype>
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<unsigned char>(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<unsigned char>(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<unsigned char>(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