diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 61d336dc..59b6819c 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -7293,22 +7293,46 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedResourceSerial = record.Serial; return; } - // TRAILING (tx2 report, "left barriered"): the glTextureView CALL needs the view - // window and MGPResourceDesc has no carrier for it. The frontend object is taken when - // the monolith-glue note still reaches one - which is every case a single-process - // split has - and the refusal is NAMED rather than silent for the case that does not. - if (stateTextureObject) { - SyncTextureViewToBackend(stateTextureObject); - m_syncedResourceSerial = record.Serial; - return; + // The view window is a sampler-view CSO, created even when this + // texture is only image-bound or attached to an FBO. It is not part + // of the resource descriptor, and needs no frontend fallback. + (void)stateTextureObject; + const auto& applier = MG_Pipe::MGPipeApplier(); + const auto handle = record.ViewCso; + if (MG_Pipe::MGPipeHandleIsNull(handle) || handle.Slot >= applier.SamplerViewCsos.size()) { + MGLOG_F("MGPipe: Fatal{ProtocolCorruption, \"texture-view-cso\"} {%u,%u}", res.Slot, res.Gen); + std::abort(); } - MGLOG_E_ONCE("MGPipe: texture view {%u, %u} (GL %u) has to be (re-)created as a view of " - "{%u, %u}, and MGPResourceDesc carries no view window - minLevel, " - "numLevels, minLayer, numLayers have no wire field - so the by-handle arm " - "cannot issue glTextureView. P5e leaves view CREATION on the frontend arm; " - "this name will sample empty until it gets one.", - res.Slot, res.Gen, record.Desc.GlNameForDiag, record.Desc.ViewOf.Slot, - record.Desc.ViewOf.Gen); + const auto& cso = applier.SamplerViewCsos[handle.Slot]; + const auto& view = cso.View; + if (!cso.Live || cso.Gen != handle.Gen || view.Texture != res || !view.NumLevels || !view.NumLayers) { + MGLOG_F("MGPipe: Fatal{ProtocolCorruption, \"texture-view-window\"} {%u,%u}", res.Slot, res.Gen); + std::abort(); + } + const auto viewTarget = BufferImpl::StagedTextureTargetForPipeTarget(record.Desc.Target); + const GLenum nativeTarget = ConvertTextureTargetToBackendGLEnum(viewTarget); + GLenum internalFormat = 0, transferFormat = 0, transferType = 0; + GenerateTextureFormatInfo(static_cast(view.InternalFormat), + &internalFormat, &transferFormat, &transferType, viewTarget); + // A name already bound or used as a view cannot be redefined by + // glTextureView. This also invalidates native binding/FBO caches. + RecreateBackendTexture(); + DebugImpl::ErrorLopper::Clear(); + ResolveTextureViewEntryPoint()(m_backendTextureId, nativeTarget, storageBackendTextureId, + internalFormat, view.MinLevel, view.NumLevels, view.MinLayer, view.NumLayers); + const GLenum error = g_GLESFuncs.glGetError(); + if (error != GL_NO_ERROR) { + MGLOG_F("MGPipe: Fatal{ResourceUnavailable, \"texture-view-native\"} {%u,%u} error=0x%x", + res.Slot, res.Gen, error); + std::abort(); + } + m_viewSourceBackendTextureId = storageBackendTextureId; + m_isInitialized = true; + m_backendStorageImmutable = true; + m_prevTextureInfo = {static_cast(record.Desc.InternalFormat), + record.Desc.Width, record.Desc.Height, record.Desc.Depth, view.NumLevels, 0, + record.Desc.Samples, record.Desc.FixedSampleLocations != 0}; + m_syncedResourceSerial = record.Serial; } #endif diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 0214442e..12ef1d76 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -1827,13 +1827,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // stamp the record's Serial. That is the per-draw cost of every already-synced view // and it reads nothing from the client. // - // The CREATION of the view is the gap and it is named rather than papered over: the - // glTextureView call needs (minLevel, numLevels, minLayer, numLayers) and MGPResourceDesc - // carries none of the four - `ViewOf` is the only view field on the wire. So a view whose - // ES name has not been made a view YET, or whose storage was re-minted underneath it, - // still needs the frontend object and takes it when one is reachable; with no object it - // declines LOUDLY and the view samples its own (empty) name. Listed as trailing in the - // tx2 report with the wire fields it needs. + // Creation/recreation resolves record.ViewCso's complete view window + // and issues the native view call against that server-owned storage. + // No frontend texture is used to recover the level/layer range. void SyncTextureViewToBackendByRecord( MG_Pipe::MGPipeHandle res, const MG_Pipe::MGPipeResourceRecord& record, const SharedPtr& stateTextureObject);