diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 2acd3094..95cbb065 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -11423,6 +11423,31 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindRenderbuffer(GL_RENDERBUFFER, m_backendRBOId); } + // P4a (D-D2): the four values BackendRenderbufferObject::SyncToBackend allocates from, + // spelled once per arm. Macros for the reason the texture-parameter block gives: in the + // PULL build each expands to the pre-P4a expression at its original site, so that + // build's tokens and its symbol sizes are unchanged (D-P). + // + // ARCHITECTURE.md:130 keeps the renderbuffer an INDEPENDENT frontend class while giving + // it the same discriminated MGPResourceDesc a texture gets, and this is where that pays: + // the same four fields, read out of the same record type, with Desc.Target telling the + // applier which of the three per-kind tables the record lives in. +#if MOBILEGL_PIPE_PUSH +#define MGB_RBO_FORMAT \ + (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.InternalFormat) \ + : stateRBOObject->GetInternalFormat()) +#define MGB_RBO_WIDTH (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.Width) : static_cast(stateRBOObject->GetWidth())) +#define MGB_RBO_HEIGHT \ + (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.Height) : static_cast(stateRBOObject->GetHeight())) +#define MGB_RBO_SAMPLES \ + (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.Samples) : static_cast(stateRBOObject->GetSamples())) +#else +#define MGB_RBO_FORMAT stateRBOObject->GetInternalFormat() +#define MGB_RBO_WIDTH static_cast(stateRBOObject->GetWidth()) +#define MGB_RBO_HEIGHT static_cast(stateRBOObject->GetHeight()) +#define MGB_RBO_SAMPLES static_cast(stateRBOObject->GetSamples()) +#endif + void BackendRenderbufferObject::SyncToBackend( const SharedPtr& stateRBOObject) { #ifdef TRACY_ENABLE @@ -11436,6 +11461,45 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("Syncing RBO with backend ID %u to backend for state ID %u", m_backendRBOId, stateRBOObject->GetExternalIndex()); +#if MOBILEGL_PIPE_PUSH + const MG_Pipe::MGPipeResourceRecord* pushedRecord = nullptr; + if (TextureResourceSubsystemEnabled()) { + // MONOLITH GLUE, named as such: the Renderbuffer handle of an object this + // backend still arrives holding. Under a real split it rides in the payload. + const MG_Pipe::MGPipeHandle res = g_backendRenderbufferObjects.HandleOf(stateRBOObject.get()); + pushedRecord = PipeRenderbufferRecordForHandle(res); + if (pushedRecord == nullptr) { + MGLOG_E_ONCE("MGPipe: renderbuffer %u has no applier record on the handle arm, so " + "its storage cannot be allocated from the pushed descriptor " + "(handle {%u, %u})", + stateRBOObject->GetExternalIndex(), res.Slot, res.Gen); + return; + } + if (m_isInitialized && m_syncedResourceSerial != 0 && + m_syncedResourceSerial == pushedRecord->Serial) { + MGLOG_D("RBO %u already initialized with matching parameters, skipping re-allocation.", + stateRBOObject->GetExternalIndex()); + return; + } + } else { +#if !MOBILEGL_PIPE_LEGACY_MEMOS + // UNREACHABLE: ResolveTextureResourceSubsystemArm stops at its first call when + // the bit is clear and the pre-handle arm is not compiled. Kept, and kept loud. + MGLOG_E_ONCE("MGPipe: the texture-resource subsystem bit is clear and " + "MOBILEGL_PIPE_LEGACY_MEMOS=0 removed the pre-handle renderbuffer " + "four-field cache, so this configuration has no arm at all"); + return; +#else + if (m_isInitialized && m_cacheInternalFormat == stateRBOObject->GetInternalFormat() && + m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight() && + m_cacheSamples == stateRBOObject->GetSamples()) { + MGLOG_D("RBO %u already initialized with matching parameters, skipping re-allocation.", + stateRBOObject->GetExternalIndex()); + return; + } +#endif + } +#else if (m_isInitialized && m_cacheInternalFormat == stateRBOObject->GetInternalFormat() && m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight() && m_cacheSamples == stateRBOObject->GetSamples()) { @@ -11443,14 +11507,15 @@ namespace MobileGL::MG_Backend::DirectGLES { stateRBOObject->GetExternalIndex()); return; } +#endif Bind(); // Allocate storage - TextureInternalFormat internalFormat = stateRBOObject->GetInternalFormat(); - Int width = static_cast(stateRBOObject->GetWidth()); - Int height = static_cast(stateRBOObject->GetHeight()); - Int samples = static_cast(stateRBOObject->GetSamples()); + TextureInternalFormat internalFormat = MGB_RBO_FORMAT; + Int width = MGB_RBO_WIDTH; + Int height = MGB_RBO_HEIGHT; + Int samples = MGB_RBO_SAMPLES; GLenum glInternalFormat, glType, glFormat; TextureImpl::GenerateRenderbufferFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType); @@ -11492,10 +11557,22 @@ namespace MobileGL::MG_Backend::DirectGLES { m_cacheWidth = width; m_cacheHeight = height; m_cacheSamples = samples; +#if MOBILEGL_PIPE_PUSH + // Stamped in the same breath as the four cache members and AFTER the allocation, so + // an allocation the driver refused with GL_OUT_OF_MEMORY above leaves the twin + // describing what it actually holds. The deferred OOM report and its RecordError are + // untouched: the error still lands on whatever entry point triggered the sync, which + // is where the deferred model puts it. + if (pushedRecord != nullptr) m_syncedResourceSerial = pushedRecord->Serial; +#endif m_isInitialized = true; MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId); } +#undef MGB_RBO_FORMAT +#undef MGB_RBO_WIDTH +#undef MGB_RBO_HEIGHT +#undef MGB_RBO_SAMPLES TwinRegistry g_backendRenderbufferObjects; diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 7164d588..822c1f15 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -2525,6 +2525,20 @@ namespace MobileGL::MG_Backend::DirectGLES { Int m_cacheWidth = 0; Int m_cacheHeight = 0; Int m_cacheSamples = 0; +#if MOBILEGL_PIPE_PUSH + // P4a (D-D2/D-B3): the resource record's Serial at the last completed allocation. + // It replaces the four-field cache above AS A GATE - the four members stay, because + // they are also what the legacy arm compares and what the twin reports about the + // storage it actually holds - and it closes the publication hole D-D2 names: + // RenderbufferObject::{SetInternalFormat, AllocateStorage, SetSamples} bump no + // version and raise no notice, so `glBindRenderbuffer; glRenderbufferStorage(new)` + // on an ALREADY-ATTACHED renderbuffer moved nothing the framebuffer bit could see. + // The client now emits resource_respecify straight from those three mutators, the + // applier bumps this serial, and one compare here sees it. + // + // Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P). + Uint64 m_syncedResourceSerial = 0; +#endif }; extern TwinRegistry