From fd60f9a7204da5254cb9c68ebacb69367d26b7c8 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 9 Oct 2026 20:54:32 -0400 Subject: [PATCH] TLS: pGLContext and gPipeInputs become constant-initialized pointer slots. --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 78 ++++----- MobileGL/MG_Backend/DirectGLES/Managers.cpp | 38 ++--- MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp | 6 +- MobileGL/MG_Backend/DirectGLES/Utils.cpp | 2 +- .../MG_Backend/DirectVulkan/DirectVulkan.cpp | 46 +++--- .../DirectVulkan/Renderer/UniformManager.cpp | 4 +- .../DirectVulkan/Renderer/VkClearManager.cpp | 2 +- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 108 ++++++------- .../DirectVulkan/Renderer/WireColorBlit.inc | 2 +- .../DirectVulkan/Renderer/WireDraw.inc | 22 +-- .../DirectVulkan/Renderer/WireFramebuffer.inc | 30 ++-- MobileGL/MG_Backend/MGPipe/PipeInputs.cpp | 8 +- MobileGL/MG_Backend/MGPipe/PipeInputs.h | 40 ++++- MobileGL/MG_Backend/Record/RecordVerbSink.cpp | 6 +- MobileGL/MG_Impl/Pipe/PipeFill.cpp | 6 +- .../Harness/DualBlockPeek.cpp | 6 +- .../Harness/DualBlockPeek.h | 2 +- MobileGL/MG_State/GLState/Core.cpp | 36 ++++- MobileGL/MG_State/GLState/Core.h | 50 +++++- .../Backend/DirectGLES/ContextEpochTest.cpp | 8 +- MobileGL/MG_Test/Buffer/SplitBufferTest.cpp | 2 +- MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp | 152 +++++++++--------- MobileGL/MG_Test/Pipe/FramebufferEmitTest.cpp | 2 +- MobileGL/MG_Test/Pipe/PipeInputsTest.cpp | 70 ++++---- MobileGL/MG_Test/Pipe/RecorderGoldenTest.cpp | 2 +- .../MG_Test/Pipe/RenderStateSpansTest.cpp | 90 +++++------ MobileGL/MG_Test/Pipe/ResourceEmitTest.cpp | 2 +- MobileGL/MG_Test/Pipe/TextureEmitTest.cpp | 2 +- MobileGL/MG_Test/Pipe/TrackerTest.cpp | 16 +- MobileGL/MG_Test/Pipe/VertexInputEmitTest.cpp | 2 +- MobileGL/MG_Test/SanityTest.cpp | 22 +-- .../State/ContextStateOwnershipTest.cpp | 4 +- MobileGL/MG_Test/Wire/PipeWireCodecTest.cpp | 16 +- MobileGL/MG_Test/Wire/ServerLoopTest.cpp | 24 +-- 34 files changed, 505 insertions(+), 401 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 38cab15b..65c4c457 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -115,7 +115,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // addresses again - the cached pointers cannot go stale. Invalidation is // exactly the pointer compare below. using FbBindingSlot = - std::remove_reference_t; + std::remove_reference_tGetFramebufferBindingSlot(FramebufferTarget::Draw))>; // P2 step e4. On the {slot, gen} arm this is an ORDINARY read of pushed state and the cache // above is not consulted, which closes the P1 accessor bypass: the cached raw pointer ran // the checked accessor once per context change and then handed out the pointee forever, so @@ -132,10 +132,10 @@ namespace MobileGL::MG_Backend::DirectGLES { // frontend getter still linear-scans, so the cache is exactly the code it was. static inline FbBindingSlot& GetFramebufferBindingSlotChecked(FramebufferTarget target) { if (EsprytSlotTablesEnabled()) { - return MG_Pipe::gPipeInputs.GetFramebufferBindingSlot(target); + return MG_Pipe::gPipeInputs->GetFramebufferBindingSlot(target); } // No legacy arm compiled: EsprytSlotTablesEnabled() is unconditionally true above. - return MG_Pipe::gPipeInputs.GetFramebufferBindingSlot(target); + return MG_Pipe::gPipeInputs->GetFramebufferBindingSlot(target); } // A4, TAKEN AT THE VERIFICATION ROUND, AND THE FOUR TEMPORARY LATCHES ARE GONE WITH IT. @@ -181,7 +181,7 @@ namespace MobileGL::MG_Backend::DirectGLES { [[noreturn]] static void RefuseFramebufferBindingSlotRead() { MG_Pipe::MGPipeInputPoisonFatalForVerb(MG_Pipe::MGPipeInputField::GetFramebufferBindingSlot, - MG_Pipe::gPipeInputs.CurrentVerb()); + MG_Pipe::gPipeInputs->CurrentVerb()); } static Bool IsDualSourceBlendFactor(BlendFactor v) { @@ -1146,7 +1146,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const SizeT packedStride = program->GetTransformFeedbackPackedStride(); const SizeT modelledVertices = - static_cast(MG_Pipe::gPipeInputs.GetTransformFeedbackCapturedVertices()); + static_cast(MG_Pipe::gPipeInputs->GetTransformFeedbackCapturedVertices()); const SizeT vertices = std::min(modelledVertices, xfb.scatterCapacityVertices); if (packedStride == 0 || vertices == 0) { // The scatter path redirected the DRIVER's capture into the scratch buffer, @@ -1669,7 +1669,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } auto* twin = ResolveVaoTwin(MG_Pipe::MGPipeApplier().BoundVertexElements); if (twin == nullptr) return; - const auto& currentVAO = MG_Pipe::gPipeInputs.GetBoundVertexArray(); + const auto& currentVAO = MG_Pipe::gPipeInputs->GetBoundVertexArray(); if (!currentVAO) return; twin->SyncClientSideAttributesForDrawArrays(currentVAO, first, count); return; @@ -1766,7 +1766,7 @@ namespace MobileGL::MG_Backend::DirectGLES { for (Uint32 remaining = memo.pendingMask; remaining != 0; remaining &= remaining - 1) { const Uint32 location = static_cast(std::countr_zero(remaining)); - const auto& currentValue = MG_Pipe::gPipeInputs.GetCurrentVertexAttribute(location); + const auto& currentValue = MG_Pipe::gPipeInputs->GetCurrentVertexAttribute(location); const auto typeInfo = MG_State::GLState::ClassifyVertexAttribType(program->GetAttribType(location)); switch (typeInfo.baseType) { case MG_State::GLState::VertexAttribBaseType::Float: @@ -1909,7 +1909,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // below rather than reading past the end. const GLenum attribType = location < link.attribTypes.size() ? link.attribTypes[location] : 0; - const auto& currentValue = MG_Pipe::gPipeInputs.GetCurrentVertexAttribute(location); + const auto& currentValue = MG_Pipe::gPipeInputs->GetCurrentVertexAttribute(location); const auto typeInfo = MG_State::GLState::ClassifyVertexAttribType(attribType); switch (typeInfo.baseType) { case MG_State::GLState::VertexAttribBaseType::Float: @@ -1986,7 +1986,7 @@ namespace MobileGL::MG_Backend::DirectGLES { static void CaptureUnitBindings(Int maxTouchedUnit, Vector& out) { out.resize(static_cast(maxTouchedUnit + 1)); for (Int unit = 0; unit <= maxTouchedUnit; ++unit) { - auto& textureUnit = MG_Pipe::gPipeInputs.GetTextureUnitObject(unit); + auto& textureUnit = MG_Pipe::gPipeInputs->GetTextureUnitObject(unit); auto& snapshot = out[static_cast(unit)]; const auto& slots = textureUnit.GetAllBindingSlots(); for (SizeT i = 0; i < slots.size(); ++i) { @@ -1999,7 +1999,7 @@ namespace MobileGL::MG_Backend::DirectGLES { static Bool UnitBindingsUnchanged(Int maxTouchedUnit, const Vector& snapshots) { if (snapshots.size() != static_cast(maxTouchedUnit + 1)) return false; for (Int unit = 0; unit <= maxTouchedUnit; ++unit) { - auto& textureUnit = MG_Pipe::gPipeInputs.GetTextureUnitObject(unit); + auto& textureUnit = MG_Pipe::gPipeInputs->GetTextureUnitObject(unit); const auto& snapshot = snapshots[static_cast(unit)]; const auto& slots = textureUnit.GetAllBindingSlots(); for (SizeT i = 0; i < slots.size(); ++i) { @@ -2146,8 +2146,8 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Util::PipeStats::CountGate(MG_Util::PipeStats::Gate::EsprytUnitBindingsEpoch, /*hit=*/false); } - const Uint64 contextId = MG_Pipe::gPipeInputs.GetTextureContextId(); - const Uint64 bindGeneration = MG_Pipe::gPipeInputs.GetTextureBindGeneration(); + const Uint64 contextId = MG_Pipe::gPipeInputs->GetTextureContextId(); + const Uint64 bindGeneration = MG_Pipe::gPipeInputs->GetTextureBindGeneration(); if (MG_Util::PipeStats::Enabled()) { // Two accessor calls whichever way the shutter goes; only the unit WALK is // gated, and that walk reads no GLContext accessor of its own. @@ -2366,7 +2366,7 @@ namespace MobileGL::MG_Backend::DirectGLES { DrawTextureSyncKeys CaptureDrawTextureSyncKeys() { DrawTextureSyncKeys keys; - keys.contextId = MG_Pipe::gPipeInputs.GetTextureContextId(); + keys.contextId = MG_Pipe::gPipeInputs->GetTextureContextId(); // Units past the frontend's high-water mark have provably-empty slots. // // P4a e2 DELIBERATELY DOES NOT take this off the sampler-view window's Count, and @@ -2379,8 +2379,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // CLIENT as the count argument and says nothing about re-deriving it server-side. // It is one accessor read per draw; the integrator can move it in one line once a // tree exists where the two can be compared. - keys.maxTouchedUnit = MG_Pipe::gPipeInputs.GetMaxTouchedTextureUnit(); - keys.samplingGeneration = MG_Pipe::gPipeInputs.GetSamplingResolutionGeneration(); + keys.maxTouchedUnit = MG_Pipe::gPipeInputs->GetMaxTouchedTextureUnit(); + keys.samplingGeneration = MG_Pipe::gPipeInputs->GetSamplingResolutionGeneration(); keys.unitBindingsEpoch = CurrentUnitBindingsEpoch(keys.maxTouchedUnit); if (MG_Util::PipeStats::Enabled()) { // The three reads above; CurrentUnitBindingsEpoch counts its own two when it @@ -3455,7 +3455,7 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif - Uint16 currentRenderStateVersion = MG_Pipe::gPipeInputs.GetRenderStateParametersVersion(); + Uint16 currentRenderStateVersion = MG_Pipe::gPipeInputs->GetRenderStateParametersVersion(); const Bool forceFullPush = g_forceFullRenderStateResync; g_forceFullRenderStateResync = false; // The alpha discipline for widened colour attachments (see the header comment on @@ -3483,7 +3483,7 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Util::PipeStats::AddCalls(MG_Util::PipeStats::CallClass::AccessorCalls, 3); } - const auto& parameters = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const auto& parameters = MG_Pipe::gPipeInputs->GetRenderStateParameters(); // The frontend has ONE version for the whole parameter block, so a per-draw blend // toggle used to re-diff all ~40 pieces of state field by field on every draw @@ -3512,7 +3512,7 @@ namespace MobileGL::MG_Backend::DirectGLES { !g_hasSyncedRenderState || std::memcmp(currentBytes + kBlendSpanEnd, syncedBytes + kBlendSpanEnd, sizeof(RenderStateParameters) - kBlendSpanEnd) != 0; - IntVec4 backendViewport = MG_Pipe::gPipeInputs.GetViewport(); + IntVec4 backendViewport = MG_Pipe::gPipeInputs->GetViewport(); if (backendViewport.z() <= 0 || backendViewport.w() <= 0) { Int surfaceWidth = 0; Int surfaceHeight = 0; @@ -3595,7 +3595,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // never turns it on, so the driver has to be told to write raw. Without this a render // into an sRGB colour buffer comes back encoded once too often (the shader's own // decode on the next fetch then leaves the value one conversion short). - const Bool srgbWrites = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); + const Bool srgbWrites = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); if (g_GLESCapabilities.SupportsSrgbWriteControl && (forceFullPush || srgbWrites != g_syncedSrgbFramebufferWrites)) { srgbWrites ? g_GLESFuncs.glEnable(GL_FRAMEBUFFER_SRGB) @@ -4505,11 +4505,11 @@ namespace MobileGL::MG_Backend::DirectGLES { !twin->ImageUnitFormatsStillMatch() || (twin->GetPassthroughTessControlPatchVertices() >= 0 && (twin->GetPassthroughTessControlPatchVertices() != - static_cast(MG_Pipe::gPipeInputs.GetPatchVertices()) || + static_cast(MG_Pipe::gPipeInputs->GetPatchVertices()) || !BitwiseEqual(twin->GetPassthroughTessControlOuterLevel(), - MG_Pipe::gPipeInputs.GetPatchDefaultOuterLevel()) || + MG_Pipe::gPipeInputs->GetPatchDefaultOuterLevel()) || !BitwiseEqual(twin->GetPassthroughTessControlInnerLevel(), - MG_Pipe::gPipeInputs.GetPatchDefaultInnerLevel())))) { + MG_Pipe::gPipeInputs->GetPatchDefaultInnerLevel())))) { twin->SyncToBackendByHandle(cso); } g_currentDrawProgramHandle = cso; @@ -5846,12 +5846,12 @@ namespace MobileGL::MG_Backend::DirectGLES { // times; rasterizer discard means there are no fragments to gate at all, so replaying // would be pure cost with nothing to show for it. Both fall back to a single pass with an // open gate, i.e. to the pre-emulation behaviour, rather than to wrong data. - if (MG_Pipe::gPipeInputs.IsTransformFeedbackActive() || - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) { + if (MG_Pipe::gPipeInputs->IsTransformFeedbackActive() || + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) { return 1; } - const auto& parameters = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const auto& parameters = MG_Pipe::gPipeInputs->GetRenderStateParameters(); Int surfaceWidth = 0; Int surfaceHeight = 0; if (!QueryCurrentSurfaceSize(surfaceWidth, surfaceHeight)) { @@ -6228,7 +6228,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // color must go through glClearBufferfv, which GLES does not clamp. GLbitfield remainingMask = mask; if ((mask & GL_COLOR_BUFFER_BIT) != 0) { - const FloatVec4& cc = MG_Pipe::gPipeInputs.GetRenderStateParameters().ClearColor; + const FloatVec4& cc = MG_Pipe::gPipeInputs->GetRenderStateParameters().ClearColor; const Bool outOfRange = cc.x() < 0.f || cc.x() > 1.f || cc.y() < 0.f || cc.y() > 1.f || cc.z() < 0.f || cc.z() > 1.f || cc.w() < 0.f || cc.w() > 1.f; // A widened attachment's stored alpha has to end up 1.0, and glClear applies ONE @@ -6456,13 +6456,13 @@ namespace MobileGL::MG_Backend::DirectGLES { } // namespace RestartSubstitutionKind ResolveRestartSubstitution(GLenum indexType) { - if (!MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) || - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex)) { + if (!MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) || + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex)) { return RestartSubstitutionKind::None; } const Uint32 fixedMax = MG_Util::FixedRestartIndexForGLType(indexType); if (fixedMax == 0) return RestartSubstitutionKind::None; - const Uint32 restartIndex = MG_Pipe::gPipeInputs.GetPrimitiveRestartIndex(); + const Uint32 restartIndex = MG_Pipe::gPipeInputs->GetPrimitiveRestartIndex(); if (restartIndex == fixedMax) return RestartSubstitutionKind::None; // Strictly greater, never truncated. GL 4.6 core 10.3.6 compares the fetched index // zero-extended against the full 32-bit state, so an index this type cannot hold matches @@ -6502,7 +6502,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } const SizeT sourceIndexSize = MG_Util::GetGLTypeSize(indexType); const Uint32 fixedMax = MG_Util::FixedRestartIndexForGLType(indexType); - const Uint32 applicationRestartIndex = MG_Pipe::gPipeInputs.GetPrimitiveRestartIndex(); + const Uint32 applicationRestartIndex = MG_Pipe::gPipeInputs->GetPrimitiveRestartIndex(); const Uint8* source = nullptr; SizeT indexCount = 0; @@ -7395,8 +7395,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // restore. Drop the flag so it is not misattributed to the emulation's own work. DrainBlitErrors(); - if (MG_Pipe::gPipeInputs.IsTransformFeedbackActive() && - !MG_Pipe::gPipeInputs.IsTransformFeedbackPaused() && g_GLESFuncs.glPauseTransformFeedback) { + if (MG_Pipe::gPipeInputs->IsTransformFeedbackActive() && + !MG_Pipe::gPipeInputs->IsTransformFeedbackPaused() && g_GLESFuncs.glPauseTransformFeedback) { g_GLESFuncs.glPauseTransformFeedback(); m_pausedTransformFeedback = true; DrainBlitErrors(); @@ -8618,7 +8618,7 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND); #endif - auto unit = MG_Pipe::gPipeInputs.GetActiveTextureUnit(); + auto unit = MG_Pipe::gPipeInputs->GetActiveTextureUnit(); auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); if (!TextureImpl::IsSupportedTextureTarget(textureTarget)) { @@ -8695,7 +8695,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // The frontend's current PACK parameters, for readbacks the ES driver serves // directly with the client's layout. static PixelStoreImpl::PackState PackStateFromContext() { - const auto packParams = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false); + const auto packParams = MG_Pipe::gPipeInputs->GetPixelStoreParameters(false); return {static_cast(packParams.Alignment), static_cast(packParams.RowLength), static_cast(packParams.SkipRows), static_cast(packParams.SkipPixels)}; } @@ -8891,7 +8891,7 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(target).c_str(), MG_Util::ConvertTextureInternalFormatToString(format).c_str()); - MG_Pipe::gPipeInputs.RecordError( + MG_Pipe::gPipeInputs->RecordError( ConvertGLESErrorToErrorCode(err), MakeUnique("DirectGLES", operation, MG_Util::ConvertGLEnumToString(err))); @@ -9407,7 +9407,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // Bind necessary FBO and texture BindCurrentFBO(FramebufferTarget::Read); - Uint activeTextureUnit = MG_Pipe::gPipeInputs.GetActiveTextureUnit(); + Uint activeTextureUnit = MG_Pipe::gPipeInputs->GetActiveTextureUnit(); TextureImpl::BackendTextureObject* dstBackendTexture = nullptr; TextureInternalFormat mgInternalFormat{}; // P5c (hd, CONTRACT-P5C §3.4): with an active transport the destination resolves from @@ -9516,7 +9516,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // Bind necessary FBO and texture BindCurrentFBO(FramebufferTarget::Read); - auto activeTextureUnit = MG_Pipe::gPipeInputs.GetActiveTextureUnit(); + auto activeTextureUnit = MG_Pipe::gPipeInputs->GetActiveTextureUnit(); TextureImpl::BackendTextureObject* dstBackendTexture = nullptr; // P5c (hd, CONTRACT-P5C §3.4): see CopyTexImage2D - the record's Dst handle, never the // client's unit binding slot or the client allocator (T2/T4). @@ -10347,7 +10347,7 @@ namespace MobileGL::MG_Backend::DirectGLES { template static Bool StoreReadbackRowsToClient(GLsizei width, GLsizei height, SizeT dstPixelBytes, void* pixels, const char* what, FillRow&& fillRow) { - const auto packParams = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false); + const auto packParams = MG_Pipe::gPipeInputs->GetPixelStoreParameters(false); const SizeT rowPixels = static_cast(packParams.RowLength > 0 ? packParams.RowLength : width); const SizeT dstRowStride = AlignPixelRow(rowPixels * dstPixelBytes, packParams.Alignment); const SizeT dstOffset = static_cast(std::max(packParams.SkipRows, 0)) * dstRowStride + @@ -11811,7 +11811,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // and legacy GL_RED reads) goes through the wide-format conversion, which picks a wide type // the driver accepts for the current attachment. GL_PACK_SWAP_BYTES has no ES equivalent, so // it always takes the conversion path (which swaps on the CPU). - const Bool packSwapBytes = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false).SwapBytes; + const Bool packSwapBytes = MG_Pipe::gPipeInputs->GetPixelStoreParameters(false).SwapBytes; // The read buffer is what glReadPixels reads, so the frontend's READ binding is exactly // the right thing to ask here. const Bool forceOpaqueAlpha = FramebufferImpl::IsAlphaWidenedFallbackReadAttachment(); diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 7309308d..6c878dfd 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -7198,9 +7198,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // that needs no work costs the same nothing per draw that any other synced texture does. void BackendTextureObject::StampViewSyncKeys( const SharedPtr& stateTextureObject) { - if (MG_Pipe::gPipeInputs.IsLive()) { - m_syncedShapeContextId = MG_Pipe::gPipeInputs.GetTextureContextId(); - m_syncedShapeGeneration = MG_Pipe::gPipeInputs.GetSamplingResolutionGeneration(); + if (MG_Pipe::gPipeInputs->IsLive()) { + m_syncedShapeContextId = MG_Pipe::gPipeInputs->GetTextureContextId(); + m_syncedShapeGeneration = MG_Pipe::gPipeInputs->GetSamplingResolutionGeneration(); m_syncedShapeParamsVersion = stateTextureObject->GetTextureParamsVersion(); } m_syncedContentVersion = stateTextureObject->GetContentVersion(); @@ -7349,9 +7349,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // LEGACY ARM ONLY from P4a on: the memos it reads are the pre-handle ones and the // record above answers the same question in one compare. if (pushedStorage == nullptr) - if (m_isInitialized && m_syncedShapeContextId != 0 && MG_Pipe::gPipeInputs.IsLive() && - m_syncedShapeContextId == MG_Pipe::gPipeInputs.GetTextureContextId() && - m_syncedShapeGeneration == MG_Pipe::gPipeInputs.GetSamplingResolutionGeneration() && + if (m_isInitialized && m_syncedShapeContextId != 0 && MG_Pipe::gPipeInputs->IsLive() && + m_syncedShapeContextId == MG_Pipe::gPipeInputs->GetTextureContextId() && + m_syncedShapeGeneration == MG_Pipe::gPipeInputs->GetSamplingResolutionGeneration() && m_syncedContentVersion == stateTextureObject->GetContentVersion() && m_syncedShapeParamsVersion == stateTextureObject->GetTextureParamsVersion() && stateTextureObject->GetStorageType() == TextureStorageType::Mipmap) { @@ -7467,9 +7467,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // The probe just proved "fully synced" from the real state, so the cheap // gate may be (re)stamped here: the coarse generation only ever goes stale // from OTHER textures' churn, and this draw re-validated this one. - if (MG_Pipe::gPipeInputs.IsLive()) { - m_syncedShapeContextId = MG_Pipe::gPipeInputs.GetTextureContextId(); - m_syncedShapeGeneration = MG_Pipe::gPipeInputs.GetSamplingResolutionGeneration(); + if (MG_Pipe::gPipeInputs->IsLive()) { + m_syncedShapeContextId = MG_Pipe::gPipeInputs->GetTextureContextId(); + m_syncedShapeGeneration = MG_Pipe::gPipeInputs->GetSamplingResolutionGeneration(); m_syncedShapeParamsVersion = stateTextureObject->GetTextureParamsVersion(); } return; @@ -8764,9 +8764,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // Same instant, so the cheap gate's keys describe exactly this synced state. // Only Mipmap storage may arm it - the gate refuses other storage types anyway, // but a stale trio must not linger on an object that later switches type. - if (MG_Pipe::gPipeInputs.IsLive() && stateTextureObject->GetStorageType() == TextureStorageType::Mipmap) { - m_syncedShapeContextId = MG_Pipe::gPipeInputs.GetTextureContextId(); - m_syncedShapeGeneration = MG_Pipe::gPipeInputs.GetSamplingResolutionGeneration(); + if (MG_Pipe::gPipeInputs->IsLive() && stateTextureObject->GetStorageType() == TextureStorageType::Mipmap) { + m_syncedShapeContextId = MG_Pipe::gPipeInputs->GetTextureContextId(); + m_syncedShapeGeneration = MG_Pipe::gPipeInputs->GetSamplingResolutionGeneration(); m_syncedShapeParamsVersion = stateTextureObject->GetTextureParamsVersion(); } else { m_syncedShapeContextId = 0; @@ -9905,7 +9905,7 @@ namespace MobileGL::MG_Backend::DirectGLES { return record && record->ReadSurface.Kind != MG_Pipe::kMGPipeSurfaceKindNone && IsSnormFormat(static_cast(record->ReadSurface.InternalFormat)); const auto& readFBO = - MG_Pipe::gPipeInputs.GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); + MG_Pipe::gPipeInputs->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); if (!readFBO) { return false; } @@ -11980,19 +11980,19 @@ namespace MobileGL::MG_Backend::DirectGLES { // patch size - so a program built for one value is stale for another. Recorded here // and compared on the draw path (SyncCurrentProgram), the same shape as the // storage-block and image-format signatures next to it. - const Uint patchVertices = MG_Pipe::gPipeInputs.IsLive() - ? MG_Pipe::gPipeInputs.GetPatchVertices() + const Uint patchVertices = MG_Pipe::gPipeInputs->IsLive() + ? MG_Pipe::gPipeInputs->GetPatchVertices() : 3u; m_passthroughTessControlPatchVertices = static_cast(patchVertices); // PATCH_DEFAULT_{OUTER,INNER}_LEVEL are the same kind of dynamic state and are baked // into the same stage (ES has no such state and no entry point to forward them to), so // they are recorded and compared alongside the patch size - the two move together, as // BuildPassthroughTessControlEssl's contract says. - m_passthroughTessControlOuterLevel = MG_Pipe::gPipeInputs.IsLive() - ? MG_Pipe::gPipeInputs.GetPatchDefaultOuterLevel() + m_passthroughTessControlOuterLevel = MG_Pipe::gPipeInputs->IsLive() + ? MG_Pipe::gPipeInputs->GetPatchDefaultOuterLevel() : FloatVec4(1.0f, 1.0f, 1.0f, 1.0f); - m_passthroughTessControlInnerLevel = MG_Pipe::gPipeInputs.IsLive() - ? MG_Pipe::gPipeInputs.GetPatchDefaultInnerLevel() + m_passthroughTessControlInnerLevel = MG_Pipe::gPipeInputs->IsLive() + ? MG_Pipe::gPipeInputs->GetPatchDefaultInnerLevel() : FloatVec2(1.0f, 1.0f); if (tessEvalShaderIndex < 0 || diff --git a/MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp b/MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp index f92fb392..8ba46961 100644 --- a/MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp +++ b/MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp @@ -44,14 +44,14 @@ namespace MobileGL::MG_Backend::DirectGLES::MultiDrawImpl { // verbatim is already "this batch restarts nowhere". Uint32 RestartSentinelFor(GLenum type) { if (ResolveRestartSubstitution(type) != RestartSubstitutionKind::None) { - return MG_Pipe::gPipeInputs.GetPrimitiveRestartIndex(); + return MG_Pipe::gPipeInputs->GetPrimitiveRestartIndex(); } return MG_Util::FixedRestartIndexForGLType(type); } Bool RestartActive() { - return MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) || - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex); + return MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) || + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex); } // Vertices per primitive for the modes whose sub-draws may be concatenated into a diff --git a/MobileGL/MG_Backend/DirectGLES/Utils.cpp b/MobileGL/MG_Backend/DirectGLES/Utils.cpp index 4dcba653..94eeb4ed 100644 --- a/MobileGL/MG_Backend/DirectGLES/Utils.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Utils.cpp @@ -2338,7 +2338,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // Destination layout is computed from the client-side PACK parameters; only the actual pixel // rows are written so skip regions of the destination stay untouched. - const auto packParams = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false); + const auto packParams = MG_Pipe::gPipeInputs->GetPixelStoreParameters(false); const SizeT rowPixels = static_cast(packParams.RowLength > 0 ? packParams.RowLength : width); const SizeT dstRowStride = AlignReadbackRow(rowPixels * dstPixelBytes, packParams.Alignment); const SizeT imageRows = diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp index 3f84835e..3f1a0e6a 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp @@ -291,25 +291,25 @@ namespace MobileGL::MG_Backend::DirectVulkan { void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::ClearBufferfi called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::ClearBufferfi called with null GL context"); pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil); } void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::ClearBufferfv called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::ClearBufferfv called with null GL context"); pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value); } void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::ClearBufferuiv called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::ClearBufferuiv called with null GL context"); pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value); } void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::ClearBufferiv called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::ClearBufferiv called with null GL context"); pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value); } @@ -345,7 +345,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null GL context"); DrawIndexedCmd payload{}; payload.mode = mode; @@ -377,7 +377,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysInstancedBaseInstance called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DrawArraysInstancedBaseInstance called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DrawArraysInstancedBaseInstance called with null GL context"); DrawCmd payload{}; payload.mode = mode; @@ -397,13 +397,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::CopyTexImage2D called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::CopyTexImage2D called with null GL context"); pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height); } void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::CopyTexSubImage2D called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::CopyTexSubImage2D called with null GL context"); pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); } void CopyImageSubData(const CopyImageEndpoint& src, @@ -412,20 +412,20 @@ namespace MobileGL::MG_Backend::DirectVulkan { GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyImageSubData called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::CopyImageSubData called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::CopyImageSubData called with null GL context"); pVulkanRenderer->CopyImageSubData(src, srcTarget, srcLevel, srcX, srcY, srcZ, dst, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); } void GenerateMipmap(GLenum target) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GenerateMipmap called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::GenerateMipmap called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::GenerateMipmap called with null GL context"); pVulkanRenderer->GenerateMipmap(target); } void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchCompute called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DispatchCompute called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DispatchCompute called with null GL context"); pVulkanRenderer->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ); } @@ -440,7 +440,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void MemoryBarrier(GLbitfield barriers) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MemoryBarrier called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::MemoryBarrier called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::MemoryBarrier called with null GL context"); pVulkanRenderer->MemoryBarrier(barriers); } @@ -530,12 +530,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { } void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::ReadPixels called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::ReadPixels called with null GL context"); pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels); } void Clear(GLbitfield mask) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::Clear called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::Clear called with null GL context"); pVulkanRenderer->Clear(mask); } @@ -582,7 +582,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DrawArrays(GLenum mode, GLint first, GLsizei count) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DrawArrays called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DrawArrays called with null GL context"); if (mode == GL_LINE_LOOP) { if (count < 2) { @@ -607,7 +607,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DrawElements called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DrawElements called with null GL context"); if (mode == GL_LINE_LOOP) { Vector closedIndices; @@ -637,7 +637,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArrays called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::MultiDrawArrays called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::MultiDrawArrays called with null GL context"); if (drawcount <= 0) { return; } @@ -743,7 +743,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::DrawElementsBaseVertex called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::DrawElementsBaseVertex called with null GL context"); if (mode == GL_LINE_LOOP) { Vector closedIndices; if (BuildClosedLineLoopIndices(count, type, indices, closedIndices)) { @@ -767,14 +767,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, GLsizei drawcount, const GLint* basevertex) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context"); MultiDrawElementsImpl(mode, count, type, indices, drawcount, basevertex); } void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "DirectVulkan::BlitFramebuffer called with null GL context"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "DirectVulkan::BlitFramebuffer called with null GL context"); pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } @@ -1018,8 +1018,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { #if MOBILEGL_BUILD_DISAGGREGATED MG_Config::Transport == MG_Config::TransportMode::Monolith && #endif - MG_Pipe::gPipeInputs.IsLive()) { - primitives += MG_Pipe::gPipeInputs.GetTransformFeedbackPausedPrimitiveCounter() - + MG_Pipe::gPipeInputs->IsLive()) { + primitives += MG_Pipe::gPipeInputs->GetTransformFeedbackPausedPrimitiveCounter() - query->pausedPrimitiveSnapshot; } *outNanoseconds = primitives; @@ -1069,7 +1069,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { #if MOBILEGL_BUILD_DISAGGREGATED MG_Config::Transport == MG_Config::TransportMode::Monolith && #endif - MG_Pipe::gPipeInputs.IsLive() ? MG_Pipe::gPipeInputs.GetTransformFeedbackPausedPrimitiveCounter() : 0; + MG_Pipe::gPipeInputs->IsLive() ? MG_Pipe::gPipeInputs->GetTransformFeedbackPausedPrimitiveCounter() : 0; // Read AFTER StartXfbQueryCapture, which is where a failed reroute-pool creation // disarms: the answer is then what this span will actually do for every draw. query->pausedPrimitivesCountedByGpu = generated && pVulkanRenderer->ArePausedDrawsGpuCounted(); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index c306ef75..3cfef5fc 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -858,7 +858,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkDescriptorBufferInfo& outBufferInfo) const { outBufferInfo = {}; MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null"); - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "ResolveStorageBufferDescriptor: GL context is null"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "ResolveStorageBufferDescriptor: GL context is null"); MOBILEGL_ASSERT(binding < programObj.storageBlockIndexByBinding.size(), "ResolveStorageBufferDescriptor: binding %u out of range", binding); if ((binding >= programObj.storageBlockIndexByBinding.size() || @@ -1155,7 +1155,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const void* outData = nullptr; VkDeviceSize outSize = 0; - MOBILEGL_ASSERT(MG_Pipe::gPipeInputs.IsLive(), "ResolveUniformBufferPayload: GL context is null"); + MOBILEGL_ASSERT(MG_Pipe::gPipeInputs->IsLive(), "ResolveUniformBufferPayload: GL context is null"); MOBILEGL_ASSERT(binding < programObj.bindingKinds.size(), "ResolveUniformBufferPayload: binding %u out of range", binding); MOBILEGL_ASSERT(programObj.bindingKinds[binding] == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp index ca7d1126..1f510fd2 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp @@ -55,7 +55,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (payload.colorEncoding != ClearColorEncoding::Float) return; // With GL_FRAMEBUFFER_SRGB enabled GL performs the encoding itself, so the driver doing it // is exactly right and there is nothing to undo. - if (MG_Pipe::gPipeInputs.IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)) return; + if (MG_Pipe::gPipeInputs->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)) return; if (ResolveSrgbAttachmentWriteFormat(destinationFormat, false) == destinationFormat) return; // sRGB -> linear (GL 4.6 core 8.24), applied to the colour channels only: alpha is stored diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 441f4562..297d88c5 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -526,12 +526,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { // round trip), which is why the honest-but-lossy path was kept over widening every // default-framebuffer Y-flip/pre-transform helper to floats. See the KNOWN INFIDELITY // note in MG_IntegrationTest/Scenarios/AdvertisedLimitsScenario.cpp. - const FloatVec4& stored = MG_Pipe::gPipeInputs.GetViewportIndexed(index); + const FloatVec4& stored = MG_Pipe::gPipeInputs->GetViewportIndexed(index); const IntVec4 viewportState(static_cast(std::lround(stored.x())), static_cast(std::lround(stored.y())), static_cast(std::lround(stored.z())), static_cast(std::lround(stored.w()))); - const FloatVec2& depthRange = MG_Pipe::gPipeInputs.GetDepthRangeIndexed(index); + const FloatVec2& depthRange = MG_Pipe::gPipeInputs->GetDepthRangeIndexed(index); const IntVec2 logicalExtent = isDefaultFramebuffer ? ResolveDefaultFramebufferLogicalExtent(preTransform, framebufferExtent) : framebufferExtent; @@ -586,7 +586,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } static void ApplyBlendConstants(VkCommandBuffer commandBuffer) { - const FloatVec4& blendColor = MG_Pipe::gPipeInputs.GetBlendColor(); + const FloatVec4& blendColor = MG_Pipe::gPipeInputs->GetBlendColor(); const float blendConstants[4] = { blendColor.x(), blendColor.y(), @@ -619,8 +619,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { } static void ApplyPolygonOffsetState(VkCommandBuffer commandBuffer) { - const Float constantFactor = MG_Pipe::gPipeInputs.GetPolygonOffsetUnits(); - const Float slopeFactor = MG_Pipe::gPipeInputs.GetPolygonOffsetFactor(); + const Float constantFactor = MG_Pipe::gPipeInputs->GetPolygonOffsetUnits(); + const Float slopeFactor = MG_Pipe::gPipeInputs->GetPolygonOffsetFactor(); auto& shadow = *g_dynamicStateShadow; if (shadow.depthBiasValid && shadow.depthBiasConstantFactor == constantFactor && shadow.depthBiasSlopeFactor == slopeFactor) { @@ -633,7 +633,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } static void ApplyLineWidthState(VkCommandBuffer commandBuffer) { - Float lineWidth = MG_Pipe::gPipeInputs.GetLineWidth(); + Float lineWidth = MG_Pipe::gPipeInputs->GetLineWidth(); #if MOBILEGL_BUILD_DISAGGREGATED // P5c (hd, CONTRACT-P5C §3.7): with an active transport the dynamic parameters are the // SERVER's own backend's - the client caps mirror is client memory (rule E). Monolith @@ -677,7 +677,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // reader of the box asks this first. The resolution matches the viewport's (ComputeGLViewport // resolves a never-written viewport to the current framebuffer's extent). static Bool GLScissorTestClips(Uint32 index = 0) { - const RenderStateParameters& parameters = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const RenderStateParameters& parameters = MG_Pipe::gPipeInputs->GetRenderStateParameters(); const Uint32 bit = 1u << index; return (parameters.ScissorTestEnabledMask & bit) != 0 && (parameters.ScissorBoxWrittenMask & bit) != 0; } @@ -748,8 +748,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { } static void ApplyStencilState(VkCommandBuffer commandBuffer) { - const StencilFaceState& frontStencil = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front); - const StencilFaceState& backStencil = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Back); + const StencilFaceState& frontStencil = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front); + const StencilFaceState& backStencil = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Back); const Uint32 frontReference = static_cast(std::max(frontStencil.Ref, 0)); const Uint32 backReference = static_cast(std::max(backStencil.Ref, 0)); @@ -1116,7 +1116,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } static void RecordTextureCopyError(const char* func, ErrorCode code, const char* message) { - MG_Pipe::gPipeInputs.RecordError(code, MakeUnique("DirectVulkan", func, message)); + MG_Pipe::gPipeInputs->RecordError(code, MakeUnique("DirectVulkan", func, message)); } namespace { @@ -1894,7 +1894,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // glReadPixels final conversion: GL_CLAMP_READ_COLOR defaults to GL_FIXED_ONLY, // clamping fixed-point (normalized) buffers to [0,1] - visible for SNORM reads. if (applyReadColorClamp && wideType == GL_FLOAT) { - const GLenum clampMode = MG_Pipe::gPipeInputs.GetClampReadColor(); + const GLenum clampMode = MG_Pipe::gPipeInputs->GetClampReadColor(); const Bool clamp = clampMode == GL_TRUE || (clampMode == GL_FIXED_ONLY && !IsFloatingPointReadbackFormat(srcFormat)); if (clamp) { @@ -2699,9 +2699,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { Uint32 VulkanRenderer::ResolveEffectiveSampleMask(VkSampleCountFlagBits rasterizationSamples) const { constexpr Uint32 kFullCoverage = 0xffffffffu; if (rasterizationSamples == VK_SAMPLE_COUNT_1_BIT) return kFullCoverage; - if (!MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::Multisample)) return kFullCoverage; - if (!MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::SampleMask)) return kFullCoverage; - return MG_Pipe::gPipeInputs.GetRenderStateParameters().SampleMaskValue; + if (!MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::Multisample)) return kFullCoverage; + if (!MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::SampleMask)) return kFullCoverage; + return MG_Pipe::gPipeInputs->GetRenderStateParameters().SampleMaskValue; } @@ -2716,7 +2716,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // // Only reached with no render-state CSO bound, and only in a build with no pre-handle // arm to fall back to instead. - return MG_Pipe::MGPipeComputePipelineSubsetHash(MG_Pipe::gPipeInputs.GetRenderStateParameters()); + return MG_Pipe::MGPipeComputePipelineSubsetHash(MG_Pipe::gPipeInputs->GetRenderStateParameters()); } // A program that runs a geometry shader AND captures transform feedback. Both halves are @@ -2748,7 +2748,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!(aspects & DrawSetupAspect::IndexBuffer) || pIndexBufferView == nullptr) { return false; } - const RenderStateParameters& rsp = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const RenderStateParameters& rsp = MG_Pipe::gPipeInputs->GetRenderStateParameters(); if (rsp.PrimitiveRestartFixedIndexEnabled) { return true; } @@ -2803,7 +2803,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // the VALUE hash of that subset, never the version itself: the version is monotonic, so // per-draw state flips (GL_BLEND toggles) would otherwise miss entries the memo holds. // The version only guards recomputing the hash - unchanged version, unchanged bytes. - const Uint renderStateVersion = MG_Pipe::gPipeInputs.GetPipelineStateVersion(); + const Uint renderStateVersion = MG_Pipe::gPipeInputs->GetPipelineStateVersion(); // P2 D12.1. Non-null means the client's render-state CSO handle is this draw's state // key and the hash below is not computed at all; null means the pre-handle arm. The // two arms' entries can never match each other: the handle arm stores hash 0 and a @@ -2996,16 +2996,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { syntheticVertexInputState.pNext = vis.state.pNext; pipelineVertexInputState = &syntheticVertexInputState; } - auto cullFaceEnabled = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::CullFace); - auto depthTestEnabled = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::DepthTest); + auto cullFaceEnabled = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::CullFace); + auto depthTestEnabled = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::DepthTest); auto polygonOffsetFillEnabled = - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) && + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) && DrawModeUsesPolygonFill(mode); auto rasterizerDiscardEnabled = - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::RasterizerDiscard); + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard); auto colorLogicOpEnabled = - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled; - auto stencilTestEnabled = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::StencilTest); + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled; + auto stencilTestEnabled = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::StencilTest); // A framebuffer without a depth (stencil) attachment behaves as if the depth // (stencil) test always passes and nothing is written - even when the bound // image is a packed depth-stencil texture attached through only one half. @@ -3016,10 +3016,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (fbo->Stencil.Kind == MG_Pipe::kMGPipeSurfaceKindNone) stencilTestEnabled = false; } } - const StencilFaceState& frontStencil = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front); - const StencilFaceState& backStencil = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Back); + const StencilFaceState& frontStencil = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front); + const StencilFaceState& backStencil = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Back); const VkPolygonMode requestedPolygonMode = - MG_Util::ConvertPolygonModeToVkEnum(MG_Pipe::gPipeInputs.GetPolygonModeFront()); + MG_Util::ConvertPolygonModeToVkEnum(MG_Pipe::gPipeInputs->GetPolygonModeFront()); // VK_POLYGON_MODE_LINE/_POINT require the fillModeNonSolid device feature; fall back to // VK_POLYGON_MODE_FILL when the device lacks it. const VkPolygonMode effectivePolygonMode = @@ -3105,18 +3105,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { // driver's own rate. Both halves move the render state's PIPELINE version, so a cached // pipeline built at the old rate cannot be handed back for the new one. .sampleShadingEnable = m_sampleRateShadingFeatureEnabled && - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::SampleShading), - .minSampleShading = MG_Pipe::gPipeInputs.GetMinSampleShadingValue(), + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::SampleShading), + .minSampleShading = MG_Pipe::gPipeInputs->GetMinSampleShadingValue(), // Word 1 keeps its all-ones initialiser: GL has no state for samples 32..63. .sampleMask = {ResolveEffectiveSampleMask(renderPassEntry.sampleCount), 0xffffffffu}, .subpass = 0, .topology = vkTopology, .primitiveRestartEnable = primitiveRestartEnabled, - .patchControlPoints = static_cast(MG_Pipe::gPipeInputs.GetPatchVertices()), + .patchControlPoints = static_cast(MG_Pipe::gPipeInputs->GetPatchVertices()), .viewportCount = ResolveDrawViewportCount(programObj.writesViewportIndexBuiltin), .polygonMode = effectivePolygonMode, .cullMode = cullFaceEnabled - ? MG_Util::ConvertCullFaceModeToVkEnum(MG_Pipe::gPipeInputs.GetCullFaceMode(), invertClockwise) + ? MG_Util::ConvertCullFaceModeToVkEnum(MG_Pipe::gPipeInputs->GetCullFaceMode(), invertClockwise) : VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_CLOCKWISE, // Read the geometry stage off the program's own shader list rather than @@ -3130,13 +3130,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { .provokingVertexMode = SelectProvokingVertexMode( vkTopology, ProgramCapturesXfbFromGeometryStage(program)), .depthTestEnable = depthTestEnabled, - .depthWriteEnable = depthTestEnabled && MG_Pipe::gPipeInputs.GetDepthMask(), + .depthWriteEnable = depthTestEnabled && MG_Pipe::gPipeInputs->GetDepthMask(), .depthBiasEnable = polygonOffsetFillEnabled, .rasterizerDiscardEnable = rasterizerDiscardEnabled, .logicOpEnable = colorLogicOpEnabled, .stencilTestEnable = stencilTestEnabled, - .depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_Pipe::gPipeInputs.GetDepthFunc()), - .logicOp = MG_Util::ConvertLogicOperationToVkEnum(MG_Pipe::gPipeInputs.GetLogicOp()), + .depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_Pipe::gPipeInputs->GetDepthFunc()), + .logicOp = MG_Util::ConvertLogicOperationToVkEnum(MG_Pipe::gPipeInputs->GetLogicOp()), .frontStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.FailOp), .frontStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthPassOp), .frontStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthFailOp), @@ -3172,8 +3172,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { // handed back after the application changed them. if (programObj.needsPassthroughTessControl && programObj.passthroughTessControlEmulatable && vkTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { - const FloatVec4& defaultOuterLevel = MG_Pipe::gPipeInputs.GetPatchDefaultOuterLevel(); - const FloatVec2& defaultInnerLevel = MG_Pipe::gPipeInputs.GetPatchDefaultInnerLevel(); + const FloatVec4& defaultOuterLevel = MG_Pipe::gPipeInputs->GetPatchDefaultOuterLevel(); + const FloatVec2& defaultInnerLevel = MG_Pipe::gPipeInputs->GetPatchDefaultInnerLevel(); payload.passthroughTessControlKey = ProgramFactory::ComputePassthroughTessControlKey( payload.patchControlPoints, defaultOuterLevel, defaultInnerLevel, programObj.passthroughPerVertexMembers); @@ -3243,14 +3243,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { BlendFactor dstAlpha = BlendFactor::Zero; BlendEquation colorEquation = BlendEquation::Add; BlendEquation alphaEquation = BlendEquation::Add; - MG_Pipe::gPipeInputs.GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha); - MG_Pipe::gPipeInputs.GetBlendEquationIndexed(i, colorEquation, alphaEquation); - const Bool blendEnabled = MG_Pipe::gPipeInputs.IsCapabilityEnabledIndexed(CapabilityInput::Blend, i); + MG_Pipe::gPipeInputs->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha); + MG_Pipe::gPipeInputs->GetBlendEquationIndexed(i, colorEquation, alphaEquation); + const Bool blendEnabled = MG_Pipe::gPipeInputs->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i); // Per-draw-buffer color write mask (glColorMaski). Divergent per-attachment masks require // the independentBlend device feature; when it is absent, fall back to draw buffer 0's // mask for every attachment (matching the non-indexed glColorMask broadcast). const BoolVec4 bufferMask = - MG_Pipe::gPipeInputs.GetColorMaskIndexed(m_independentBlendFeatureEnabled ? i : 0); + MG_Pipe::gPipeInputs->GetColorMaskIndexed(m_independentBlendFeatureEnabled ? i : 0); VkColorComponentFlags attachmentColorWriteMask = static_cast( (bufferMask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) | (bufferMask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) | @@ -3404,7 +3404,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRect2D VulkanRenderer::ComputeGLScissorRect(Uint32 index, const IntVec2& extent, VkSurfaceTransformFlagBitsKHR preTransform, Bool isDefaultFbo) const { - const auto& parameters = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const auto& parameters = MG_Pipe::gPipeInputs->GetRenderStateParameters(); if (!GLScissorTestClips(index)) { VkRect2D full{}; full.offset = {0, 0}; @@ -3480,7 +3480,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // counter still would make Espryt skip re-syncing the blend state it just changed. // The second-level DynamicTailKey compare below is therefore what actually absorbs a // pipeline-only change, exactly as it did before P2: one key build, no vkCmd*. - const Uint paramsVersion = MG_Pipe::gPipeInputs.GetRenderStateParametersVersion(); + const Uint paramsVersion = MG_Pipe::gPipeInputs->GetRenderStateParametersVersion(); if (shadow.dynamicTailValid && shadow.dynamicTailParamsVersion == paramsVersion && shadow.dynamicTailExtentX == extent.x() && shadow.dynamicTailExtentY == extent.y() && shadow.dynamicTailIsDefaultFbo == isDefaultFbo) { @@ -3504,7 +3504,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // re-derive the value its shadow already holds. DynamicStateShadow::DynamicTailKey key; { - const RenderStateParameters& p = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const RenderStateParameters& p = MG_Pipe::gPipeInputs->GetRenderStateParameters(); // Viewport 0 and its depth range: ApplyGLViewportState reads exactly those two // (per-index state for indices > 0 is keyed separately, see multiViewportKey below). key.viewport[0] = p.Viewports[0].x(); @@ -3763,9 +3763,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!fbo) MagmaWireFatal("clear-framebuffer-record"); ClearAttachmentPayload payload{}; payload.mask = mask; - payload.color = MG_Pipe::gPipeInputs.GetClearColor(); - payload.depth = MG_Pipe::gPipeInputs.GetClearDepth(); - payload.stencil = MG_Pipe::gPipeInputs.GetClearStencil(); + payload.color = MG_Pipe::gPipeInputs->GetClearColor(); + payload.depth = MG_Pipe::gPipeInputs->GetClearDepth(); + payload.stencil = MG_Pipe::gPipeInputs->GetClearStencil(); ClearWireFramebuffer(*fbo, payload); return; } @@ -4846,7 +4846,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const SharedPtr wireReplyHasNoPackBuffer; const auto& pixelPackBufferObject = wireReplyHasNoPackBuffer; - const auto packParams = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false); + const auto packParams = MG_Pipe::gPipeInputs->GetPixelStoreParameters(false); const SizeT rowPixels = static_cast(packParams.RowLength > 0 ? packParams.RowLength : width); const SizeT packAlignment = packParams.Alignment > 0 ? static_cast(packParams.Alignment) : 1; const SizeT dstRowStride = ((rowPixels * dstPixelBytes) + packAlignment - 1) / packAlignment * packAlignment; @@ -4894,7 +4894,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // resets its counter state, because those bytes describe the previous owner's span. Uint32 VulkanRenderer::CurrentXfbCounterSlot() { constexpr Uint32 kNoSlot = static_cast(kXfbCounterObjectSlots); - const Uint64 identity = MG_Pipe::gPipeInputs.GetBoundTransformFeedbackLifetimeId(); + const Uint64 identity = MG_Pipe::gPipeInputs->GetBoundTransformFeedbackLifetimeId(); MOBILEGL_ASSERT(identity != 0, "transform feedback object reported the free-slot sentinel (0) as its identity - " "every slot would then read as 'mine' without ever being claimed"); @@ -4943,14 +4943,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { } Bool VulkanRenderer::BeginXfbCaptureForDraw(FrameContext::FrameData& frame) { - if (!m_transformFeedbackFeatureEnabled || !MG_Pipe::gPipeInputs.IsLive() || - !MG_Pipe::gPipeInputs.IsTransformFeedbackActive()) { + if (!m_transformFeedbackFeatureEnabled || !MG_Pipe::gPipeInputs->IsLive() || + !MG_Pipe::gPipeInputs->IsTransformFeedbackActive()) { return false; } // A paused span captures nothing, and the counter buffers keep their values, so the // next resumed draw appends exactly where the last captured one stopped - which is // what pause/resume means (ARB_transform_feedback2). - if (MG_Pipe::gPipeInputs.IsTransformFeedbackPaused()) { + if (MG_Pipe::gPipeInputs->IsTransformFeedbackPaused()) { return false; } // The bound pipeline's last pre-rasterization stage has to have been declared with Xfb @@ -4993,7 +4993,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } const Uint32 counterSlot = CurrentXfbCounterSlot(); - const Uint64 generation = MG_Pipe::gPipeInputs.GetTransformFeedbackGeneration(); + const Uint64 generation = MG_Pipe::gPipeInputs->GetTransformFeedbackGeneration(); const Bool resume = m_xfbCountersValid[counterSlot] && m_xfbLastSeenGeneration[counterSlot] == generation; m_xfbLastSeenGeneration[counterSlot] = generation; @@ -5667,7 +5667,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { default: break; } if (mergeGranularity != 0) { - const RenderStateParameters& rsp = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const RenderStateParameters& rsp = MG_Pipe::gPipeInputs->GetRenderStateParameters(); if (rsp.PrimitiveRestartEnabled || rsp.PrimitiveRestartFixedIndexEnabled) { mergeGranularity = 0; } @@ -6428,8 +6428,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!m_provokingVertexModePerPipeline) { return VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; } - return (MG_Pipe::gPipeInputs.IsLive() && - MG_Pipe::gPipeInputs.GetProvokingVertexMode() == ProvokingVertexMode::FirstVertex) + return (MG_Pipe::gPipeInputs->IsLive() && + MG_Pipe::gPipeInputs->GetProvokingVertexMode() == ProvokingVertexMode::FirstVertex) ? VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT : VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.inc b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.inc index e58bcf00..5e9b22d7 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.inc +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.inc @@ -238,7 +238,7 @@ // Mip generation samples and writes the texture's own color space; // GL_FRAMEBUFFER_SRGB only controls framebuffer operations. if (!mipmap) destination.format = ResolveSrgbAttachmentWriteFormat(destination.format, - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)); + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)); VkFormatProperties destinationProperties{}; vkGetPhysicalDeviceFormatProperties(m_physicalDevice.handle, destination.format, &destinationProperties); if (!(destinationProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) return false; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDraw.inc b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDraw.inc index 0e29085e..ef67c75e 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDraw.inc +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDraw.inc @@ -248,7 +248,7 @@ !(memo.drawFramebuffer == st.BoundFramebuffer[SizeT(MG_Pipe::MGPipeFramebufferTarget::Draw)]) || memo.textureImageEpoch != m_textureManager->GetTextureImageEpoch() || memo.resourceEraseEpoch != m_textureManager->GetResourceEraseEpoch() || - memo.framebufferSrgb != MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)) + memo.framebufferSrgb != MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)) return false; // The resources are good while the erase epoch holds. Each must still be what the walk // left: in GENERAL and synced to its record's serial with nothing pending. @@ -300,7 +300,7 @@ auto& passKey = scratch.passKey; passKey.ResetKeepingCapacity(); passKey.isDefault = fbo.IsDefault; - passKey.framebufferSrgb = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); + passKey.framebufferSrgb = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); if (fbo.IsDefault) { passKey.swapchain = m_swapchainObject.GetHandle(); // A drawing pass on the default framebuffer is what makes the freshly acquired @@ -326,7 +326,7 @@ {image.resource, image.storage, surface.Kind == MG_Pipe::kMGPipeSurfaceKindRenderbuffer}); if (aspect == VK_IMAGE_ASPECT_COLOR_BIT) image.format = ResolveSrgbAttachmentWriteFormat(image.format, - MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)); + MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb)); const VkImageLayout layout = aspect == VK_IMAGE_ASPECT_COLOR_BIT ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_GENERAL; // Already in its attachment layout: its barrier (which closes any open pass) waits until @@ -470,7 +470,7 @@ memo.drawFramebuffer = st.BoundFramebuffer[SizeT(MG_Pipe::MGPipeFramebufferTarget::Draw)]; memo.textureImageEpoch = m_textureManager->GetTextureImageEpoch(); memo.resourceEraseEpoch = m_textureManager->GetResourceEraseEpoch(); - memo.framebufferSrgb = MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); + memo.framebufferSrgb = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); memo.passHash = m_wireDrawPass->hash; memo.marks.assign(scratch.gpuWriteMarks.begin(), scratch.gpuWriteMarks.end()); } @@ -522,7 +522,7 @@ ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionFlags(GetBaseTransformFlagsRaw(fbo->IsDefault)); - if (m_transformFeedbackFeatureEnabled && MG_Pipe::gPipeInputs.IsTransformFeedbackActive() && + if (m_transformFeedbackFeatureEnabled && MG_Pipe::gPipeInputs->IsTransformFeedbackActive() && program.GetTransformFeedbackVaryingCount() > 0) flags |= ProgramFactory::CompileOptionBit::XfbCapture; const auto* programObject = &m_programFactory->GetOrCreateProgram(program, flags); @@ -727,7 +727,7 @@ return false; } indexType = width == 4 ? VK_INDEX_TYPE_UINT32 : width == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT8; - const auto& restart = MG_Pipe::gPipeInputs.GetRenderStateParameters(); + const auto& restart = MG_Pipe::gPipeInputs->GetRenderStateParameters(); const Uint32 fixed = MG_Util::FixedRestartIndexForGLType(indices->indexType); const Bool replaceRestart = restart.PrimitiveRestartEnabled && !restart.PrimitiveRestartFixedIndexEnabled && restart.PrimitiveRestartIndex < fixed; @@ -864,7 +864,7 @@ VkFormat format = VK_FORMAT_UNDEFINED; const void* data = nullptr; VkDeviceSize size = 0; - if (!TryGetCurrentVertexAttributeUploadPayload(MG_Pipe::gPipeInputs.GetCurrentVertexAttribute(location), + if (!TryGetCurrentVertexAttributeUploadPayload(MG_Pipe::gPipeInputs->GetCurrentVertexAttribute(location), programObj.vertexInputTypes[location], format, data, size)) { MGL_WIRE_DECLINE_AT(CurrentAttributePayload, "a disabled array's current attribute value has no upload payload"); return false; @@ -987,7 +987,7 @@ const Int32 attachment = fbo.DrawBuffers[i]; if (attachment < 0 || attachment >= static_cast(MG_Pipe::kMGPipeMaxColorAttachments)) continue; if (!fbo.IsDefault && fbo.Color[attachment].Kind == MG_Pipe::kMGPipeSurfaceKindNone) continue; - const auto mask = MG_Pipe::gPipeInputs.GetColorMaskIndexed(i); + const auto mask = MG_Pipe::gPipeInputs->GetColorMaskIndexed(i); if (!mask.r() && !mask.g() && !mask.b() && !mask.a()) continue; if (!mask.r() || !mask.g() || !mask.b() || !mask.a()) { all = false; break; } if (i >= key.colorReferences.size() || key.colorReferences[i] == VK_ATTACHMENT_UNUSED || @@ -1007,7 +1007,7 @@ : nullptr; VkImageAspectFlags depthStencilAspects = 0; if (remaining & GL_DEPTH_BUFFER_BIT) { - if (!MG_Pipe::gPipeInputs.GetDepthMask()) { + if (!MG_Pipe::gPipeInputs->GetDepthMask()) { handled |= GL_DEPTH_BUFFER_BIT; // nothing to write, as on the standalone path } else if (!fbo.IsDefault && fbo.Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) { handled |= GL_DEPTH_BUFFER_BIT; // no depth surface: nothing to clear @@ -1018,7 +1018,7 @@ } } if (remaining & GL_STENCIL_BUFFER_BIT) { - const Uint32 mask = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front).WriteMask & 255u; + const Uint32 mask = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front).WriteMask & 255u; if (mask == 0) { handled |= GL_STENCIL_BUFFER_BIT; } else if (!fbo.IsDefault && fbo.Stencil.Kind == MG_Pipe::kMGPipeSurfaceKindNone) { @@ -1047,7 +1047,7 @@ VkRect2D area{{0, 0}, {key.width, key.height}}; if (GLScissorTestClips()) { - const auto& box = MG_Pipe::gPipeInputs.GetScissorBox(); + const auto& box = MG_Pipe::gPipeInputs->GetScissorBox(); const Int32 x0 = std::max(box.x(), 0), y0 = std::max(box.y(), 0); const Int32 x1 = std::min(box.x() + box.z(), static_cast(key.width)); const Int32 y1 = std::min(box.y() + box.w(), static_cast(key.height)); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc index 97bc53a6..34df1a32 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc @@ -370,7 +370,7 @@ const Uint64 passHash = active->hash; VkRect2D area{{0, 0}, {key.width, key.height}}; if (GLScissorTestClips()) { - const auto& box = MG_Pipe::gPipeInputs.GetScissorBox(); + const auto& box = MG_Pipe::gPipeInputs->GetScissorBox(); const Int32 x0 = std::max(box.x(), 0), y0 = std::max(box.y(), 0); const Int32 x1 = std::min(box.x() + box.z(), static_cast(key.width)); const Int32 y1 = std::min(box.y() + box.w(), static_cast(key.height)); @@ -394,7 +394,7 @@ const Int32 slot = fbo.DrawBuffers[i]; if (slot < 0 || slot >= static_cast(MG_Pipe::kMGPipeMaxColorAttachments)) continue; if (fbo.Color[slot].Kind == MG_Pipe::kMGPipeSurfaceKindNone) continue; - const auto mask = MG_Pipe::gPipeInputs.GetColorMaskIndexed(i); + const auto mask = MG_Pipe::gPipeInputs->GetColorMaskIndexed(i); if (!mask.r() && !mask.g() && !mask.b() && !mask.a()) continue; if (!mask.r() || !mask.g() || !mask.b() || !mask.a() || payload.colorEncoding != ClearColorEncoding::Float) { all = false; @@ -429,7 +429,7 @@ (key.attachments[key.depthReference].aspect & aspect) != 0; }; if (remaining & GL_DEPTH_BUFFER_BIT) { - if (!MG_Pipe::gPipeInputs.GetDepthMask() || fbo.Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) { + if (!MG_Pipe::gPipeInputs->GetDepthMask() || fbo.Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) { handled |= GL_DEPTH_BUFFER_BIT; } else if (depthStencilHeld(fbo.Depth, VK_IMAGE_ASPECT_DEPTH_BIT)) { depthStencilAspects |= VK_IMAGE_ASPECT_DEPTH_BIT; @@ -437,7 +437,7 @@ } } if (remaining & GL_STENCIL_BUFFER_BIT) { - const Uint32 mask = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front).WriteMask & 255u; + const Uint32 mask = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front).WriteMask & 255u; if (mask == 0 || fbo.Stencil.Kind == MG_Pipe::kMGPipeSurfaceKindNone) { handled |= GL_STENCIL_BUFFER_BIT; } else if (mask == 255u && depthStencilHeld(fbo.Stencil, VK_IMAGE_ASPECT_STENCIL_BIT)) { @@ -472,7 +472,7 @@ const Bool scissor = GLScissorTestClips(); const auto wholeImage = [&](const WireImage& image) { if (!scissor) return true; - const auto& box = MG_Pipe::gPipeInputs.GetScissorBox(); + const auto& box = MG_Pipe::gPipeInputs->GetScissorBox(); return box.x() <= 0 && box.y() <= 0 && box.x() + box.z() >= static_cast(image.extent.width) && box.y() + box.w() >= static_cast(image.extent.height); }; @@ -498,7 +498,7 @@ if (slot < 0 || slot >= static_cast(MG_Pipe::kMGPipeMaxColorAttachments)) continue; const auto& surface = fbo.Color[slot]; if (surface.Kind == MG_Pipe::kMGPipeSurfaceKindNone) continue; - const auto mask = MG_Pipe::gPipeInputs.GetColorMaskIndexed(i); + const auto mask = MG_Pipe::gPipeInputs->GetColorMaskIndexed(i); if (!mask.r() && !mask.g() && !mask.b() && !mask.a()) continue; if (!mask.r() || !mask.g() || !mask.b() || !mask.a()) { all = false; @@ -538,13 +538,13 @@ return true; }; if (remaining & GL_DEPTH_BUFFER_BIT) { - if (!MG_Pipe::gPipeInputs.GetDepthMask() || fbo.Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) + if (!MG_Pipe::gPipeInputs->GetDepthMask() || fbo.Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) handled |= GL_DEPTH_BUFFER_BIT; else if (depthStencil(fbo.Depth, VK_IMAGE_ASPECT_DEPTH_BIT)) handled |= GL_DEPTH_BUFFER_BIT; } if (remaining & GL_STENCIL_BUFFER_BIT) { - const Uint32 mask = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front).WriteMask & 255u; + const Uint32 mask = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front).WriteMask & 255u; if (mask == 0 || fbo.Stencil.Kind == MG_Pipe::kMGPipeSurfaceKindNone) handled |= GL_STENCIL_BUFFER_BIT; else if (mask == 255u && depthStencil(fbo.Stencil, VK_IMAGE_ASPECT_STENCIL_BIT)) @@ -564,7 +564,7 @@ void VulkanRenderer::ClearWireFramebuffer(const MG_Pipe::MGPFramebufferState& fbo, const ClearAttachmentPayload& clearRequest, GLint drawbuffer) { - if (MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) return; + if (MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) return; // P15 S0: what the draw pass can take is cleared inside it (ClearWireFramebufferInPass, // WireDraw.inc); only the buffers it hands back take the standalone pass below. // P15: in the open pass when it is this framebuffer's (the in-pass clear) or merely holds @@ -586,12 +586,12 @@ if (m_wireRetiredObjects.size() >= kRetiredObjectsBeforeSubmit && m_wirePreparationDepth == 0 && HasPendingRecordedWork()) (void)FlushPendingCommands(); - if (MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) return; + if (MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) return; const auto clearSurface = [&](const MG_Pipe::MGPSurface& surface, VkImageAspectFlags aspect, Uint32 colorIndex) { if (!fbo.IsDefault && surface.Kind == MG_Pipe::kMGPipeSurfaceKindNone) return; if (aspect == VK_IMAGE_ASPECT_COLOR_BIT) { - const auto mask = MG_Pipe::gPipeInputs.GetColorMaskIndexed(colorIndex); + const auto mask = MG_Pipe::gPipeInputs->GetColorMaskIndexed(colorIndex); if (!mask.r() && !mask.g() && !mask.b() && !mask.a()) return; if (!mask.r() || !mask.g() || !mask.b() || !mask.a()) { MGLOG_W_ONCE("DirectVulkan: glClear with a partial color mask is not supported"); @@ -599,10 +599,10 @@ } } if (aspect & VK_IMAGE_ASPECT_DEPTH_BIT) { - if (!MG_Pipe::gPipeInputs.GetDepthMask()) aspect &= ~VK_IMAGE_ASPECT_DEPTH_BIT; + if (!MG_Pipe::gPipeInputs->GetDepthMask()) aspect &= ~VK_IMAGE_ASPECT_DEPTH_BIT; } if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) { - const Uint32 mask = MG_Pipe::gPipeInputs.GetStencilState(StencilFace::Front).WriteMask & 255u; + const Uint32 mask = MG_Pipe::gPipeInputs->GetStencilState(StencilFace::Front).WriteMask & 255u; if (!mask) aspect &= ~VK_IMAGE_ASPECT_STENCIL_BIT; else if (mask != 255u) { MGLOG_W_ONCE("DirectVulkan: glClear with a partial stencil write mask is not supported"); @@ -615,7 +615,7 @@ m_textureManager->FlushPendingUploads(); VkRect2D area{{0, 0}, image.extent}; if (GLScissorTestClips()) { - const auto& box = MG_Pipe::gPipeInputs.GetScissorBox(); + const auto& box = MG_Pipe::gPipeInputs->GetScissorBox(); const Int32 x0 = std::max(box.x(), 0), y0 = std::max(box.y(), 0); const Int32 x1 = std::min(box.x() + box.z(), static_cast(image.extent.width)); const Int32 y1 = std::min(box.y() + box.w(), static_cast(image.extent.height)); @@ -1264,7 +1264,7 @@ // The scissor test clips blit writes: intersect the destination rectangle with // the scissor box and shrink the source proportionally. if (GLScissorTestClips()) { - const IntVec4& scissor = MG_Pipe::gPipeInputs.GetScissorBox(); + const IntVec4& scissor = MG_Pipe::gPipeInputs->GetScissorBox(); const auto clipAxis = [](GLint& d0, GLint& d1, GLint& s0, GLint& s1, GLint clipLo, GLint clipHi) -> Bool { const Bool dstFlipped = d1 < d0; GLint lo = dstFlipped ? d1 : d0; diff --git a/MobileGL/MG_Backend/MGPipe/PipeInputs.cpp b/MobileGL/MG_Backend/MGPipe/PipeInputs.cpp index 91263c10..af001d12 100644 --- a/MobileGL/MG_Backend/MGPipe/PipeInputs.cpp +++ b/MobileGL/MG_Backend/MGPipe/PipeInputs.cpp @@ -442,7 +442,7 @@ namespace MobileGL::MG_Pipe { // D10: THE WIDER PREDICATE, and the narrow one was a latent crash rather than a missing // optimisation. Gated on the REHEARSAL, this early-returned for the whole life of a // spawn server - because that knob is off by default and nothing in the spawn shape - // turns it on - so the server's gPipeInputs.ContextIdentity() stayed nullptr forever. + // turns it on - so the server's gPipeInputs->ContextIdentity() stayed nullptr forever. // DirectGLES' fb-slot memo compares that identity FIRST and with no generation, so a // nullptr against its own nullptr initialiser reads as a CACHE HIT and hands out a slot // that was never filled. `st` lands the named Fatal at that site; this is the gate that @@ -596,12 +596,12 @@ namespace MobileGL::MG_Pipe { // The seven carry no MGP_INPUT_CHECK at all (the declared exception argued at // PipeInputs.h's F-class block), so freshness can never reach them and neither can the // stamp's withdrawal. This is the only thing that puts them in `rsp`. - if (!gPipeInputs.ServerStampedVerb()) return; + if (!gPipeInputs->ServerStampedVerb()) return; const auto ownership = MGPipeFieldOwnershipOf(field); if (ownership == MGPipeFieldOwnership::kFatal) - MGPipeInputPoisonFatalForVerb(field, gPipeInputs.CurrentVerb()); + MGPipeInputPoisonFatalForVerb(field, gPipeInputs->CurrentVerb()); if (ownership == MGPipeFieldOwnership::kBarrierPulled) - CountBarrierPull(field, gPipeInputs.CurrentVerb()); + CountBarrierPull(field, gPipeInputs->CurrentVerb()); } #endif // MOBILEGL_BUILD_RECORD_ARM && MOBILEGL_PIPE_POISON diff --git a/MobileGL/MG_Backend/MGPipe/PipeInputs.h b/MobileGL/MG_Backend/MGPipe/PipeInputs.h index 57e496fa..9678be59 100644 --- a/MobileGL/MG_Backend/MGPipe/PipeInputs.h +++ b/MobileGL/MG_Backend/MGPipe/PipeInputs.h @@ -832,12 +832,18 @@ namespace MobileGL::MG_Pipe { // have. Nothing about the block's contents changed; what changed is that the name resolves to // the SESSION'S block on a thread that belongs to one. // - // WHY A THREAD-LOCAL REFERENCE, AND NOT SOMETHING CLEVERER. gPipeInputs is spelled at ~380 - // sites in MG_Backend/MG_Impl (they read `MG_Pipe::gPipeInputs.` directly since P13 retired the - // pull/push switch macro); a reference whose TARGET varies with the calling thread is the - // only shape that keeps all of them compiling and all of them correct. The cost is one TLS - // address computation per access site - not one per field, and with no guard: the reference is - // bound once per thread on its first use. + // WHY A THREAD-LOCAL SLOT, AND NOT SOMETHING CLEVERER. gPipeInputs is spelled at ~380 + // sites in MG_Backend/MG_Impl (they read `MG_Pipe::gPipeInputs->` directly since P13 retired the + // pull/push switch macro); a name whose TARGET varies with the calling thread is the only + // shape that keeps all of them compiling and all of them correct. + // + // P15: A POINTER SLOT, NOT A REFERENCE. It used to be a `thread_local PipeInputs&` bound by a + // dynamic initializer, and a thread_local with a dynamic initializer is reached through its + // TLS init function, which tests two more thread_local guards on every read: three TLS + // address calls per access in a dlopen'ed library, at every API level. The slot below is + // constant-initialized and trivially destructible, so an access is one TLS address + // computation, a load and a null test; the binding itself is unchanged - once per thread, at + // its first use, through the same resolver. // // THE RESOLVER IS A HOOK because this header may not know about sessions (MG_Remote/Server // owns them and includes THIS header, not the other way round). It is installed once by the @@ -860,7 +866,27 @@ namespace MobileGL::MG_Pipe { return gPipeInputsDefault; } - inline thread_local PipeInputs& gPipeInputs = MGPipeServerInputsForCallingThread(); + class PipeInputsThreadSlot { + public: + constexpr PipeInputsThreadSlot() = default; + PipeInputsThreadSlot(const PipeInputsThreadSlot&) = delete; + PipeInputsThreadSlot& operator=(const PipeInputsThreadSlot&) = delete; + // The block's address is `&*gPipeInputs`; the slot's own address names nothing. + void operator&() const = delete; + + PipeInputs& Get() { + PipeInputs* bound = m_bound; + if (bound == nullptr) [[unlikely]] bound = m_bound = &MGPipeServerInputsForCallingThread(); + return *bound; + } + PipeInputs* operator->() { return &Get(); } + PipeInputs& operator*() { return Get(); } + operator PipeInputs&() { return Get(); } + + private: + PipeInputs* m_bound = nullptr; + }; + inline constinit thread_local PipeInputsThreadSlot gPipeInputs; #if MOBILEGL_BUILD_DISAGGREGATED // ============================================================================ diff --git a/MobileGL/MG_Backend/Record/RecordVerbSink.cpp b/MobileGL/MG_Backend/Record/RecordVerbSink.cpp index 9bbe96f1..a47f0536 100644 --- a/MobileGL/MG_Backend/Record/RecordVerbSink.cpp +++ b/MobileGL/MG_Backend/Record/RecordVerbSink.cpp @@ -275,11 +275,11 @@ namespace MobileGL::MG_Record { // Save the server-visible pack state, force neutral for the read, restore. Both go through // the applier's own set_pixel_pack_state entry point (MGPipeApplySetPixelPackState writes - // gPipeInputs.m_pixelStore[0], which the backend's ReadPixels reads via + // gPipeInputs->m_pixelStore[0], which the backend's ReadPixels reads via // gPipeInputs->GetPixelStoreParameters); the read is synchronous on this thread, so the window // in which the pack state is neutral does not outlive the call. const MG_Pipe::PixelStoreParameters savedPack = - MG_Pipe::gPipeInputs.GetPixelStoreParameters(/*isUnpack=*/false); + MG_Pipe::gPipeInputs->GetPixelStoreParameters(/*isUnpack=*/false); // MG_Pipe owns the constant (MGPipeTypes.h): in a verify build the compare-at-read hook's // oracle for the pack half inside this window is the same value, and a second hand-typed // copy would drift without a build break. @@ -566,7 +566,7 @@ namespace MobileGL::MG_Record { // session child (false = latched, the verb declines); unarmed they still die. Bool CheckUnitWindows(const MG_Pipe::MGPipeApplierState& st, const char* verb) { if (st.SamplerViewCount == 0 && st.SamplerStateCount == 0) return true; - const Int maxTouched = MG_Pipe::gPipeInputs.GetMaxTouchedTextureUnit(); + const Int maxTouched = MG_Pipe::gPipeInputs->GetMaxTouchedTextureUnit(); if (maxTouched < 0) return true; const Uint32 required = static_cast(maxTouched) + 1u; if (st.SamplerViewStart != 0 || st.SamplerViewCount < required) { diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 6e38463e..9225e5d5 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -671,7 +671,7 @@ namespace MobileGL::MG_Pipe { } void MGPipeVerifyReadHook(const PipeInputs& self, MGPipeInputField field, Uint index0, Uint index1) { - if (&self != &gPipeInputs || !g_verify.Enabled) return; + if (&self != &*gPipeInputs || !g_verify.Enabled) return; const auto index = static_cast(field); if (kMGPipeInputFieldSticky[index]) return; // P13 W5: the monolith verb port applies records without a server stamp, and its readback @@ -2256,7 +2256,7 @@ namespace MobileGL::MG_Pipe { // static initialisation, by the translation unit that owns the forward. const Bool kCompileEnvHookRegistered = [] { MGPipeSetCompileEnvChangedHook([] { - if (gPipeInputs.IsLive()) gPipeInputs.InvalidateCompileEnv(); + if (gPipeInputs->IsLive()) gPipeInputs->InvalidateCompileEnv(); }); return true; }(); @@ -3134,7 +3134,7 @@ namespace MobileGL::MG_Pipe { // GLContext's m_currentVertexAttributes hold exactly those, so the diff below is // EMPTY on the one walk that must publish everything. The server's mirror is not // default: MGPipeApplierReset() clears the CSO store and the residual block and - // leaves gPipeInputs.m_currentVertexAttribute holding the PREVIOUS context's + // leaves gPipeInputs->m_currentVertexAttribute holding the PREVIOUS context's // defaults. So the InvalidateAll() a fresh context does to the set-hash // suppressor would have been cancelled two lines later by this diff, and the one // call P2 fully owns would publish nothing across a context change - exactly the diff --git a/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.cpp b/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.cpp index 8aa82fad..da999575 100644 --- a/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.cpp +++ b/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.cpp @@ -32,10 +32,10 @@ namespace MGITest { out->peekAvailable = true; out->roleSplitActive = MGP::MGPipeRoleSplitRehearsalActive(); MGP::PipeInputs& client = MGP::MGPipeClientInputs(); - out->blocksDistinct = &client != &MGP::gPipeInputs; + out->blocksDistinct = &client != &*MGP::gPipeInputs; out->clientSerial = client.FilledState().CurrentVerbSerial; - out->serverSerial = MGP::gPipeInputs.FilledState().CurrentVerbSerial; - out->serverIdentity = MGP::gPipeInputs.ContextIdentity(); + out->serverSerial = MGP::gPipeInputs->FilledState().CurrentVerbSerial; + out->serverIdentity = MGP::gPipeInputs->ContextIdentity(); return true; } diff --git a/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.h b/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.h index 708a92c4..233acd11 100644 --- a/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.h +++ b/MobileGL/MG_IntegrationTest/Harness/DualBlockPeek.h @@ -39,7 +39,7 @@ namespace MGITest { // verb boundaries; the server block's moves only on a server verb stamp. unsigned long long clientSerial = 0; unsigned long long serverSerial = 0; - // gPipeInputs.ContextIdentity(): non-null once the server has stamped a verb boundary + // gPipeInputs->ContextIdentity(): non-null once the server has stamped a verb boundary // under the rehearsal (CONTRACT-P5E §3.2's server-owned identity). const void* serverIdentity = nullptr; }; diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index 52064b3c..9195b464 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -1655,8 +1655,40 @@ namespace MobileGL::MG_State { } // namespace GLState // Leak-at-exit storage; see GlobalObjects.cpp. - thread_local SharedPtr pGLContext; + constinit thread_local CurrentGLContextSlot pGLContext; + + // The reference that keeps the calling thread's pGLContext alive (Core.h). Registered for + // destruction on the thread's first assignment; at thread exit it clears the slot first, so + // whatever the context's destructor reaches sees no current context rather than one that is + // being destroyed. + struct CurrentGLContextOwner { + SharedPtr context; + ~CurrentGLContextOwner() { pGLContext.m_context = nullptr; } + }; + namespace { + thread_local CurrentGLContextOwner tCurrentGLContextOwner; + } + + const SharedPtr& CurrentGLContextSlot::Shared() const { + return tCurrentGLContextOwner.context; + } + + SharedPtr CurrentGLContextSlot::Take() { + m_context = nullptr; + return Move(tCurrentGLContextOwner.context); + } + + CurrentGLContextSlot& CurrentGLContextSlot::operator=(SharedPtr context) { + auto& owner = tCurrentGLContextOwner; + m_context = context.get(); + // The old context's last reference may run destructors that read pGLContext: the slot + // already names the new one, as it did when this was a SharedPtr assignment. + SharedPtr previous = Move(owner.context); + owner.context = Move(context); + return *this; + } + #if MOBILEGL_BUILD_DISAGGREGATED - thread_local Bool tThreadReleasedLostContext = false; + constinit thread_local Bool tThreadReleasedLostContext = false; #endif } // namespace MobileGL::MG_State diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index 657345e2..23429bc3 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -782,7 +782,53 @@ namespace MobileGL { // thread that never crossed an eglMakeCurrent keeps the process default MG_State::Init() // gave it. NULL on a thread for which neither has happened, the same answer a process // that never reached MG_State::Init() (the spawn server image) has always given. - extern thread_local SharedPtr pGLContext; + // + // P15: A PLAIN POINTER IN TLS, WITH THE OWNING REFERENCE KEPT BESIDE IT. Every GL entry + // point reads this, often several times. A thread_local with a destructor (the SharedPtr + // it used to be) is reached through its TLS init function, which tests a second + // thread_local guard first: two TLS address calls per read in a dlopen'ed library, at + // every API level. This object is trivially destructible and constant-initialized, so a + // read is one TLS address computation and a load. The SharedPtr that keeps the context + // alive lives in a separate thread_local in Core.cpp, written only by the assignments + // below (eglMakeCurrent and the release edge, MG_State::Init(), tests); its destructor + // clears this pointer before it drops the reference, so a thread's exit leaves no + // dangling pointer behind. + // + // Assignment, reset() and the SharedPtr conversions touch the owner and belong to the + // CALLING THREAD only: never assign through a reference to another thread's slot. + class CurrentGLContextSlot { + public: + constexpr CurrentGLContextSlot() = default; + CurrentGLContextSlot(const CurrentGLContextSlot&) = delete; + CurrentGLContextSlot& operator=(const CurrentGLContextSlot&) = delete; + + GLState::GLContext* get() const { return m_context; } + GLState::GLContext* operator->() const { return m_context; } + GLState::GLContext& operator*() const { return *m_context; } + explicit operator bool() const { return m_context != nullptr; } + + // The owning reference (cold: a second TLS read). + const SharedPtr& Shared() const; + operator const SharedPtr&() const& { return Shared(); } + // A move out of the slot is spelled Take(): std::move of the slot does not compile. + operator const SharedPtr&() const&& = delete; + SharedPtr Take(); + + CurrentGLContextSlot& operator=(SharedPtr context); + void reset() { *this = nullptr; } + + friend Bool operator==(const CurrentGLContextSlot& slot, std::nullptr_t) { + return slot.m_context == nullptr; + } + friend Bool operator==(const CurrentGLContextSlot& slot, const SharedPtr& other) { + return slot.m_context == other.get(); + } + + private: + friend struct CurrentGLContextOwner; + GLState::GLContext* m_context = nullptr; + }; + extern constinit thread_local CurrentGLContextSlot pGLContext; #if MOBILEGL_BUILD_DISAGGREGATED // True on a thread whose last EGL release let go of a context lost with an ended server // session, until it makes a context current again. The release hands such a thread the @@ -790,7 +836,7 @@ namespace MobileGL { // TLS that state's last owner), so this is what keeps the thread answering as lost: an // application that releases its context before asking glGetGraphicsResetStatus - Qt's // render threads do - still learns that the context is gone and rebuilds it. - extern thread_local Bool tThreadReleasedLostContext; + extern constinit thread_local Bool tThreadReleasedLostContext; #endif // The fallback pGLContext starts at and an EGL release edge restores to: the process's diff --git a/MobileGL/MG_Test/Backend/DirectGLES/ContextEpochTest.cpp b/MobileGL/MG_Test/Backend/DirectGLES/ContextEpochTest.cpp index 5c155131..f45a9e34 100644 --- a/MobileGL/MG_Test/Backend/DirectGLES/ContextEpochTest.cpp +++ b/MobileGL/MG_Test/Backend/DirectGLES/ContextEpochTest.cpp @@ -147,17 +147,17 @@ TEST(ContextEpochTest, SameXfbNameInTwoServedContextsDoesNotAliasThePausedSpan) TEST(ContextEpochTest, ServerLivenessDoesNotFollowTheClientContextOrAVerbStamp) { #if MOBILEGL_BUILD_DISAGGREGATED DriverScope scope; - auto context = Move(MG_State::pGLContext); + auto context = MG_State::pGLContext.Take(); const Bool previous = MG_Pipe::MGPipeServerContextIsLive(); MG_Pipe::MGPipeServerSetContextLive(false); MG_State::pGLContext = MakeUnique(); - EXPECT_FALSE(MG_Pipe::gPipeInputs.IsLive()); + EXPECT_FALSE(MG_Pipe::gPipeInputs->IsLive()); MG_Pipe::MGPipeServerSetContextLive(true); MG_State::pGLContext.reset(); - EXPECT_TRUE(MG_Pipe::gPipeInputs.IsLive()); + EXPECT_TRUE(MG_Pipe::gPipeInputs->IsLive()); MG_Pipe::MGPipeServerSetContextLive(false); MG_Pipe::MGPipeServerStampVerbBoundary(MG_Pipe::MGPipeVerb::DrawArrays); - EXPECT_FALSE(MG_Pipe::gPipeInputs.IsLive()) << "a stale command resurrected a destroyed server context"; + EXPECT_FALSE(MG_Pipe::gPipeInputs->IsLive()) << "a stale command resurrected a destroyed server context"; MG_Pipe::MGPipeServerClearVerbBoundary(); MG_State::pGLContext = Move(context); MG_Pipe::MGPipeServerSetContextLive(previous); diff --git a/MobileGL/MG_Test/Buffer/SplitBufferTest.cpp b/MobileGL/MG_Test/Buffer/SplitBufferTest.cpp index 15a7a6d0..1be35f3a 100644 --- a/MobileGL/MG_Test/Buffer/SplitBufferTest.cpp +++ b/MobileGL/MG_Test/Buffer/SplitBufferTest.cpp @@ -87,7 +87,7 @@ namespace { m_blockKb = MG_Config::RecordArm.PersistentBlockKb; m_adoptTier = MG_Config::Ipc.AdoptTier; m_pipeStats = MG_Config::Features.PipeStats; - m_context = Move(MG_State::pGLContext); + m_context = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MG_Config::Transport = MG_Config::TransportMode::InProcess; MG_Config::RecordArm.PersistentBlockKb = 64; diff --git a/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp b/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp index 66b45f1b..62c578fe 100644 --- a/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp +++ b/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp @@ -87,7 +87,7 @@ namespace { class FieldOwnershipTest : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); #if MOBILEGL_BUILD_DISAGGREGATED MG_Config::Ipc.StrictErrors = false; @@ -486,14 +486,14 @@ TEST_F(FieldOwnershipTest, TheResidualFillsSuppliedMemoReKeysOnEveryInputThatMov TEST_F(FieldOwnershipTest, AServerStampMakesRecordSuppliedFieldsFreshAndWithdrawsTheRest) { MGPipeServerStampVerbBoundary(MGPipeVerb::Clear); - EXPECT_TRUE(gPipeInputs.ServerStampedVerb()); - EXPECT_EQ(gPipeInputs.CurrentVerb(), MGPipeVerb::Clear); + EXPECT_TRUE(gPipeInputs->ServerStampedVerb()); + EXPECT_EQ(gPipeInputs->CurrentVerb(), MGPipeVerb::Clear); const MGPipeFieldMask& mask = kMGPipeClassFieldMask[static_cast( kMGPipeVerbClass[static_cast(MGPipeVerb::Clear)])]; SizeT stamped = 0; for (SizeT i = 0; i < kMGPipeInputFieldCount; ++i) { const auto field = static_cast(i); - const Bool fresh = MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), field); + const Bool fresh = MGPipeInputFieldIsFresh(gPipeInputs->FilledState(), field); // The stamp respects the verb's own may-read table for the client fill's reason: a // field outside the class was never copied for this verb, so answering it would hand // the server the previous verb's value. @@ -512,7 +512,7 @@ TEST_F(FieldOwnershipTest, AServerStampMakesRecordSuppliedFieldsFreshAndWithdraw // `answerable` out of kMGPipeFieldOwnership, so it can only catch a stamp that disagrees // with the table - never a table that is wrong. These four say what the stamp must do for // four fields whose class is an argument of this package rather than a lookup. - const MGPipeFilledState& filled = gPipeInputs.FilledState(); + const MGPipeFilledState& filled = gPipeInputs->FilledState(); EXPECT_TRUE(MGPipeInputFieldIsFresh(filled, MGPipeInputField::GetClearColor)); // supplied EXPECT_TRUE(MGPipeInputFieldIsFresh(filled, MGPipeInputField::GetRenderStateParameters)); EXPECT_FALSE(MGPipeInputFieldIsFresh(filled, MGPipeInputField::GetFramebufferBindingSlot)); // pulled @@ -525,14 +525,14 @@ TEST_F(FieldOwnershipTest, AServerStampMakesRecordSuppliedFieldsFreshAndWithdraw // changing. Before this, the seven most dangerous fields were exempt by construction. TEST_F(FieldOwnershipTest, TheStickyExemptionIsCancelledByTheServerStamp) { MGPipeValidateForVerb(MGPipeVerb::Clear); // the CLIENT fills and stamps all 63, sticky included - EXPECT_TRUE(MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), MGPipeInputField::RecordError)); + EXPECT_TRUE(MGPipeInputFieldIsFresh(gPipeInputs->FilledState(), MGPipeInputField::RecordError)); MGPipeServerStampVerbBoundary(MGPipeVerb::Clear); for (SizeT i = 0; i < kMGPipeFieldOwnershipForwardCount; ++i) { const MGPipeInputField field = kMGPipeFieldOwnershipForwardField[i]; // P5f fe retired the scalar forwards to server-owned answers. Their freshness // comes from that ownership; the remaining client forwards lose the exemption. const Bool serverOwned = MGPipeFieldOwnershipOf(field) == MGPipeFieldOwnership::kApplierDerived; - EXPECT_EQ(MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), field), serverOwned) + EXPECT_EQ(MGPipeInputFieldIsFresh(gPipeInputs->FilledState(), field), serverOwned) << kMGPipeInputFieldNames[Index(field)] << " has the wrong server-stamp freshness"; } } @@ -543,21 +543,21 @@ TEST_F(FieldOwnershipTest, ARecordSuppliedFieldIsReadableAfterAServerStamp) { ASSERT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetClearColor), MGPipeFieldOwnership::kRecordSupplied); MGPipeServerStampVerbBoundary(MGPipeVerb::Clear); - (void)gPipeInputs.GetClearColor(); - (void)gPipeInputs.GetRenderStateParameters(); + (void)gPipeInputs->GetClearColor(); + (void)gPipeInputs->GetRenderStateParameters(); EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); // The pixel store is in kReadback's class, not kClear's, so its readable half is exercised // under the verb that actually reads it. And P5c rv's record-supplied rows join it there: // GetActiveTextureUnit is exactly the read that used to count into `rsp`. MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - (void)gPipeInputs.GetPixelStoreParameters(false); // the half that has a carrier - (void)gPipeInputs.GetActiveTextureUnit(); // P5c rv: set_context_values carries it - (void)gPipeInputs.GetMaxTouchedTextureUnit(); + (void)gPipeInputs->GetPixelStoreParameters(false); // the half that has a carrier + (void)gPipeInputs->GetActiveTextureUnit(); // P5c rv: set_context_values carries it + (void)gPipeInputs->GetMaxTouchedTextureUnit(); EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); // And a shutter answers the applier's own Serial under a server stamp (APPLIER-DERIVED), // not the client's residual-fill copy: still zero pulls, and the answer MOVES when the // applier's texture state does. - (void)gPipeInputs.GetTextureBindGeneration(); + (void)gPipeInputs->GetTextureBindGeneration(); EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); } @@ -578,16 +578,16 @@ TEST_F(FieldOwnershipTest, SetContextValuesLandsInPipeInputsAndTheShuttersAnswer MGPipeApplySetContextValues(values); MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - EXPECT_EQ(gPipeInputs.GetActiveTextureUnit(), 5); - EXPECT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), 23); + EXPECT_EQ(gPipeInputs->GetActiveTextureUnit(), 5); + EXPECT_EQ(gPipeInputs->GetMaxTouchedTextureUnit(), 23); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(BufferTarget::Uniform), SizeT{7}); - EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(BufferTarget::Vertex), SizeT{0}); - EXPECT_TRUE(gPipeInputs.IsTransformFeedbackActive()); - EXPECT_FALSE(gPipeInputs.IsTransformFeedbackPaused()); - EXPECT_EQ(gPipeInputs.GetTransformFeedbackGeneration(), 0x1112131415161718ull); - EXPECT_EQ(gPipeInputs.GetBoundTransformFeedbackLifetimeId(), 0x2122232425262728ull); - EXPECT_EQ(gPipeInputs.GetTransformFeedbackCapturedVertices(), 0x3132333435363738ull); + EXPECT_EQ(gPipeInputs->GetTouchedBufferBindingPointCount(BufferTarget::Uniform), SizeT{7}); + EXPECT_EQ(gPipeInputs->GetTouchedBufferBindingPointCount(BufferTarget::Vertex), SizeT{0}); + EXPECT_TRUE(gPipeInputs->IsTransformFeedbackActive()); + EXPECT_FALSE(gPipeInputs->IsTransformFeedbackPaused()); + EXPECT_EQ(gPipeInputs->GetTransformFeedbackGeneration(), 0x1112131415161718ull); + EXPECT_EQ(gPipeInputs->GetBoundTransformFeedbackLifetimeId(), 0x2122232425262728ull); + EXPECT_EQ(gPipeInputs->GetTransformFeedbackCapturedVertices(), 0x3132333435363738ull); // Eight record-supplied reads and not one residual pull. EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); @@ -595,12 +595,12 @@ TEST_F(FieldOwnershipTest, SetContextValuesLandsInPipeInputsAndTheShuttersAnswer // SHUTTERS - the value matters only in that it MOVES when the server's texture state does // and never walks backwards - so the pin is the identity with the applier's counters, not // any particular number. - EXPECT_EQ(gPipeInputs.GetTextureBindGeneration(), MGPipeApplierTextureShutterSerial()); - EXPECT_EQ(gPipeInputs.GetSamplingResolutionGeneration(), MGPipeApplierTextureShutterSerial()); - EXPECT_EQ(gPipeInputs.GetTextureContextId(), MGPipeApplierContextSerial()); + EXPECT_EQ(gPipeInputs->GetTextureBindGeneration(), MGPipeApplierTextureShutterSerial()); + EXPECT_EQ(gPipeInputs->GetSamplingResolutionGeneration(), MGPipeApplierTextureShutterSerial()); + EXPECT_EQ(gPipeInputs->GetTextureContextId(), MGPipeApplierContextSerial()); const Uint64 before = MGPipeApplierTextureShutterSerial(); MGPipeApplierNoteTextureStateMoved(); - EXPECT_EQ(gPipeInputs.GetTextureBindGeneration(), before + 1) + EXPECT_EQ(gPipeInputs->GetTextureBindGeneration(), before + 1) << "a texture-state apply moved the serial but the shutter did not answer with it"; EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); } @@ -612,7 +612,7 @@ TEST_F(FieldOwnershipTest, ABarrierPulledReadAfterAServerStampIsCountedNotFatal) const ChildResult r = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), std::string::npos) << r.Log; @@ -629,7 +629,7 @@ TEST_F(FieldOwnershipTest, AStickyForwardIsCountedAsAResidualPull) { const ChildResult r = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::Clear); - (void)gPipeInputs.ValidateProgramName(1u); + (void)gPipeInputs->ValidateProgramName(1u); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"ValidateProgramName@Clear\"}"), std::string::npos) << r.Log; @@ -644,11 +644,11 @@ TEST_F(FieldOwnershipTest, AStickyForwardIsCountedAsAResidualPull) { // for - and what keeps build-split's monolith lanes behaving as a verify build's do. TEST_F(FieldOwnershipTest, NothingIsCountedOutsideAServerStampedVerb) { MGPipeValidateForVerb(MGPipeVerb::ReadPixels); - (void)gPipeInputs.ValidateProgramName(1u); - gPipeInputs.InvalidateCompileEnv(); - (void)gPipeInputs.GetActiveTextureUnit(); + (void)gPipeInputs->ValidateProgramName(1u); + gPipeInputs->InvalidateCompileEnv(); + (void)gPipeInputs->GetActiveTextureUnit(); EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); - EXPECT_FALSE(gPipeInputs.ServerStampedVerb()); + EXPECT_FALSE(gPipeInputs->ServerStampedVerb()); } // THE APPLIER'S OWN CLEAR, reached directly rather than through the client's fill. In a spawned @@ -658,13 +658,13 @@ TEST_F(FieldOwnershipTest, NothingIsCountedOutsideAServerStampedVerb) { // InvalidateCompileEnv is reached from backend initialisation under - is gone for good. TEST_F(FieldOwnershipTest, TheAppliersOwnClearDisarmsTheStampWithoutTheClientsFill) { MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - ASSERT_TRUE(gPipeInputs.ServerStampedVerb()); - (void)gPipeInputs.GetActiveTextureUnit(); + ASSERT_TRUE(gPipeInputs->ServerStampedVerb()); + (void)gPipeInputs->GetActiveTextureUnit(); ASSERT_EQ(MGPipeResidualPullCount(), Uint64{0}); MGPipeServerClearVerbBoundary(); - EXPECT_FALSE(gPipeInputs.ServerStampedVerb()); - (void)gPipeInputs.ValidateProgramName(1u); - gPipeInputs.InvalidateCompileEnv(); + EXPECT_FALSE(gPipeInputs->ServerStampedVerb()); + (void)gPipeInputs->ValidateProgramName(1u); + gPipeInputs->InvalidateCompileEnv(); EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0}); } @@ -677,7 +677,7 @@ TEST_F(FieldOwnershipTest, ABarrierPulledFieldOutsideTheVerbsClassIsStillFatal) #if MGTEST_HAVE_FORK const ChildResult r = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::Clear); - (void)gPipeInputs.GetProgramForDraw(); // retired accessor, outside kClear too + (void)gPipeInputs->GetProgramForDraw(); // retired accessor, outside kClear too }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetProgramForDraw@Clear\"}"), std::string::npos) @@ -693,7 +693,7 @@ TEST_F(FieldOwnershipTest, ResidualPullsReachThePublishedPerFrameCounter) { PS::SetEnabledForTesting(true); PS::ResetForTesting(); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetCurrentVertexAttribute(0); + (void)gPipeInputs->GetCurrentVertexAttribute(0); EXPECT_EQ(PS::FrameCalls(PS::CallClass::ResidualPulls), Uint64{0}); EXPECT_NE(PS::FormatWindowLine().find(" rsp=0"), std::string::npos) << PS::FormatWindowLine(); // Prove the reporting channel did not merely become a constant zero after retirement. @@ -742,9 +742,9 @@ TEST_F(FieldOwnershipTest, SplitBindingPointCapacityNeverConsultsTheFrontend) { RoleSplitArm guard; guard.Arm(true); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::Uniform), 84u); - EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::TransformFeedback), 84u); - EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::PixelPack), 0u); + EXPECT_EQ(gPipeInputs->GetBufferBindingPointCount(BufferTarget::Uniform), 84u); + EXPECT_EQ(gPipeInputs->GetBufferBindingPointCount(BufferTarget::TransformFeedback), 84u); + EXPECT_EQ(gPipeInputs->GetBufferBindingPointCount(BufferTarget::PixelPack), 0u); EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetBufferBindingPointCount), MGPipeFieldOwnership::kApplierDerived); MGPipeServerClearVerbBoundary(); @@ -756,16 +756,16 @@ TEST_F(FieldOwnershipTest, SplitOpenSpansAreOwnedByTheApplierAndSurviveOtherBind auto& state = MGPipeApplier(); state.StreamOutputSpans.clear(); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(0)); - EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(11)); + EXPECT_FALSE(gPipeInputs->HasOpenTransformFeedbackSpan(0)); + EXPECT_FALSE(gPipeInputs->HasOpenTransformFeedbackSpan(11)); state.StreamOutputSpans[11] = {}; state.StreamOutputSpans[12] = {}; state.BoundStreamOutputLifetimeId = 12; - EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(11)); - EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(12)); + EXPECT_TRUE(gPipeInputs->HasOpenTransformFeedbackSpan(11)); + EXPECT_TRUE(gPipeInputs->HasOpenTransformFeedbackSpan(12)); state.StreamOutputSpans.erase(12); - EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(11)); - EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(12)); + EXPECT_TRUE(gPipeInputs->HasOpenTransformFeedbackSpan(11)); + EXPECT_FALSE(gPipeInputs->HasOpenTransformFeedbackSpan(12)); EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::HasOpenTransformFeedbackSpan), MGPipeFieldOwnership::kApplierDerived); state.StreamOutputSpans.clear(); @@ -793,7 +793,7 @@ TEST_F(FieldOwnershipTest, SplitCaptureSnapshotSurvivesMakeCurrentUntilObjectRel returning.IsTransformFeedbackActive = 1; MGPipeApplySetContextValues(returning); EXPECT_EQ(state.BoundStreamOutputLifetimeId, begin.LifetimeId); - EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(begin.LifetimeId)); + EXPECT_TRUE(gPipeInputs->HasOpenTransformFeedbackSpan(begin.LifetimeId)); const auto found = state.StreamOutputSpans.find(begin.LifetimeId); EXPECT_NE(found, state.StreamOutputSpans.end()); if (found != state.StreamOutputSpans.end()) { @@ -803,13 +803,13 @@ TEST_F(FieldOwnershipTest, SplitCaptureSnapshotSurvivesMakeCurrentUntilObjectRel EXPECT_EQ(found->second.Targets[3].Size, 64u); } MGPipeApplierReleaseObjectRecords(); - EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(begin.LifetimeId)); + EXPECT_FALSE(gPipeInputs->HasOpenTransformFeedbackSpan(begin.LifetimeId)); EXPECT_EQ(state.BoundStreamOutputLifetimeId, 0u); } TEST_F(FieldOwnershipTest, RoleSplitOffFoldsTheFillSideOntoTheSharedBlock) { EXPECT_FALSE(MGPipeRoleSplitRehearsalActive()); - EXPECT_EQ(&MGPipeClientInputs(), &gPipeInputs); + EXPECT_EQ(&MGPipeClientInputs(), &*gPipeInputs); } // The knob alone is not the arm: under monolith transport the two roles are one thread and @@ -820,7 +820,7 @@ TEST_F(FieldOwnershipTest, RoleSplitUnderMonolithTransportIsStillOneBlock) { MG_Config::Ipc.RoleSplitState = true; MG_Config::Transport = MG_Config::TransportMode::Monolith; EXPECT_FALSE(MGPipeRoleSplitRehearsalActive()); - EXPECT_EQ(&MGPipeClientInputs(), &gPipeInputs); + EXPECT_EQ(&MGPipeClientInputs(), &*gPipeInputs); } // D1c/D10 (CONTRACT-P6 3.2, 3.4). THE PREDICATE THAT IS TRUE WITHOUT THE KNOB, and the reason @@ -850,38 +850,38 @@ TEST_F(FieldOwnershipTest, MonolithKeepsOneBlockAndTheWiderPredicateSaysSo) { MG_Config::Ipc.RoleSplitState = false; MG_Config::Transport = MG_Config::TransportMode::Monolith; EXPECT_FALSE(MGPipeBlocksAreDistinct()); - EXPECT_EQ(&MGPipeClientInputs(), &gPipeInputs); + EXPECT_EQ(&MGPipeClientInputs(), &*gPipeInputs); } TEST_F(FieldOwnershipTest, RoleSplitGivesTheFillSideADistinctBlockTheStampNeverTouches) { RoleSplitArm guard; guard.Arm(true); ASSERT_TRUE(MGPipeRoleSplitRehearsalActive()); - ASSERT_NE(&MGPipeClientInputs(), &gPipeInputs); + ASSERT_NE(&MGPipeClientInputs(), &*gPipeInputs); - const Uint64 serverSerialBefore = gPipeInputs.FilledState().CurrentVerbSerial; + const Uint64 serverSerialBefore = gPipeInputs->FilledState().CurrentVerbSerial; const Uint64 clientSerialBefore = MGPipeClientInputs().FilledState().CurrentVerbSerial; MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - EXPECT_EQ(gPipeInputs.FilledState().CurrentVerbSerial, serverSerialBefore + 1); + EXPECT_EQ(gPipeInputs->FilledState().CurrentVerbSerial, serverSerialBefore + 1); EXPECT_EQ(MGPipeClientInputs().FilledState().CurrentVerbSerial, clientSerialBefore) << "the server's verb stamp reached into the client block"; - EXPECT_TRUE(gPipeInputs.ServerStampedVerb()); + EXPECT_TRUE(gPipeInputs->ServerStampedVerb()); EXPECT_FALSE(MGPipeClientInputs().ServerStampedVerb()); // The fill side's clear is the client block's own: it must not disarm the server's stamp, // which is CONTRACT-P5E §3.2's "the server's stamp is server-private" as a fact rather // than as a comment. MGPipeClientClearVerbBoundary(); - EXPECT_TRUE(gPipeInputs.ServerStampedVerb()) + EXPECT_TRUE(gPipeInputs->ServerStampedVerb()) << "the client-role clear withdrew the SERVER's stamp"; MGPipeServerClearVerbBoundary(); - EXPECT_FALSE(gPipeInputs.ServerStampedVerb()); + EXPECT_FALSE(gPipeInputs->ServerStampedVerb()); // And the server block's identity is server-owned under the rehearsal (§3.2's other half): // the stamp set it, and it is non-null - a null identity reads as a hit against // DirectGLES' zero-initialised fb-slot memo cache, which is the unnamed crash this line // exists to preclude. - EXPECT_NE(gPipeInputs.ContextIdentity(), nullptr); + EXPECT_NE(gPipeInputs->ContextIdentity(), nullptr); } // The fill side's writers land in the client block alone. MGPipeLeaveVerb rather than @@ -891,12 +891,12 @@ TEST_F(FieldOwnershipTest, RoleSplitGivesTheFillSideADistinctBlockTheStampNeverT TEST_F(FieldOwnershipTest, TheClientVerbLeaveWritesTheClientBlockAlone) { RoleSplitArm guard; guard.Arm(true); - ASSERT_NE(&MGPipeClientInputs(), &gPipeInputs); - const Uint64 serverSerialBefore = gPipeInputs.FilledState().CurrentVerbSerial; + ASSERT_NE(&MGPipeClientInputs(), &*gPipeInputs); + const Uint64 serverSerialBefore = gPipeInputs->FilledState().CurrentVerbSerial; const Uint64 clientSerialBefore = MGPipeClientInputs().FilledState().CurrentVerbSerial; MGPipeLeaveVerb(); EXPECT_EQ(MGPipeClientInputs().FilledState().CurrentVerbSerial, clientSerialBefore + 1); - EXPECT_EQ(gPipeInputs.FilledState().CurrentVerbSerial, serverSerialBefore) + EXPECT_EQ(gPipeInputs->FilledState().CurrentVerbSerial, serverSerialBefore) << "a fill-side write reached the server block"; EXPECT_EQ(MGPipeClientInputs().CurrentVerb(), MGPipeVerb::kVerbCount); } @@ -909,9 +909,9 @@ TEST_F(FieldOwnershipTest, AClientFreshStampCannotReviveARetiredServerGetter) { MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); // Simulate a regressed writer stamping the old mirror as fresh. FATAL is a // representation verdict, not a freshness verdict, and must still reject it. - auto& filled = const_cast(gPipeInputs.FilledState()); + auto& filled = const_cast(gPipeInputs->FilledState()); filled.FilledGen[Index(MGPipeInputField::GetBoundVertexArray)] = filled.CurrentVerbSerial; - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), @@ -923,7 +923,7 @@ TEST_F(FieldOwnershipTest, StrictErrorsTurnsABarrierPulledReadIntoANamedAbort) { const ChildResult r = RunInChild([] { MG_Config::Ipc.StrictErrors = true; MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), std::string::npos) << r.Log; @@ -936,7 +936,7 @@ TEST_F(FieldOwnershipTest, TheSameReadWithoutStrictErrorsSurvivesAndIsCounted) { const ChildResult r = RunInChild([] { MG_Config::Ipc.StrictErrors = false; MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), std::string::npos) << r.Log; @@ -950,7 +950,7 @@ TEST_F(FieldOwnershipTest, AnEscalatedRecordsPullIsAdmittedAndSaysWhy) { MG_Config::Ipc.StrictErrors = true; MGPipeApplierSetCurrentRecordBarrieredByEscalation(true); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), std::string::npos) << r.Log; @@ -963,7 +963,7 @@ TEST_F(FieldOwnershipTest, StrictErrorsReachTheStickyForwardsAndNameThemByField) const ChildResult r = RunInChild([] { MG_Config::Ipc.StrictErrors = true; MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.ValidateProgramName(1u); + (void)gPipeInputs->ValidateProgramName(1u); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"ValidateProgramName@DrawArrays\"}"), std::string::npos) << r.Log; @@ -976,7 +976,7 @@ TEST_F(FieldOwnershipTest, AnAdmittedBarrierPullIsLoudOnceAndNotFatal) { const ChildResult r = RunInChild([] { MG_Config::Ipc.StrictErrors = true; MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - (void)gPipeInputs.ValidateProgramName(1u); + (void)gPipeInputs->ValidateProgramName(1u); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"ValidateProgramName@ReadPixels\"}"), std::string::npos) << r.Log; @@ -987,7 +987,7 @@ TEST_F(FieldOwnershipTest, AnAdmittedBarrierPullIsLoudOnceAndNotFatal) { TEST_F(FieldOwnershipTest, AFatalClassReadAbortsEvenWithoutStrictErrors) { const ChildResult r = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetTransformFeedbackPausedPrimitiveCounter(); + (void)gPipeInputs->GetTransformFeedbackPausedPrimitiveCounter(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, " @@ -1002,7 +1002,7 @@ TEST_F(FieldOwnershipTest, TheComputeProgramIsServedUnderADispatchStampFromP5bOn const ChildResult r = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::DispatchCompute); - (void)gPipeInputs.GetProgramForDispatch(); + (void)gPipeInputs->GetProgramForDispatch(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetProgramForDispatch@DispatchCompute\"}"), std::string::npos) << r.Log; @@ -1016,7 +1016,7 @@ TEST_F(FieldOwnershipTest, TheComputeProgramIsServedUnderADispatchStampFromP5bOn TEST_F(FieldOwnershipTest, TheUnpackHalfOfThePixelStoreAbortsWhileThePackHalfDoesNot) { const ChildResult fatal = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - (void)gPipeInputs.GetPixelStoreParameters(true); + (void)gPipeInputs->GetPixelStoreParameters(true); }); ASSERT_TRUE(DiedOfAbort(fatal)) << DescribeStatus(fatal) << "\n" << fatal.Log; EXPECT_NE(fatal.Log.find("Fatal{UnmigratedPipeInput, \"GetPixelStoreParameters@ReadPixels\"}"), @@ -1032,7 +1032,7 @@ TEST_F(FieldOwnershipTest, TheUnpackHalfOfThePixelStoreAbortsWhileThePackHalfDoe const ChildResult ok = RunInChild([] { MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - (void)gPipeInputs.GetPixelStoreParameters(false); + (void)gPipeInputs->GetPixelStoreParameters(false); if (MGPipeResidualPullCount() != 0) ::_exit(7); }); ASSERT_TRUE(ExitedWith(ok, 0)) << DescribeStatus(ok) << "\n" << ok.Log; @@ -1067,7 +1067,7 @@ TEST_F(FieldOwnershipTest, DualBlockMakesABarrierPulledReadANamedAbortWithoutStr MG_Config::Ipc.RoleSplitState = true; MG_Config::Ipc.StrictErrors = false; MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"), std::string::npos) << r.Log; @@ -1081,7 +1081,7 @@ TEST_F(FieldOwnershipTest, DualBlockDoesNotArmUnderMonolithTransport) { MG_Config::Ipc.RoleSplitState = true; // A real monolith fill, not a manufactured server stamp on a monolith process. MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetBoundVertexArray(); + (void)gPipeInputs->GetBoundVertexArray(); if (MGPipeRoleSplitRehearsalActive() || MGPipeResidualPullCount() != 0) ::_exit(7); }); ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log; diff --git a/MobileGL/MG_Test/Pipe/FramebufferEmitTest.cpp b/MobileGL/MG_Test/Pipe/FramebufferEmitTest.cpp index 4a6771f9..9216ebdd 100644 --- a/MobileGL/MG_Test/Pipe/FramebufferEmitTest.cpp +++ b/MobileGL/MG_Test/Pipe/FramebufferEmitTest.cpp @@ -246,7 +246,7 @@ namespace { kMGPipeSubsystemFramebuffer | kMGPipeSubsystemTextureResources | kMGPipeSubsystemSamplers; - m_previousContext = Move(MG_State::pGLContext); + m_previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MGPipeFramebufferEmitterInstance().ResetForTest(); MGPipeTextureEmitterInstance().ResetForTest(); diff --git a/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp b/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp index d2fc9482..eedd8f6b 100644 --- a/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp +++ b/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp @@ -73,7 +73,7 @@ namespace { class PipeInputsTest : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MGPipeSetPoisonOmission(nullptr, nullptr); } @@ -85,7 +85,7 @@ namespace { }; #if MOBILEGL_PIPE_POISON - Bool Fresh(MGPipeInputField field) { return MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), field); } + Bool Fresh(MGPipeInputField field) { return MGPipeInputFieldIsFresh(gPipeInputs->FilledState(), field); } #endif [[maybe_unused]] constexpr const char* kOmittedFatal ="Fatal{UnmigratedPipeInput, \"GetActiveTextureUnit@GenerateMipmap\"}"; @@ -147,7 +147,7 @@ TEST_F(PipeInputsTest, OmittingOneFieldForOneVerbLeavesExactlyThatFieldStale) { EXPECT_TRUE(Fresh(MGPipeInputField::GetTextureUnitObject)); EXPECT_FALSE(Fresh(MGPipeInputField::GetActiveTextureUnit)); // The value was still copied: only the stamp is withheld. - EXPECT_EQ(gPipeInputs.CurrentVerb(), MGPipeVerb::GenerateMipmap); + EXPECT_EQ(gPipeInputs->CurrentVerb(), MGPipeVerb::GenerateMipmap); // Exactly that field: a field is fresh iff its bit is in kTextureOp's mask and it is not // the omitted one. { @@ -174,7 +174,7 @@ TEST_F(PipeInputsTest, OmittingOneFieldForOneVerbLeavesExactlyThatFieldStale) { } // Negative control B, layer 2 (G5): the read itself. The child fills GenerateMipmap with the -// omission and reads gPipeInputs.GetActiveTextureUnit(); the parent expects SIGABRT and the +// omission and reads gPipeInputs->GetActiveTextureUnit(); the parent expects SIGABRT and the // exact Fatal line, and that nothing else was fatal. TEST_F(PipeInputsTest, ReadingAnOmittedFieldAbortsNamingTheVerb) { #if !MOBILEGL_PIPE_POISON @@ -186,10 +186,10 @@ TEST_F(PipeInputsTest, ReadingAnOmittedFieldAbortsNamingTheVerb) { const ChildResult r = RunInChild([] { MGPipeSetPoisonOmission("GenerateMipmap", "GetActiveTextureUnit"); MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetRenderStateParameters(); // a filled field of the preceding draw: must not abort + (void)gPipeInputs->GetRenderStateParameters(); // a filled field of the preceding draw: must not abort MGPipeValidateForVerb(MGPipeVerb::GenerateMipmap); - (void)gPipeInputs.GetTextureUnitObject(0); // the sibling field: filled, must not abort - (void)gPipeInputs.GetActiveTextureUnit(); // the omitted field: Fatal + (void)gPipeInputs->GetTextureUnitObject(0); // the sibling field: filled, must not abort + (void)gPipeInputs->GetActiveTextureUnit(); // the omitted field: Fatal ::_exit(3); // reached only if the poison failed }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; @@ -207,10 +207,10 @@ TEST_F(PipeInputsTest, ReadingAFilledFieldCompletes) { ASSERT_FALSE(g_logPath.empty()) << "main() did not set MOBILEGL_LOG_FILE_PATH"; const ChildResult r = RunInChild([] { MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetRenderStateParameters(); + (void)gPipeInputs->GetRenderStateParameters(); MGPipeValidateForVerb(MGPipeVerb::GenerateMipmap); - (void)gPipeInputs.GetTextureUnitObject(0); - (void)gPipeInputs.GetActiveTextureUnit(); + (void)gPipeInputs->GetTextureUnitObject(0); + (void)gPipeInputs->GetActiveTextureUnit(); }); ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_EQ(r.Log.find("Fatal{"), std::string::npos) << r.Log; @@ -229,7 +229,7 @@ TEST_F(PipeInputsTest, ReadingBeforeAnyFillAbortsNamingNoVerb) { GTEST_SKIP() << "no fork() on this platform"; #else ASSERT_FALSE(g_logPath.empty()) << "main() did not set MOBILEGL_LOG_FILE_PATH"; - if (gPipeInputs.FilledState().CurrentVerbSerial != 0) { + if (gPipeInputs->FilledState().CurrentVerbSerial != 0) { GTEST_SKIP() << "another case already filled in this process; gtest_discover_tests runs each case alone"; } MG_State::pGLContext->SetLineWidth(7.0f); // a live value the default storage (0) does not hold @@ -237,7 +237,7 @@ TEST_F(PipeInputsTest, ReadingBeforeAnyFillAbortsNamingNoVerb) { #if MOBILEGL_PIPE_VERIFY MG_Config::Features.PipeVerify = true; #endif - (void)gPipeInputs.GetLineWidth(); // Fatal{UnmigratedPipeInput, "GetLineWidth@"} + (void)gPipeInputs->GetLineWidth(); // Fatal{UnmigratedPipeInput, "GetLineWidth@"} ::_exit(3); // reached only if the pre-fill window read as fresh }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; @@ -261,8 +261,8 @@ TEST_F(PipeInputsTest, PoisonOmitKnobArmsTheOmission) { const ChildResult r = RunInChild([] { MG_Config::Features.PipePoisonOmit = kOmissionKnob; MGPipeValidateForVerb(MGPipeVerb::GenerateMipmap); - (void)gPipeInputs.GetTextureUnitObject(0); // the sibling field: filled, must not abort - (void)gPipeInputs.GetActiveTextureUnit(); // the omitted field: Fatal + (void)gPipeInputs->GetTextureUnitObject(0); // the sibling field: filled, must not abort + (void)gPipeInputs->GetActiveTextureUnit(); // the omitted field: Fatal ::_exit(3); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; @@ -301,9 +301,9 @@ TEST_F(PipeInputsTest, CorruptedSnapshotFieldIsNamedWithItsSerial) { #if !MOBILEGL_PIPE_VERIFY GTEST_SKIP() << "verify not compiled in (MOBILEGL_PIPE_VERIFY=OFF)"; #else - const Uint64 serialBefore = gPipeInputs.FilledState().CurrentVerbSerial; + const Uint64 serialBefore = gPipeInputs->FilledState().CurrentVerbSerial; MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - const Uint64 serial = gPipeInputs.FilledState().CurrentVerbSerial; + const Uint64 serial = gPipeInputs->FilledState().CurrentVerbSerial; EXPECT_EQ(serial, serialBefore + 1); const MGPipeFieldMask& mask = kMGPipeClassFieldMask[static_cast(MGPipeVerbClass::kDraw)]; @@ -318,7 +318,7 @@ TEST_F(PipeInputsTest, CorruptedSnapshotFieldIsNamedWithItsSerial) { EXPECT_EQ(field, MGPipeInputField::GetRenderStateParameters); EXPECT_STREQ(kMGPipeInputFieldNames[static_cast(field)], "GetRenderStateParameters"); // The serial the report would print is the fill's, and it stamped that field. - EXPECT_EQ(gPipeInputs.FilledState().FilledGen[static_cast(field)], serial); + EXPECT_EQ(gPipeInputs->FilledState().FilledGen[static_cast(field)], serial); // A forwarded field has nothing to corrupt, and the corruption of a field outside the // mask is not seen by a compare over that mask. @@ -341,15 +341,15 @@ TEST_F(PipeInputsTest, MutatedFieldIsNamedAtRead) { #else ASSERT_FALSE(g_logPath.empty()) << "main() did not set MOBILEGL_LOG_FILE_PATH"; MGPipeValidateForVerb(MGPipeVerb::Clear); // the parent armed nothing: Features.PipeVerify is false here - const Uint64 serial = gPipeInputs.FilledState().CurrentVerbSerial + 1; // the child's DrawArrays fill + const Uint64 serial = gPipeInputs->FilledState().CurrentVerbSerial + 1; // the child's DrawArrays fill const ChildResult r = RunInChild([] { MG_Config::Features.PipeVerify = true; MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - const Float boundary = gPipeInputs.GetLineWidth(); // boundary == live: completes - (void)gPipeInputs.GetRenderStateParameters(); + const Float boundary = gPipeInputs->GetLineWidth(); // boundary == live: completes + (void)gPipeInputs->GetRenderStateParameters(); MG_State::pGLContext->SetLineWidth(boundary + 1.0f); if (MG_State::pGLContext->GetLineWidth() == boundary) ::_exit(7); // the mutation did not take - (void)gPipeInputs.GetLineWidth(); // the stored value is stale against the live one: Fatal + (void)gPipeInputs->GetLineWidth(); // the stored value is stale against the live one: Fatal ::_exit(3); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; @@ -375,7 +375,7 @@ TEST_F(PipeInputsTest, VerifyCorruptKnobNamesTheFieldAtEntry) { #else ASSERT_FALSE(g_logPath.empty()) << "main() did not set MOBILEGL_LOG_FILE_PATH"; MGPipeValidateForVerb(MGPipeVerb::Clear); - const Uint64 serial = gPipeInputs.FilledState().CurrentVerbSerial + 1; + const Uint64 serial = gPipeInputs->FilledState().CurrentVerbSerial + 1; const ChildResult r = RunInChild([] { MG_Config::Features.PipeVerify = true; MG_Config::Features.PipeVerifyCorrupt = "GetRenderStateParameters"; @@ -428,7 +428,7 @@ TEST_F(PipeInputsTest, VerifyFatalOffLogsTheDivergenceAndContinues) { #else ASSERT_FALSE(g_logPath.empty()) << "main() did not set MOBILEGL_LOG_FILE_PATH"; MGPipeValidateForVerb(MGPipeVerb::Clear); - const Uint64 serial = gPipeInputs.FilledState().CurrentVerbSerial + 1; + const Uint64 serial = gPipeInputs->FilledState().CurrentVerbSerial + 1; const ChildResult r = RunInChild([] { MG_Config::Features.PipeVerify = true; MG_Config::Features.PipeVerifyFatal = false; @@ -467,8 +467,8 @@ TEST_F(PipeInputsTest, EveryVerbFillsItsClassAndNothingElse) { << kMGPipeInputFieldNames[f] << " after " << kMGPipeVerbNames[v]; } } - EXPECT_EQ(gPipeInputs.ContextIdentity(), static_cast(MG_State::pGLContext.get())); - EXPECT_TRUE(gPipeInputs.IsLive()); + EXPECT_EQ(gPipeInputs->ContextIdentity(), static_cast(MG_State::pGLContext.get())); + EXPECT_TRUE(gPipeInputs->IsLive()); #endif } @@ -481,9 +481,9 @@ TEST_F(PipeInputsTest, EveryVerbFillsItsClassAndNothingElse) { TEST_F(PipeInputsTest, AFrontendMutationInsideAVerbRefreshesThePushedField) { auto& ctx = *MG_State::pGLContext; MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - ASSERT_EQ(gPipeInputs.GetSamplingResolutionGeneration(), ctx.GetSamplingResolutionGeneration()); - ASSERT_EQ(gPipeInputs.GetTextureBindGeneration(), ctx.GetTextureBindGeneration()); - ASSERT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), ctx.GetMaxTouchedTextureUnit()); + ASSERT_EQ(gPipeInputs->GetSamplingResolutionGeneration(), ctx.GetSamplingResolutionGeneration()); + ASSERT_EQ(gPipeInputs->GetTextureBindGeneration(), ctx.GetTextureBindGeneration()); + ASSERT_EQ(gPipeInputs->GetMaxTouchedTextureUnit(), ctx.GetMaxTouchedTextureUnit()); // What UniformManager's fallback path does mid-draw: change a sampler object's filter, // which bumps the context-wide sampling-resolution generation (SamplerObject.cpp). @@ -492,7 +492,7 @@ TEST_F(PipeInputsTest, AFrontendMutationInsideAVerbRefreshesThePushedField) { sampler->SetMinFilter(sampler->GetMinFilter() == SamplerFilterMode::Nearest ? SamplerFilterMode::Linear : SamplerFilterMode::Nearest); ASSERT_NE(ctx.GetSamplingResolutionGeneration(), samplingBefore) << "the mutation did not move the counter"; - EXPECT_EQ(gPipeInputs.GetSamplingResolutionGeneration(), ctx.GetSamplingResolutionGeneration()); + EXPECT_EQ(gPipeInputs->GetSamplingResolutionGeneration(), ctx.GetSamplingResolutionGeneration()); // And a bind reached from inside a verb moves both the bind generation and the // high-water mark of touched units (TextureState::NoteUnitTouched). @@ -501,8 +501,8 @@ TEST_F(PipeInputsTest, AFrontendMutationInsideAVerbRefreshesThePushedField) { ctx.NoteTextureUnitTouched(unit); ASSERT_NE(ctx.GetTextureBindGeneration(), bindBefore) << "the bind did not move the counter"; ASSERT_EQ(ctx.GetMaxTouchedTextureUnit(), unit); - EXPECT_EQ(gPipeInputs.GetTextureBindGeneration(), ctx.GetTextureBindGeneration()); - EXPECT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), ctx.GetMaxTouchedTextureUnit()); + EXPECT_EQ(gPipeInputs->GetTextureBindGeneration(), ctx.GetTextureBindGeneration()); + EXPECT_EQ(gPipeInputs->GetMaxTouchedTextureUnit(), ctx.GetMaxTouchedTextureUnit()); } // The notice refreshes the VALUE and never the stamp: a field this verb withheld the stamp @@ -547,7 +547,7 @@ TEST_F(PipeInputsTest, AFrontendMutationInsideAVerbDoesNotDivergeAtRead) { const ChildResult r = RunInChild([] { MG_Config::Features.PipeVerify = true; MGPipeValidateForVerb(MGPipeVerb::DrawArrays); - (void)gPipeInputs.GetSamplingResolutionGeneration(); // boundary == live: completes + (void)gPipeInputs->GetSamplingResolutionGeneration(); // boundary == live: completes auto& ctx = *MG_State::pGLContext; const Uint64 before = ctx.GetSamplingResolutionGeneration(); auto sampler = MakeShared(0u); @@ -556,10 +556,10 @@ TEST_F(PipeInputsTest, AFrontendMutationInsideAVerbDoesNotDivergeAtRead) { if (ctx.GetSamplingResolutionGeneration() == before) { ::_exit(7); // the mutation did not take: the case would pass for the wrong reason } - (void)gPipeInputs.GetSamplingResolutionGeneration(); // Fatal{PipeVerifyDiffer} without the notice + (void)gPipeInputs->GetSamplingResolutionGeneration(); // Fatal{PipeVerifyDiffer} without the notice ctx.NoteTextureUnitTouched(ctx.GetMaxTouchedTextureUnit() + 1); - (void)gPipeInputs.GetTextureBindGeneration(); - (void)gPipeInputs.GetMaxTouchedTextureUnit(); + (void)gPipeInputs->GetTextureBindGeneration(); + (void)gPipeInputs->GetMaxTouchedTextureUnit(); }); ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log; EXPECT_NE(r.Log.find("MGPipe: verify armed"), std::string::npos) << r.Log; diff --git a/MobileGL/MG_Test/Pipe/RecorderGoldenTest.cpp b/MobileGL/MG_Test/Pipe/RecorderGoldenTest.cpp index c676c757..ed7885fa 100644 --- a/MobileGL/MG_Test/Pipe/RecorderGoldenTest.cpp +++ b/MobileGL/MG_Test/Pipe/RecorderGoldenTest.cpp @@ -375,7 +375,7 @@ namespace { m_savedResourceOps = MGPipeGetResourceOps(); static const MGPipeResourceOps kEmpty{}; MGPipeSetResourceOps(&kEmpty); - m_savedContext = Move(MG_State::pGLContext); + m_savedContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); m_savedTable = MG_Backend::gBackendFunctionsTable; diff --git a/MobileGL/MG_Test/Pipe/RenderStateSpansTest.cpp b/MobileGL/MG_Test/Pipe/RenderStateSpansTest.cpp index 414b640a..77a7366b 100644 --- a/MobileGL/MG_Test/Pipe/RenderStateSpansTest.cpp +++ b/MobileGL/MG_Test/Pipe/RenderStateSpansTest.cpp @@ -146,60 +146,60 @@ namespace { // --------------------------------------------------------------------------------- void ExpectDerivedDrawFieldsMatch(GLContext& ctx, const char* tag) { SCOPED_TRACE(tag); - EXPECT_EQ(gPipeInputs.GetBlendColor(), ctx.GetBlendColor()); + EXPECT_EQ(gPipeInputs->GetBlendColor(), ctx.GetBlendColor()); for (Uint i = 0; i < kMGMaxDrawBuffers; ++i) { BlendEquation gotColor{}, gotAlpha{}, wantColor{}, wantAlpha{}; - gPipeInputs.GetBlendEquationIndexed(i, gotColor, gotAlpha); + gPipeInputs->GetBlendEquationIndexed(i, gotColor, gotAlpha); ctx.GetBlendEquationIndexed(i, wantColor, wantAlpha); EXPECT_EQ(gotColor, wantColor) << "blend equation " << i; EXPECT_EQ(gotAlpha, wantAlpha) << "blend equation " << i; BlendFactor gotSrcRGB{}, gotDstRGB{}, gotSrcA{}, gotDstA{}; BlendFactor wantSrcRGB{}, wantDstRGB{}, wantSrcA{}, wantDstA{}; - gPipeInputs.GetBlendFuncIndexed(i, gotSrcRGB, gotDstRGB, gotSrcA, gotDstA); + gPipeInputs->GetBlendFuncIndexed(i, gotSrcRGB, gotDstRGB, gotSrcA, gotDstA); ctx.GetBlendFuncIndexed(i, wantSrcRGB, wantDstRGB, wantSrcA, wantDstA); EXPECT_EQ(gotSrcRGB, wantSrcRGB) << "blend func " << i; EXPECT_EQ(gotDstRGB, wantDstRGB) << "blend func " << i; EXPECT_EQ(gotSrcA, wantSrcA) << "blend func " << i; EXPECT_EQ(gotDstA, wantDstA) << "blend func " << i; - EXPECT_EQ(gPipeInputs.GetColorMaskIndexed(i), ctx.GetColorMaskIndexed(i)) << "colour mask " << i; - EXPECT_EQ(gPipeInputs.IsCapabilityEnabledIndexed(CapabilityInput::Blend, i), + EXPECT_EQ(gPipeInputs->GetColorMaskIndexed(i), ctx.GetColorMaskIndexed(i)) << "colour mask " << i; + EXPECT_EQ(gPipeInputs->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i), ctx.IsCapabilityEnabledIndexed(CapabilityInput::Blend, i)) << "indexed blend enable " << i; } - EXPECT_EQ(gPipeInputs.GetCullFaceMode(), ctx.GetCullFaceMode()); - EXPECT_EQ(gPipeInputs.GetDepthFunc(), ctx.GetDepthFunc()); - EXPECT_EQ(gPipeInputs.GetDepthMask(), ctx.GetDepthMask()); + EXPECT_EQ(gPipeInputs->GetCullFaceMode(), ctx.GetCullFaceMode()); + EXPECT_EQ(gPipeInputs->GetDepthFunc(), ctx.GetDepthFunc()); + EXPECT_EQ(gPipeInputs->GetDepthMask(), ctx.GetDepthMask()); for (Uint i = 0; i < RenderStateParameters::MAX_VIEWPORTS; ++i) { - EXPECT_EQ(gPipeInputs.GetDepthRangeIndexed(i), ctx.GetDepthRangeIndexed(i)) << "depth range " << i; - EXPECT_EQ(gPipeInputs.GetViewportIndexed(i), ctx.GetViewportIndexed(i)) << "viewport " << i; - EXPECT_EQ(gPipeInputs.IsCapabilityEnabledIndexed(CapabilityInput::ScissorTest, i), + EXPECT_EQ(gPipeInputs->GetDepthRangeIndexed(i), ctx.GetDepthRangeIndexed(i)) << "depth range " << i; + EXPECT_EQ(gPipeInputs->GetViewportIndexed(i), ctx.GetViewportIndexed(i)) << "viewport " << i; + EXPECT_EQ(gPipeInputs->IsCapabilityEnabledIndexed(CapabilityInput::ScissorTest, i), ctx.IsCapabilityEnabledIndexed(CapabilityInput::ScissorTest, i)) << "indexed scissor enable " << i; } - EXPECT_EQ(gPipeInputs.GetLineWidth(), ctx.GetLineWidth()); - EXPECT_EQ(gPipeInputs.GetLogicOp(), ctx.GetLogicOp()); - EXPECT_EQ(gPipeInputs.GetMinSampleShadingValue(), ctx.GetMinSampleShadingValue()); - EXPECT_EQ(gPipeInputs.GetPatchDefaultInnerLevel(), ctx.GetPatchDefaultInnerLevel()); - EXPECT_EQ(gPipeInputs.GetPatchDefaultOuterLevel(), ctx.GetPatchDefaultOuterLevel()); - EXPECT_EQ(gPipeInputs.GetPatchVertices(), ctx.GetPatchVertices()); - EXPECT_EQ(gPipeInputs.GetPolygonModeFront(), ctx.GetPolygonModeFront()); - EXPECT_EQ(gPipeInputs.GetPolygonOffsetFactor(), ctx.GetPolygonOffsetFactor()); - EXPECT_EQ(gPipeInputs.GetPolygonOffsetUnits(), ctx.GetPolygonOffsetUnits()); - EXPECT_EQ(gPipeInputs.GetPrimitiveRestartIndex(), ctx.GetPrimitiveRestartIndex()); - EXPECT_EQ(gPipeInputs.GetProvokingVertexMode(), ctx.GetProvokingVertexMode()); - EXPECT_EQ(gPipeInputs.GetScissorBox(), ctx.GetScissorBox()); - EXPECT_EQ(gPipeInputs.GetViewport(), ctx.GetViewport()); + EXPECT_EQ(gPipeInputs->GetLineWidth(), ctx.GetLineWidth()); + EXPECT_EQ(gPipeInputs->GetLogicOp(), ctx.GetLogicOp()); + EXPECT_EQ(gPipeInputs->GetMinSampleShadingValue(), ctx.GetMinSampleShadingValue()); + EXPECT_EQ(gPipeInputs->GetPatchDefaultInnerLevel(), ctx.GetPatchDefaultInnerLevel()); + EXPECT_EQ(gPipeInputs->GetPatchDefaultOuterLevel(), ctx.GetPatchDefaultOuterLevel()); + EXPECT_EQ(gPipeInputs->GetPatchVertices(), ctx.GetPatchVertices()); + EXPECT_EQ(gPipeInputs->GetPolygonModeFront(), ctx.GetPolygonModeFront()); + EXPECT_EQ(gPipeInputs->GetPolygonOffsetFactor(), ctx.GetPolygonOffsetFactor()); + EXPECT_EQ(gPipeInputs->GetPolygonOffsetUnits(), ctx.GetPolygonOffsetUnits()); + EXPECT_EQ(gPipeInputs->GetPrimitiveRestartIndex(), ctx.GetPrimitiveRestartIndex()); + EXPECT_EQ(gPipeInputs->GetProvokingVertexMode(), ctx.GetProvokingVertexMode()); + EXPECT_EQ(gPipeInputs->GetScissorBox(), ctx.GetScissorBox()); + EXPECT_EQ(gPipeInputs->GetViewport(), ctx.GetViewport()); for (const StencilFace face : {StencilFace::Front, StencilFace::Back}) { - const StencilFaceState& got = gPipeInputs.GetStencilState(face); + const StencilFaceState& got = gPipeInputs->GetStencilState(face); const StencilFaceState& want = ctx.GetStencilState(face); EXPECT_EQ(std::memcmp(&got, &want, sizeof(StencilFaceState)), 0) << "stencil face " << static_cast(face); } for (SizeT i = 0; i < static_cast(CapabilityInput::CapabilityInputCount); ++i) { const CapabilityInput cap = static_cast(i); - EXPECT_EQ(gPipeInputs.IsCapabilityEnabled(cap), ctx.IsCapabilityEnabled(cap)) << "capability " << i; + EXPECT_EQ(gPipeInputs->IsCapabilityEnabled(cap), ctx.IsCapabilityEnabled(cap)) << "capability " << i; } } @@ -214,7 +214,7 @@ namespace { // the only thing in the suite that covers them. void ExpectAssembledBlockIsTheLiveBlock(GLContext& ctx, const char* tag) { SCOPED_TRACE(tag); - EXPECT_EQ(std::memcmp(&gPipeInputs.GetRenderStateParameters(), &ctx.GetRenderStateParameters(), + EXPECT_EQ(std::memcmp(&gPipeInputs->GetRenderStateParameters(), &ctx.GetRenderStateParameters(), sizeof(RenderStateParameters)), 0) << "the assembled working block is not byte-identical to the live one - a chunk of " @@ -554,7 +554,7 @@ namespace { // restored on the way out so the case stays independent (SanityTest's idiom). struct ContextGuard { SharedPtr Previous; - ContextGuard() : Previous(Move(MG_State::pGLContext)) { + ContextGuard() : Previous(MG_State::pGLContext.Take()) { MG_State::pGLContext = MakeUnique(); MGPipeApplierReset(); } @@ -653,7 +653,7 @@ namespace { // The vacuity guard: the block still holds what the fill copied out of the DEFAULT // context, so it must currently DISAGREE with the live one. If this ever passes, the // comparisons below would be checking the filler against itself. - ASSERT_NE(gPipeInputs.GetLineWidth(), ctx.GetLineWidth()); + ASSERT_NE(gPipeInputs->GetLineWidth(), ctx.GetLineWidth()); applyWholeBlock(); @@ -667,7 +667,7 @@ namespace { // would hand the backends a 63-wide rectangle where 64 was asked for. The literal // is std::lround's answer - round half AWAY FROM ZERO, so 1.5 -> 2 and 2.5 -> 3, // not the banker's rounding a nearbyint() transcription would give. - EXPECT_EQ(gPipeInputs.GetViewport(), IntVec4(2, 3, 64, 32)); + EXPECT_EQ(gPipeInputs->GetViewport(), IntVec4(2, 3, 64, 32)); } // phase 1, kDraw // Phase 2, kClear: the three clear values. The verb's own fill runs FIRST and copies @@ -678,13 +678,13 @@ namespace { ctx.SetClearColor(FloatVec4(0.9f, 0.8f, 0.7f, 0.6f)); ctx.SetClearDepth(0.125f); ctx.SetClearStencil(21); - ASSERT_NE(gPipeInputs.GetClearDepth(), ctx.GetClearDepth()); + ASSERT_NE(gPipeInputs->GetClearDepth(), ctx.GetClearDepth()); applyWholeBlock(); - EXPECT_EQ(gPipeInputs.GetClearColor(), ctx.GetClearColor()); - EXPECT_EQ(gPipeInputs.GetClearDepth(), ctx.GetClearDepth()); - EXPECT_EQ(gPipeInputs.GetClearStencil(), ctx.GetClearStencil()); + EXPECT_EQ(gPipeInputs->GetClearColor(), ctx.GetClearColor()); + EXPECT_EQ(gPipeInputs->GetClearDepth(), ctx.GetClearDepth()); + EXPECT_EQ(gPipeInputs->GetClearStencil(), ctx.GetClearStencil()); } // Phase 3, kReadback: GetClampReadColor, the one derived field no draw and no clear @@ -692,12 +692,12 @@ namespace { { MG_Test::ScopedPipeVerb verb(MGPipeVerb::ReadPixels); ctx.SetClampReadColor(GL_FALSE); - ASSERT_NE(gPipeInputs.GetClampReadColor(), ctx.GetClampReadColor()); + ASSERT_NE(gPipeInputs->GetClampReadColor(), ctx.GetClampReadColor()); applyWholeBlock(); - EXPECT_EQ(gPipeInputs.GetClampReadColor(), ctx.GetClampReadColor()); - EXPECT_EQ(gPipeInputs.GetClampReadColor(), static_cast(GL_FALSE)); + EXPECT_EQ(gPipeInputs->GetClampReadColor(), ctx.GetClampReadColor()); + EXPECT_EQ(gPipeInputs->GetClampReadColor(), static_cast(GL_FALSE)); } } @@ -764,7 +764,7 @@ namespace { TEST(RenderStateSpans, IncrementalChunksKeepEveryDerivedFieldInStep) { struct ContextGuard { SharedPtr Previous; - ContextGuard() : Previous(Move(MG_State::pGLContext)) { + ContextGuard() : Previous(MG_State::pGLContext.Take()) { MG_State::pGLContext = MakeUnique(); MGPipeApplierReset(); } @@ -926,7 +926,7 @@ namespace { // idiom, and the same guard cases 3 and 5 declare inline). struct ApplierContextGuard { SharedPtr Previous; - ApplierContextGuard() : Previous(Move(MG_State::pGLContext)) { + ApplierContextGuard() : Previous(MG_State::pGLContext.Take()) { MG_State::pGLContext = MakeUnique(); MGPipeApplierReset(); } @@ -1122,7 +1122,7 @@ namespace { pack.Pack.SkipRows = 5; pack.Pack.SwapBytes = true; MGPipeApplySetPixelPackState(pack); - const PixelStoreParameters got = gPipeInputs.GetPixelStoreParameters(false); + const PixelStoreParameters got = gPipeInputs->GetPixelStoreParameters(false); EXPECT_EQ(got.Alignment, 8); EXPECT_EQ(got.RowLength, 37); EXPECT_EQ(got.SkipRows, 5); @@ -1155,13 +1155,13 @@ namespace { std::memcpy(tail[1].IntView, secondInt, sizeof(secondInt)); MGPipeApplySetVertexAttribDefaults(hdr, tail); - EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[0], 1.5f); - EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[3], 4.5f); - EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(9).floatValue[2], 0.5f); + EXPECT_EQ(gPipeInputs->GetCurrentVertexAttribute(2).floatValue[0], 1.5f); + EXPECT_EQ(gPipeInputs->GetCurrentVertexAttribute(2).floatValue[3], 4.5f); + EXPECT_EQ(gPipeInputs->GetCurrentVertexAttribute(9).floatValue[2], 0.5f); // ... and the CONVERTED views are the record's, not a memcpy of the float bits: // 1.5f's bits are 0x3FC00000, and the frontend's int view of it is 1. - EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).intValue[0], 1); - EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(9).intValue[0], -1); + EXPECT_EQ(gPipeInputs->GetCurrentVertexAttribute(2).intValue[0], 1); + EXPECT_EQ(gPipeInputs->GetCurrentVertexAttribute(9).intValue[0], -1); } // delete_render_state: the record stops being live and a bound handle stops being diff --git a/MobileGL/MG_Test/Pipe/ResourceEmitTest.cpp b/MobileGL/MG_Test/Pipe/ResourceEmitTest.cpp index b6ad9d32..63fb0221 100644 --- a/MobileGL/MG_Test/Pipe/ResourceEmitTest.cpp +++ b/MobileGL/MG_Test/Pipe/ResourceEmitTest.cpp @@ -1807,7 +1807,7 @@ namespace { m_previousPush = MG_Config::Features.PipePush; MG_Config::Features.PipePush |= kMGPipeSubsystemResources; MGPipeSetResourceOps(&m_ops); - m_previousContext = Move(MG_State::pGLContext); + m_previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); } ~PushArm() { diff --git a/MobileGL/MG_Test/Pipe/TextureEmitTest.cpp b/MobileGL/MG_Test/Pipe/TextureEmitTest.cpp index abd5a1a5..c4195b5b 100644 --- a/MobileGL/MG_Test/Pipe/TextureEmitTest.cpp +++ b/MobileGL/MG_Test/Pipe/TextureEmitTest.cpp @@ -231,7 +231,7 @@ namespace { MG_Config::Features.PipePush |= kMGPipeSubsystemResources | kMGPipeSubsystemTextureResources | kMGPipeSubsystemSamplers; - m_previousContext = Move(MG_State::pGLContext); + m_previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MGPipeTextureEmitterInstance().ResetForTest(); // AND THE APPLIER IS A PROCESS SINGLETON, so its object records outlive a case. With diff --git a/MobileGL/MG_Test/Pipe/TrackerTest.cpp b/MobileGL/MG_Test/Pipe/TrackerTest.cpp index a4f482f5..dea038de 100644 --- a/MobileGL/MG_Test/Pipe/TrackerTest.cpp +++ b/MobileGL/MG_Test/Pipe/TrackerTest.cpp @@ -58,7 +58,7 @@ namespace { class TrackerAggregates : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); } void TearDown() override { MG_State::pGLContext = Move(m_previous); } @@ -174,7 +174,7 @@ namespace { } TEST_F(TrackerAggregates, ANoteWithoutALiveContextIsANoOp) { - SharedPtr held = Move(MG_State::pGLContext); + SharedPtr held = MG_State::pGLContext.Take(); MGP_NOTE_AGGREGATE(BufferChange); // must not dereference a null context MG_State::pGLContext = Move(held); SUCCEED(); @@ -246,7 +246,7 @@ namespace { class TrackerWalk : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); m_savedPush = MG_Config::Features.PipePush; ResetTheServerSideSingletons(); @@ -904,7 +904,7 @@ namespace { class TrackerAttribPayload : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); } void TearDown() override { MG_State::pGLContext = Move(m_previous); } @@ -993,7 +993,7 @@ namespace { class TrackerShippedEmitter : public ::testing::Test { protected: void SetUp() override { - m_previous = Move(MG_State::pGLContext); + m_previous = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); m_savedPush = MG_Config::Features.PipePush; MG_Config::Features.PipePush = kMGPipeSubsystemsMigratedAtP2; @@ -1166,7 +1166,7 @@ namespace { // that the capability itself reaches the applier's assembled block on the next draw. TEST_F(TrackerShippedEmitter, AClipDistanceEnableReArmsTheResidualBlock) { Draw(); - ASSERT_FALSE(MobileGL::MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::ClipDistance0)) + ASSERT_FALSE(MobileGL::MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::ClipDistance0)) << "the premise is gone: a fresh context already has clip distance 0 enabled"; Ctx().SetCapability(CapabilityInput::ClipDistance0, true); @@ -1177,7 +1177,7 @@ namespace { << "the premise is gone: a clip-distance enable now moves the pipeline version"; EXPECT_EQ(static_cast(Ctx().GetPipelineStateVersion()), pipelineBefore); - EXPECT_TRUE(MobileGL::MG_Pipe::gPipeInputs.IsCapabilityEnabled(CapabilityInput::ClipDistance0)) + EXPECT_TRUE(MobileGL::MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::ClipDistance0)) << "a capability change that moves only m_version never reached the applier's block"; } @@ -1295,7 +1295,7 @@ namespace { // stand into the next verb. A draw with no context is a no-op; its argument must not // outlive it. MGPipeSetPendingBaseInstance(11); - SharedPtr parked = Move(MG_State::pGLContext); + SharedPtr parked = MG_State::pGLContext.Take(); Draw(); EXPECT_EQ(MGPipePendingBaseInstance(), 0u) << "the no-live-context exit left the draw's base instance standing for the next verb"; diff --git a/MobileGL/MG_Test/Pipe/VertexInputEmitTest.cpp b/MobileGL/MG_Test/Pipe/VertexInputEmitTest.cpp index a8958d56..fd4cdf18 100644 --- a/MobileGL/MG_Test/Pipe/VertexInputEmitTest.cpp +++ b/MobileGL/MG_Test/Pipe/VertexInputEmitTest.cpp @@ -132,7 +132,7 @@ namespace { // case out of the gate's reach. struct EmitterScope { EmitterScope() { - m_previousContext = Move(MG_State::pGLContext); + m_previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MGPipeVertexInputEmitterInstance().Reset(); MGPipeVertexInputEmitterInstance().ResetCounters(); diff --git a/MobileGL/MG_Test/SanityTest.cpp b/MobileGL/MG_Test/SanityTest.cpp index cd1c3387..5752cc1d 100644 --- a/MobileGL/MG_Test/SanityTest.cpp +++ b/MobileGL/MG_Test/SanityTest.cpp @@ -894,7 +894,7 @@ TEST(DirectVulkanSanity, AdvertisesSubgroupOnlyWhenVulkanReportsUsableSupport) { TEST(DirectVulkanSanity, CapabilityRefreshInvalidatesTheCachedCompileEnvironment) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); @@ -1006,7 +1006,7 @@ TEST(GetterSanity, ClampsMaxVertexAttribsToCurrentValueStorageCapacity) { TEST(GetterSanity, ReportsFragmentInterpolationLimitsForFloatAndIntegerQueries) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); @@ -1056,7 +1056,7 @@ TEST(GetterSanity, ReportsFragmentInterpolationLimitsForFloatAndIntegerQueries) TEST(GetterSanity, StorageAndUniformBufferOffsetAlignmentsAreSeparateLimits) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); @@ -1145,7 +1145,7 @@ TEST(GetterSanity, AtomicCounterQueriesMatchShaderCompilerLimits) { using namespace MobileGL; namespace Transpiler = MG_Util::ShaderTranspiler; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); MG_Backend::pActiveBackendObject = MakeUnique(MG_Backend::DynamicBackendParameters{}); @@ -1224,7 +1224,7 @@ void main() { TEST(GetterSanity, ComputeWorkGroupQueriesMatchShaderCompilerLimits) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); MG_Backend::pActiveBackendObject = MakeUnique(MG_Backend::DynamicBackendParameters{}); @@ -1305,7 +1305,7 @@ void main() { TEST(GetterSanity, EveryLimitWithABuiltinAgreesWithItsQuery) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); MG_Backend::pActiveBackendObject = @@ -1404,7 +1404,7 @@ TEST(GetterSanity, EveryLimitWithABuiltinAgreesWithItsQuery) { TEST(GetterSanity, MaxElementIndexIsTheFull32BitIndexCeiling) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); MG_Backend::pActiveBackendObject = MakeUnique(MG_Backend::DynamicBackendParameters{}); @@ -1431,7 +1431,7 @@ TEST(GetterSanity, MaxElementIndexIsTheFull32BitIndexCeiling) { TEST(GetterSanity, PerCategoryMultisampleCeilingsAreProbedRatherThanFlooredAtFour) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); @@ -1473,7 +1473,7 @@ TEST(GetterSanity, PerCategoryMultisampleCeilingsAreProbedRatherThanFlooredAtFou TEST(ShaderCompilerSanity, ArbCullDistanceIsUsableBelow450) { using namespace MobileGL; - auto previousContext = Move(MG_State::pGLContext); + auto previousContext = MG_State::pGLContext.Take(); auto previousBackend = Move(MG_Backend::pActiveBackendObject); MG_State::pGLContext = MakeUnique(); MG_Backend::pActiveBackendObject = MakeUnique(MG_Backend::DynamicBackendParameters{}); @@ -4579,7 +4579,7 @@ TEST(DirectGLESVertexInputDraw, TheAttributeWalkTakesItsBuffersFromTheRecordNotT // this case exists to catch - gPipeInputs->GetBoundVertexArray()->GetAllAttributes() - has // anything to read at all; a free-standing object would make the revert crash instead of // disagree, which is a red for the wrong reason. - SharedPtr previousContext = Move(MG_State::pGLContext); + SharedPtr previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MG_State::pGLContext->CreateVertexArrayObject(1); MG_State::pGLContext->BindVertexArray(1); @@ -4650,7 +4650,7 @@ TEST(DirectGLESVertexInputDraw, TheIndexArmTakesItsBufferAndItsSerialFromTheReco // The frontend's element slot has moved to another buffer with nothing emitted, in a real // context for the reason the case above gives. - SharedPtr previousContext = Move(MG_State::pGLContext); + SharedPtr previousContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); MG_State::pGLContext->CreateVertexArrayObject(1); MG_State::pGLContext->BindVertexArray(1); diff --git a/MobileGL/MG_Test/State/ContextStateOwnershipTest.cpp b/MobileGL/MG_Test/State/ContextStateOwnershipTest.cpp index 1aa7e69f..8d54e6f1 100644 --- a/MobileGL/MG_Test/State/ContextStateOwnershipTest.cpp +++ b/MobileGL/MG_Test/State/ContextStateOwnershipTest.cpp @@ -222,7 +222,7 @@ TEST_F(ContextStateOwnershipTest, DestroyingOneContextLeavesTheOtherAlone) { TEST_F(ContextStateOwnershipTest, ReleasingAnEglContextRestoresTheThreadsPreviousGLState) { const auto contextA = NewContext(EGL_NO_CONTEXT); - const auto before = MG_State::pGLContext; + const auto before = MG_State::pGLContext.Shared(); ASSERT_NE(before, nullptr); MakeCurrent(contextA); @@ -234,7 +234,7 @@ TEST_F(ContextStateOwnershipTest, ReleasingAnEglContextRestoresTheThreadsPreviou } TEST_F(ContextStateOwnershipTest, AThreadWithoutACurrentContextUsesTheProcessDefaultContext) { - const auto processDefault = MG_State::pGLContext; + const auto processDefault = MG_State::pGLContext.Shared(); ASSERT_NE(processDefault, nullptr); EXPECT_EQ(processDefault, MG_State::ProcessDefaultGLContext()); diff --git a/MobileGL/MG_Test/Wire/PipeWireCodecTest.cpp b/MobileGL/MG_Test/Wire/PipeWireCodecTest.cpp index 4d8e3fd8..1739d36c 100644 --- a/MobileGL/MG_Test/Wire/PipeWireCodecTest.cpp +++ b/MobileGL/MG_Test/Wire/PipeWireCodecTest.cpp @@ -1469,19 +1469,19 @@ TEST_F(PipeWireCodecTest, SetContextValuesRoundTripsIntoPipeInputs) { // kReadback's class carries the two texture-unit counters, kDraw's the rest // (FillPoints.def) - the stamp is what publishes a RECORD-SUPPLIED field for the read. MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels); - EXPECT_EQ(gPipeInputs.GetActiveTextureUnit(), 9); - EXPECT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), 41); + EXPECT_EQ(gPipeInputs->GetActiveTextureUnit(), 9); + EXPECT_EQ(gPipeInputs->GetMaxTouchedTextureUnit(), 41); MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); for (Uint32 t = 0; t < 15; ++t) { - EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(static_cast(t)), + EXPECT_EQ(gPipeInputs->GetTouchedBufferBindingPointCount(static_cast(t)), SizeT{100 + t}) << "target " << t; } - EXPECT_TRUE(gPipeInputs.IsTransformFeedbackActive()); - EXPECT_TRUE(gPipeInputs.IsTransformFeedbackPaused()); - EXPECT_EQ(gPipeInputs.GetTransformFeedbackGeneration(), 0xA1A2A3A4A5A6A7A8ull); - EXPECT_EQ(gPipeInputs.GetBoundTransformFeedbackLifetimeId(), 0xB1B2B3B4B5B6B7B8ull); - EXPECT_EQ(gPipeInputs.GetTransformFeedbackCapturedVertices(), 0xC1C2C3C4C5C6C7C8ull); + EXPECT_TRUE(gPipeInputs->IsTransformFeedbackActive()); + EXPECT_TRUE(gPipeInputs->IsTransformFeedbackPaused()); + EXPECT_EQ(gPipeInputs->GetTransformFeedbackGeneration(), 0xA1A2A3A4A5A6A7A8ull); + EXPECT_EQ(gPipeInputs->GetBoundTransformFeedbackLifetimeId(), 0xB1B2B3B4B5B6B7B8ull); + EXPECT_EQ(gPipeInputs->GetTransformFeedbackCapturedVertices(), 0xC1C2C3C4C5C6C7C8ull); MGPipeServerClearVerbBoundary(); } diff --git a/MobileGL/MG_Test/Wire/ServerLoopTest.cpp b/MobileGL/MG_Test/Wire/ServerLoopTest.cpp index a8e6c173..22e5d101 100644 --- a/MobileGL/MG_Test/Wire/ServerLoopTest.cpp +++ b/MobileGL/MG_Test/Wire/ServerLoopTest.cpp @@ -816,21 +816,21 @@ TEST(ServerLoopTest, AClearRecordCrossesAndIsStampedAsAVerbBoundary) { ASSERT_TRUE(fixture.StartLoop()); // The pre-state is the honest one: nothing has stamped yet in this process. - ASSERT_NE(MG_Pipe::gPipeInputs.CurrentVerb(), MG_Pipe::MGPipeVerb::Clear); + ASSERT_NE(MG_Pipe::gPipeInputs->CurrentVerb(), MG_Pipe::MGPipeVerb::Clear); const MG_Pipe::MGPClear clear = WholeFramebufferClear(); ASSERT_TRUE(fixture.EmitAndWait(MG_Pipe::MGPWireOp::Clear, &clear, sizeof(clear))); Server::ServerLoop& loop = Server::ServerLoopInstance(); EXPECT_EQ(loop.DrainedRecords(), 1u); - EXPECT_EQ(MG_Pipe::gPipeInputs.CurrentVerb(), MG_Pipe::MGPipeVerb::Clear) + EXPECT_EQ(MG_Pipe::gPipeInputs->CurrentVerb(), MG_Pipe::MGPipeVerb::Clear) << "PipeApplier::StampVerbBoundary did not run, so every server-side PipeInputs read " "would abort on the first field inside SyncRenderState"; // MANDATORY on leaving the applier (p1's M-5): without it a SPAWNED server latches the flag // for its whole life, every later read is judged against the last verb's mask, and the // sticky forwards start aborting under strict on the very case their exemption exists for. - EXPECT_FALSE(MG_Pipe::gPipeInputs.ServerStampedVerb()) + EXPECT_FALSE(MG_Pipe::gPipeInputs->ServerStampedVerb()) << "MGPipeServerClearVerbBoundary was not called when the apply thread left the applier"; // No backend object in this process, so the five class-B verbs DECLINE. Asserted rather @@ -1629,7 +1629,7 @@ namespace { // Empty on success, else the step that failed - the harness's SkipReason shape. std::string BringUp() { PinHeadlessEglEnvironment(); - savedContext = Move(MG_State::pGLContext); + savedContext = MG_State::pGLContext.Take(); MG_State::pGLContext = MakeUnique(); Server::ServerLoop& loop = Server::ServerLoopInstance(); // InitSplitRoles step 1: the server's private backend, no GL and no EGL yet; its @@ -1944,13 +1944,13 @@ TEST(ServerLoopEglTest, ServerLivenessFollowsControlFramesAcrossReleaseAndRecrea MGL_EGL_BRING_UP_OR_BAIL(fixture); const auto live = [] { Bool answer = false; - EXPECT_EQ(OnApply([&] { answer = MG_Pipe::gPipeInputs.IsLive(); }), MOBILEGL_OK); + EXPECT_EQ(OnApply([&] { answer = MG_Pipe::gPipeInputs->IsLive(); }), MOBILEGL_OK); return answer; }; EXPECT_FALSE(live()) << "surface creation alone is not a served current context"; ASSERT_TRUE(fixture.MakeCurrent()); EXPECT_TRUE(live()); - auto client = Move(MG_State::pGLContext); + auto client = MG_State::pGLContext.Take(); EXPECT_TRUE(live()) << "server liveness must not consult the client GLContext"; MG_State::pGLContext = Move(client); ASSERT_TRUE(fixture.ReleaseCurrent()); @@ -2571,7 +2571,7 @@ TEST(ServerLoopTest, AnInstancedBaseVertexDrawRecordReachesTheSinkWithItsFieldsI EXPECT_EQ(seen.FirstRange.IndexBias, 5); EXPECT_FALSE(seen.HadUserIndices); EXPECT_FALSE(seen.HadIndirect); - EXPECT_FALSE(MG_Pipe::gPipeInputs.ServerStampedVerb()); + EXPECT_FALSE(MG_Pipe::gPipeInputs->ServerStampedVerb()); fixture.Stop(); } @@ -2714,7 +2714,7 @@ TEST(P5fReverseChannel, GlErrorsUseTheOwnedCallbackWithoutAResidualPull) { g_fvErrorCalls = 0; MG_Pipe::MGPipeResetResidualPullCountForTesting(); MG_Pipe::MGPipeServerStampVerbBoundary(MG_Pipe::MGPipeVerb::Clear); - MG_Pipe::gPipeInputs.RecordError(ErrorCode::InvalidOperation, + MG_Pipe::gPipeInputs->RecordError(ErrorCode::InvalidOperation, MakeUnique("fv", "draw", "driver message")); EXPECT_EQ(g_fvErrorCalls, 1u); EXPECT_EQ(g_fvErrorCode, static_cast(ErrorCode::InvalidOperation)); @@ -2780,7 +2780,7 @@ TEST(P5fReverseChannel, RecordErrorWithoutCallbackIsNamedFatal) { MG_Config::Ipc.StrictErrors = true; MG_Config::Ipc.RoleSplitState = true; MG_Pipe::gMGPipeCallbacks.OnGlError = nullptr; - MG_Pipe::gPipeInputs.RecordError(ErrorCode::InvalidOperation, nullptr); + MG_Pipe::gPipeInputs->RecordError(ErrorCode::InvalidOperation, nullptr); std::_Exit(9); }, ::testing::KilledBySignal(SIGABRT), ""); EXPECT_NE(ReadLog().find("OnGlError.callback-missing"), std::string::npos); @@ -2815,7 +2815,7 @@ TEST(P5fReverseChannel, GlErrorMessagesShareFifoWithOtherReverseEvents) { ASSERT_EQ(Server::ServerLoopInstance().RunProbeOnApplyThreadForTesting( +[](void*) -> MobileGLResult { MG_Pipe::MGPipeServerStampVerbBoundary(MG_Pipe::MGPipeVerb::Clear); - MG_Pipe::gPipeInputs.RecordError(ErrorCode::InvalidOperation, + MG_Pipe::gPipeInputs->RecordError(ErrorCode::InvalidOperation, MakeUnique("fv", "driver error")); const MG_Pipe::MGPRange whole{0, MG_Pipe::kMGPipeWholeBuffer}; MG_Pipe::gMGPipeCallbacks.OnGpuWritten({17, 3}, 1, &whole); @@ -3165,7 +3165,7 @@ namespace { const MG_Pipe::MGPDrawRange range{0, 3, 0}; if (!fixture.EmitAndWaitWithTail(MG_Pipe::MGPWireOp::DrawVbo, &info, sizeof(info), &range, sizeof(range))) ::_exit(65); - if (MG_Pipe::gPipeInputs.CurrentVerb() == MG_Pipe::MGPipeVerb::Clear) ::_exit(66); + if (MG_Pipe::gPipeInputs->CurrentVerb() == MG_Pipe::MGPipeVerb::Clear) ::_exit(66); // A Clear encoded legally and then SHORTENED in the ring before it is published - the // raw-record peer driver's move, in process: its header says 8 bytes, a header and no // MGPClear at all. @@ -3185,7 +3185,7 @@ namespace { Server::ServerLoop& loop = Server::ServerLoopInstance(); (void)PollUntil([&] { return !loop.Running(); }, 3000); int failed = 0; - if (MG_Pipe::gPipeInputs.CurrentVerb() == MG_Pipe::MGPipeVerb::Clear) failed |= kShortStamped; + if (MG_Pipe::gPipeInputs->CurrentVerb() == MG_Pipe::MGPipeVerb::Clear) failed |= kShortStamped; if (!Remote::SessionLatched() || std::strstr(Remote::SessionLatchedLine(), "\"record.Minimum\"") == nullptr) failed |= kShortWrongFault; if (loop.DrainedRecords() != 2) failed |= kShortDrained;