diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 5654752f..87c6d954 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -9775,14 +9775,20 @@ namespace MobileGL::MG_Backend::DirectGLES { if (MG_Config::Transport != MG_Config::TransportMode::Monolith) { const MG_Pipe::MGPipeHandle dstHandle = MG_Pipe::MGPipeApplier().VerbCopyTexDst; const auto* dstRecord = PipeTextureRecordForHandle(dstHandle); - auto* backendTextureSlot = TextureImpl::g_backendTextureObjects.FindByHandle(dstHandle); - if (backendTextureSlot == nullptr || *backendTextureSlot == nullptr || dstRecord == nullptr) { + // P5e (tx2): SYNCED, not merely looked up. The destination of a copy is not sampled + // by the draw program, so the per-draw unit list - which is the sampler-view window + // now - never brings it across; before P5e the frontend walk over every slot of every + // touched unit happened to sync it as a side effect. The named narrowing (P5e-5) says + // the union that still covers every texture includes "the waited texture ops", and + // this is one of them: it syncs its own endpoint by handle. + auto& backendTexture = TextureImpl::SyncTextureToBackendByHandle(dstHandle); + if (!backendTexture || dstRecord == nullptr) { MGLOG_E_ONCE("CopyTexImage2D: the verb's destination texture {%u, %u} has no twin " "or no applier record on this side", dstHandle.Slot, dstHandle.Gen); return; } - dstBackendTexture = backendTextureSlot->get(); + dstBackendTexture = backendTexture.get(); mgInternalFormat = static_cast(dstRecord->Desc.InternalFormat); } else #endif @@ -9890,14 +9896,16 @@ namespace MobileGL::MG_Backend::DirectGLES { // client's unit binding slot or the client allocator (T2/T4). if (MG_Config::Transport != MG_Config::TransportMode::Monolith) { const MG_Pipe::MGPipeHandle dstHandle = MG_Pipe::MGPipeApplier().VerbCopyTexDst; - auto* backendTextureSlot = TextureImpl::g_backendTextureObjects.FindByHandle(dstHandle); - if (backendTextureSlot == nullptr || *backendTextureSlot == nullptr) { + // P5e (tx2): synced by handle - see CopyTexImage2D's note. A copy destination is not + // in the sampler-view window, so nothing else on this path would build its twin. + auto& backendTexture = TextureImpl::SyncTextureToBackendByHandle(dstHandle); + if (!backendTexture) { MGLOG_E_ONCE("CopyTexSubImage2D: the verb's destination texture {%u, %u} has no " "twin on this side", dstHandle.Slot, dstHandle.Gen); return; } - dstBackendTexture = backendTextureSlot->get(); + dstBackendTexture = backendTexture.get(); } else #endif { diff --git a/MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp b/MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp index 1ff5215e..322b9016 100644 --- a/MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp +++ b/MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp @@ -65,6 +65,21 @@ namespace MobileGL { surface); std::abort(); } + + // P5e (tx2), ruling 12's shape (ID-90): THE NEW READ-ONLY ROWS ARE KEYED ON THE + // BACKEND KIND, and that is not a softening - it is the same line ยง6 draws for + // every other P5e guard. MAGMA KEEPS THE LOCKSTEP: a DirectVulkan server's + // records are all barriered and its blit path still asks a frontend texture + // whether it IsComplete() (VulkanRenderer's ResolveColorBlitBinding), which is a + // P7 debt and legal under P5C's rules for a client parked in its own wait. What + // P5e retires is ESPRYT's per-draw shape reads, so the new rows abort on a + // DirectGLES server and are silent on a DirectVulkan one. The MUTATOR rows above + // stay unconditional: no backend may write a frontend texture's storage from the + // apply thread, and none does. + void RefuseLegacyTextureShapeReadFromApplyThread(const char* surface) { + if (MG_Config::ActiveBackendType != BackendType::DirectGLES) return; + RefuseLegacyTextureArmFromApplyThread(surface); + } #endif // Overlapping OR abutting ([lo, hi) intervals meeting edge-to-edge) in @@ -113,7 +128,7 @@ namespace MobileGL { SizeT MipmapStorage::GetLevelCount() const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetMipmapLevelCount"); + RefuseLegacyTextureShapeReadFromApplyThread("GetMipmapLevelCount"); #endif return m_data.size(); } @@ -190,7 +205,7 @@ namespace MobileGL { GLenum MipmapStorage::GetCompressedFormat(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetCompressedFormat"); + RefuseLegacyTextureShapeReadFromApplyThread("GetCompressedFormat"); #endif if (level >= m_compressedFormats.size()) return GL_NONE; return m_compressedFormats[level]; @@ -198,7 +213,7 @@ namespace MobileGL { SizeT MipmapStorage::GetCompressedByteSize(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetCompressedByteSize"); + RefuseLegacyTextureShapeReadFromApplyThread("GetCompressedByteSize"); #endif if (level >= m_compressedData.size()) return 0; return m_compressedData[level].size(); @@ -206,7 +221,7 @@ namespace MobileGL { const void* MipmapStorage::MapCompressedData(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("MapCompressedMipmapData"); + RefuseLegacyTextureShapeReadFromApplyThread("MapCompressedMipmapData"); #endif if (level >= m_compressedData.size()) return nullptr; return m_compressedData[level].data(); @@ -219,7 +234,7 @@ namespace MobileGL { GLenum MipmapStorage::GetRequestedCompressedFormat(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetRequestedCompressedFormat"); + RefuseLegacyTextureShapeReadFromApplyThread("GetRequestedCompressedFormat"); #endif if (level >= m_requestedCompressedFormats.size()) return GL_NONE; return m_requestedCompressedFormats[level]; @@ -270,7 +285,7 @@ namespace MobileGL { IntVec3 MipmapStorage::GetTexelSize(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetMipmapTexelSize"); + RefuseLegacyTextureShapeReadFromApplyThread("GetMipmapTexelSize"); #endif auto& targetTexelSizes = m_texelSizes; if (level >= targetTexelSizes.size()) return {0, 0, 0}; @@ -279,7 +294,7 @@ namespace MobileGL { SizeT MipmapStorage::GetByteSize(Uint level) const { #if MOBILEGL_BUILD_DISAGGREGATED - RefuseLegacyTextureArmFromApplyThread("GetMipmapByteSize"); + RefuseLegacyTextureShapeReadFromApplyThread("GetMipmapByteSize"); #endif if (level >= m_data.size()) return 0; return m_data[level].size();