diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.h b/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.h index 61b75424..46bd54f6 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.h @@ -120,10 +120,9 @@ namespace MobileGL::MG_State::GLState { // L1 shader-translation memo key for this program's SPIR-V (see // MG_Util/ShaderTranspiler/TranslationCache.h). Built HERE, at the tail of phase // A, and not by phase B - two reasons, both structural: - // * the key covers the four link-time request maps and the merged opaque - // bindings, and one of those (explicitOpaqueUniformBindings) lives in - // `artifacts`, which phase B is forbidden to read because the GL-thread join - // moves it out from under phase B; + // * the key covers the three link-time request maps, which live in `in` - and + // it has to be built before the link, because a hit is what makes the link + // unnecessary; // * built once, it serves both the lookup and the insert, so the program's // sources are copied into the blob exactly once per link. // Invalid (null blob) when the cache is disabled, or when a stage arrived @@ -168,10 +167,11 @@ namespace MobileGL::MG_State::GLState { // with any other, and an attached shader that failed to compile. Split out of // ConsumeShaders so they still run - in the same order, with the same diagnostics - // BEFORE the L1 memo is consulted, rather than behind a hit that would skip them. - // The two lexical side channels the relaxed parse cannot provide, merged across - // stages. Reads the compile snapshots only, so it runs before any parse - the merged - // opaque bindings are part of the L1 memo key. Sets artifacts.infoLog and leaves - // linkStatus false when two stages disagree on an explicit uniform location. + // Merges the per-stage explicit default-block uniform locations glslang recorded at + // compile time. Reads the compile snapshots only, so it runs before any parse - and + // before the L1 memo, so a hit can never paper over a program that must fail to link. + // Sets artifacts.infoLog and leaves linkStatus false when two stages disagree on an + // explicit uniform location. void MergeShaderSideChannels(); Bool ValidateAttachedShaders(); Bool ConsumeShaders(Vector>& outShaders); diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index 86059076..8158e0f7 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -155,7 +155,7 @@ namespace MobileGL::MG_State::GLState { // // The failure case is covered too: the info log stays queryable because nothing is // cleared. And if the stored TShader already fed a link, the no-op leaves - // preprocessedSource and both side-channel maps intact, which is precisely what + // preprocessedSource and the explicit-location snapshot intact, which is precisely what // ClaimParsedShader's on-demand re-parse needs - a real recompile would have handed // the next link a fresh parse, the no-op hands it a fresh re-parse of the identical // source instead. Same result, one parse either way. diff --git a/MobileGL/MG_Test/Program/AsyncSpirvPhaseTest.cpp b/MobileGL/MG_Test/Program/AsyncSpirvPhaseTest.cpp index bcd91279..d0df8541 100644 --- a/MobileGL/MG_Test/Program/AsyncSpirvPhaseTest.cpp +++ b/MobileGL/MG_Test/Program/AsyncSpirvPhaseTest.cpp @@ -877,7 +877,7 @@ TEST_F(AsyncSpirvPhaseTest, AsyncOffAndAsyncOnProduceIdenticalSpirvAndShadow) { // The ASYNC arm runs FIRST, deliberately. Both arms must compile the same source text for // their SPIR-V to be comparable, and the first arm to run is the one that pays for the // cold path: it misses the per-context ShaderPreprocessCache and therefore executes - // PreprocessShaderSource, the reserved-identifier scan and both lexical extractions. Run + // PreprocessShaderSource and the lexical rejection scans. Run // the sync arm first and the async arm becomes a cache hit that never runs any of that on // a worker - which is exactly the half this case exists to compare. const SingleWorkerScope oneWorker; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 0827ab6e..a268b1e6 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -3169,9 +3169,9 @@ void main() { fragColor = vec4(pow(uBase, 2.2), 1.0); } // Layer 1 - the same shader object re-sourced with byte-identical text keeps its // compiled state, and glCompileShader on it is a no-op. // Layer 2 - two DIFFERENT shader objects holding byte-identical text share the -// source-only half of the pipeline (preprocess + lexical checks + -// side-channel extraction) through the context's ShaderPreprocessCache, -// while each still gets its own glslang parse. +// source-only half of the pipeline (preprocess + the lexical rejection +// checks) through the context's ShaderPreprocessCache, while each still +// gets its own glslang parse. // --------------------------------------------------------------------------- namespace { const char* kP0bVs = R"(#version 330 core