[Fix, Test] (MG_State, MG_Backend/DirectGLES, MG_Test): close three holes review found in the composite uniform mirror - unrecorded stage programs, byte-identical writes, and Espryt's baked image units

This commit is contained in:
2026-08-11 23:19:22 -04:00
parent ff324057ad
commit b4e07ce651
7 changed files with 183 additions and 17 deletions
@@ -2085,8 +2085,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
// the entry point because that one must never trigger a build (see
// ShaderStorageBlockBinding below). The signature is over the values, so an
// application that re-sets the same bindings every frame rebuilds nothing.
//
// The image-unit generation is a third of the same shape, and it used to be
// carried by accident: glUniform1i on an image uniform bumped the program's backend
// state version, which was in the program-pipeline composite's cache key, so a
// pipeline draw got a whole NEW composite object and therefore a fresh twin. Keying
// that cache on the link version instead (ProgramPipelineObject) removed the
// accident - and it never covered the monolithic glUseProgram path at all - so the
// dependency is stated here instead.
if (!twin->GetBackendProgramId() ||
twin->GetSyncedLinkVersion() != currentProgram->GetLinkVersion() ||
twin->GetSyncedImageUnitVersion() != currentProgram->GetImageUnitVersion() ||
twin->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask ||
twin->GetUnormFallbackClampOutputMask() != g_unormFallbackClampOutputMask ||
twin->GetFragColorBroadcastCount() != g_fragColorBroadcastCount ||
@@ -4537,6 +4537,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// driver's linked interface.
ReseedShaderStorageBlockBindings(m_backendProgramId, *stateProgramObject);
m_syncedLinkVersion = stateProgramObject->GetLinkVersion();
m_syncedImageUnitVersion = stateProgramObject->GetImageUnitVersion();
m_isInitialized = true;
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
@@ -1048,6 +1048,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Frontend link version this backend program (and its resource caches) was
// built from; a mismatch means every link-derived cache here is stale.
Uint32 GetSyncedLinkVersion() const { return m_syncedLinkVersion; }
// Image-uniform unit generation this backend program was GENERATED against.
// Separate from the link version because it is not link state: ES forbids
// glUniform1i on an image uniform, so RebindImageUniformsToFrontendUnits bakes the
// unit into the ESSL, and a program built before glUniform1i moved that unit is as
// stale as one built before a relink - while the sampler half, which really is
// re-issued per draw, needs nothing of the sort.
Uint32 GetSyncedImageUnitVersion() const { return m_syncedImageUnitVersion; }
private:
void CacheResourceLocations(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
@@ -1079,6 +1086,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint32 m_lastUploadedGlobalUboVersion = ~0u;
BufferImpl::UboRingAllocation m_globalUboRingAllocation;
Uint32 m_syncedLinkVersion = ~0u;
Uint32 m_syncedImageUnitVersion = ~0u;
SamplerPassMemo m_samplerPassMemo;
};