From a0004db9cb9b4aa9b96d538fbc9d8b65e1da04ee Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 19 Sep 2026 22:02:23 -0400 Subject: [PATCH] [MG_Pipe, MG_Test] (Disaggregated): P5f fe - derive scalar forwards and ratchet Espryt fatals --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 6 ++ MobileGL/MG_Impl/Pipe/PipeFill.cpp | 12 ++++ .../Harness/dualblock-expected-fatals.txt | 25 ++----- MobileGL/MG_Pipe/FieldOwnership.def | 18 ++--- .../MG_Pipe/generated/PipeFieldOwnership.inc | 68 +++++++++---------- MobileGL/MG_Remote/Server/PipeApplier.cpp | 12 ++-- MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp | 39 ++++++++++- 7 files changed, 111 insertions(+), 69 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index c1007520..ee0eb67d 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -1992,6 +1992,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // capture gap-free into scratch storage and place the records at End instead. xfb.scattered = false; xfb.scatterProgram.reset(); +#if MOBILEGL_BUILD_DISAGGREGATED + xfb.scatterArchive.reset(); +#endif xfb.scatterCapacityVertices = 0; if (program->NeedsScatteredTransformFeedbackCapture()) { SizeT capacityVertices = ~SizeT(0); @@ -2097,6 +2100,9 @@ namespace MobileGL::MG_Backend::DirectGLES { ScatterCapturedRecords(xfb); xfb.scattered = false; xfb.scatterProgram.reset(); +#if MOBILEGL_BUILD_DISAGGREGATED + xfb.scatterArchive.reset(); +#endif } else { ReadbackCapturedRanges(xfb.targets); } diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 53d99b40..e9f7931a 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -2117,6 +2117,18 @@ namespace MobileGL::MG_Pipe { #endif SizeT PipeInputs::GetBufferBindingPointCount(BufferTarget target) const { +#if MOBILEGL_BUILD_DISAGGREGATED + if (MG_Config::Transport != MG_Config::TransportMode::Monolith) { + switch (target) { + case BufferTarget::Uniform: + case BufferTarget::ShaderStorage: + case BufferTarget::AtomicCounter: + case BufferTarget::TransformFeedback: + return kMGPipeMaxBufferBindingPoints; + default: return 0; + } + } +#endif MGP_STICKY_FORWARD_PULL(GetBufferBindingPointCount); const auto* ctx = LiveContext(); return ctx != nullptr ? ctx->GetBufferBindingPointCount(target) : 0; diff --git a/MobileGL/MG_IntegrationTest/Harness/dualblock-expected-fatals.txt b/MobileGL/MG_IntegrationTest/Harness/dualblock-expected-fatals.txt index ad2e54fb..8790eb08 100644 --- a/MobileGL/MG_IntegrationTest/Harness/dualblock-expected-fatals.txt +++ b/MobileGL/MG_IntegrationTest/Harness/dualblock-expected-fatals.txt @@ -34,23 +34,10 @@ # a row advances those entries to their next one. See docs/Disaggregated/notes/p5f/f1-report.md. # --------------------------------------------------------------------------------------------- # -# Espryt's readback path reads the framebuffer binding slot out of the block (the field's -# Espryt half retired at P5e for the UNBARRIERED path only; the barriered readback pull is the -# residual). The largest block of the census by far. -# 132 entries -GetFramebufferBindingSlot@ReadPixels -# The XFB program check at draw setup (FieldOwnership.def: "P3b/P4b (Espryt), P7 (Magma)"). -# 11 entries (the TessellationXfbCapture / XfbCaptureBufferReuse family) -GetTransformFeedbackProgram@DrawArrays -# CopyImageSubData resolves both textures through the sticky forward (def: "P7"). -# 6 entries -GetTextureObject@CopyImageSubData -# Magma's Clear path (the two DirectVulkan.Split.NamedBlit entries) - fm's first rows. -# 2 entries +# P5f fe measured at 881e050e: 181 entries, 175 green, 4 skipped, 2 red. +# Espryt retired all five previous first-blocker pairs, and their downstream reads: +# READ FBO surface classification + reply-only PixelPack; copy destination arm ordering; +# copy-image endpoint handles; capture archive/ranges; storage-block program handle. +# The complete lane reached no new first-blocker pair (see fe-report.md). +# Magma's Clear path remains fm's independently owned pair (two NamedBlit entries). GetFramebufferBindingSlot@Clear -# CopyTexImage2D's texture-unit read (def: "P5e (Espryt unbarriered), P7 (Magma)"). -# 2 entries -GetTextureUnitObject@CopyTexImage2D -# The program-name validation sticky forward at ShaderStorageBlockBinding (def: "P9"). -# 2 entries -ValidateProgramName@ShaderStorageBlockBinding diff --git a/MobileGL/MG_Pipe/FieldOwnership.def b/MobileGL/MG_Pipe/FieldOwnership.def index 4c3bc75f..a0b3ce72 100644 --- a/MobileGL/MG_Pipe/FieldOwnership.def +++ b/MobileGL/MG_Pipe/FieldOwnership.def @@ -83,11 +83,11 @@ /* (:2995) is SELF-DECLARED monolith glue (DirectGLES.cpp:2961-2965) while BindCurrentFBO */ \ /* (:4303-4353) is already split-clean - the bind is migrated, the sync is not. */ \ X(GetFramebufferBindingSlot, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \ - "frontend BindingSlot pointer") \ + "P5f fe: Espryt reads framebuffer records; Magma retains frontend pointer debt") \ X(GetImageTextureBinding, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \ "frontend ImageTextureBinding base pointer") \ X(GetTextureUnitObject, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \ - "frontend TextureUnit base pointer; 13 Espryt + 8 Magma sites") \ + "P5f fe: Espryt transport readers retired; Magma retains texture-unit debt") \ /* DirectGLES.cpp:4497, PrepareForDraw, the second unconditional pointer read of every draw. */ \ X(GetProgramForDraw, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \ "frontend SharedPtr; the record carries a handle") \ @@ -104,7 +104,7 @@ /* case a field census taken from "what the scenario does" rather than from the mask would */ \ /* miss. The family's five VALUE rows rode set_context_values out of this list at P5c rv. */ \ X(GetTransformFeedbackProgram, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \ - "frontend SharedPtr") \ + "P5f fe: Espryt capture uses the Begin snapshot; Magma retains program debt") \ \ /* ---- APPLIER_DERIVED ---- */ \ /* THE FIRST ROW, and it is the one the contract asked P5 to split into two field ids. It is */ \ @@ -144,14 +144,14 @@ /* pair that disagrees. Their poison exemption (generated/PipeFilled.inc:422's sticky arm) */ \ /* is cancelled under split by the server stamp, which zeroes their FilledGen - and 0 loses */ \ /* to nothing, because :419's "never filled" test runs first. */ \ - X(GetBufferBindingPointCount, BARRIER_PULLED, "P7/P13", \ - "an argument-keyed lookup into the frontend's binding-point table") \ + X(GetBufferBindingPointCount, APPLIER_DERIVED, "-", \ + "P5f fe: server constant binding-point capacity, no frontend lookup") \ X(GetProgramObject, BARRIER_PULLED, "P9", \ "hands the backend a frontend SharedPtr keyed by GL name") \ X(GetTextureObject, BARRIER_PULLED, "P7", \ "hands the backend a frontend SharedPtr keyed by GL name") \ - X(HasOpenTransformFeedbackSpan, BARRIER_PULLED, "P7/P9", \ - "a lookup into frontend XFB span state keyed by lifetime id") \ + X(HasOpenTransformFeedbackSpan, APPLIER_DERIVED, "-", \ + "P5f fe: begin/end_stream_output maintain server spans by lifetime id") \ X(ValidateProgramName, BARRIER_PULLED, "P9", \ "a frontend name-table probe; Coverage.def calls it kClientResolved") \ /* P5c ev DELETED the forward under an active transport (CONTRACT-P5C section 4.2): */ \ @@ -176,13 +176,13 @@ // Mechanism is what replaces the forward, which is NOT the same question as which phase // retires the pull. #define MGP_FIELD_OWNERSHIP_FORWARD_LIST(X) \ - X(GetBufferBindingPointCount, BARRIER_PULLED, "P7/P13", \ + X(GetBufferBindingPointCount, APPLIER_DERIVED, "-", \ "a server-side binding-point table") \ X(GetProgramObject, BARRIER_PULLED, "P9", \ "a client-resolved program handle table (ARCHITECTURE 3.2 explicitly-not-ported)") \ X(GetTextureObject, BARRIER_PULLED, "P7", \ "a server-side texture handle table") \ - X(HasOpenTransformFeedbackSpan, BARRIER_PULLED, "P7/P9", \ + X(HasOpenTransformFeedbackSpan, APPLIER_DERIVED, "-", \ "server-side XFB span state") \ X(ValidateProgramName, BARRIER_PULLED, "P9", \ "a client-resolved program name probe") \ diff --git a/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc b/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc index 7d922734..af763391 100644 --- a/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc +++ b/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc @@ -42,7 +42,7 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou MGPipeFieldOwnership::kBarrierPulled, // GetBoundVertexArray MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingSlot MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPoint - MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount + MGPipeFieldOwnership::kApplierDerived, // GetBufferBindingPointCount MGPipeFieldOwnership::kRecordSupplied, // GetTouchedBufferBindingPointCount MGPipeFieldOwnership::kRecordSupplied, // GetClampReadColor MGPipeFieldOwnership::kRecordSupplied, // GetClearColor @@ -96,7 +96,7 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName MGPipeFieldOwnership::kBarrierPulled, // RecordError MGPipeFieldOwnership::kRecordSupplied, // GetBoundTransformFeedbackLifetimeId - MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan + MGPipeFieldOwnership::kApplierDerived, // HasOpenTransformFeedbackSpan }; // The ROADMAP phase whose row retires the pull. "-" for every class but BARRIER-PULLED. @@ -109,7 +109,7 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] = "P5e (Espryt unbarriered), P7 (Magma)", // GetBoundVertexArray "P8 (indirect), P9 (readback), P13 (transfer)", // GetBufferBindingSlot "P5e (Espryt unbarriered), P7 (Magma)", // GetBufferBindingPoint - "P7/P13", // GetBufferBindingPointCount + "-", // GetBufferBindingPointCount "-", // GetTouchedBufferBindingPointCount "-", // GetClampReadColor "-", // GetClearColor @@ -163,7 +163,7 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] = "P9", // ValidateProgramName "P9", // RecordError "-", // GetBoundTransformFeedbackLifetimeId - "P7/P9", // HasOpenTransformFeedbackSpan + "-", // HasOpenTransformFeedbackSpan }; // The seven sticky forwards, which are among the 63 above and need a row of their own: @@ -182,19 +182,19 @@ inline constexpr MGPipeInputField kMGPipeFieldOwnershipForwardField[kMGPipeField MGPipeInputField::RecordError, }; inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnershipForward[kMGPipeFieldOwnershipForwardCount] = { - MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount + MGPipeFieldOwnership::kApplierDerived, // GetBufferBindingPointCount MGPipeFieldOwnership::kBarrierPulled, // GetProgramObject MGPipeFieldOwnership::kBarrierPulled, // GetTextureObject - MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan + MGPipeFieldOwnership::kApplierDerived, // HasOpenTransformFeedbackSpan MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName MGPipeFieldOwnership::kFatal, // InvalidateCompileEnv MGPipeFieldOwnership::kBarrierPulled, // RecordError }; inline constexpr const char* kMGPipeFieldOwnershipForwardMechanism[kMGPipeFieldOwnershipForwardCount] = { - "a server-side binding-point table", // GetBufferBindingPointCount, retires in P7/P13 + "a server-side binding-point table", // GetBufferBindingPointCount, retires in - "a client-resolved program handle table (ARCHITECTURE 3.2 explicitly-not-ported)", // GetProgramObject, retires in P9 "a server-side texture handle table", // GetTextureObject, retires in P7 - "server-side XFB span state", // HasOpenTransformFeedbackSpan, retires in P7/P9 + "server-side XFB span state", // HasOpenTransformFeedbackSpan, retires in - "a client-resolved program name probe", // ValidateProgramName, retires in P9 "DELETED under split by P5c ev; the re-arriving caps snapshot IS the invalidation (R-12)", // InvalidateCompileEnv, retires in - "OnGlError, the ordered reverse-channel error post (R-12); its ordering is P9's", // RecordError, retires in P9 @@ -323,7 +323,7 @@ inline constexpr SizeT kMGPipeVerbBoundaryExemptCount = 3; // wait. A verb with no stamp row admits nothing - the server stamps only MGP_VERB_OP_LIST's // ops, so no other verb can be the one a residual pull is reported against. inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = { - {{0x5808402000000140ull, 0x0000000000000000ull}}, // DrawArrays + {{0x1808402000000040ull, 0x0000000000000000ull}}, // DrawArrays {{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElements {{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElementsBaseVertex {{0x0000000000000000ull, 0x0000000000000000ull}}, // MultiDrawArrays @@ -343,7 +343,7 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = { {{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawArraysInstanced {{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElementsIndirect {{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawArraysIndirect - {{0x5800402000000100ull, 0x0000000000000000ull}}, // Clear + {{0x1800402000000000ull, 0x0000000000000000ull}}, // Clear {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferfi {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferfv {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferuiv @@ -352,27 +352,27 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = { {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferfi {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferiv {{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferuiv - {{0x5800402000000100ull, 0x0000000000000000ull}}, // BlitFramebuffer + {{0x1800402000000000ull, 0x0000000000000000ull}}, // BlitFramebuffer {{0x0000000000000000ull, 0x0000000000000000ull}}, // BlitNamedFramebuffer - {{0x5800c02000300180ull, 0x0000000000000000ull}}, // CopyTexImage2D + {{0x1800c02000300080ull, 0x0000000000000000ull}}, // CopyTexImage2D {{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyTexSubImage2D - {{0x5800c02000300180ull, 0x0000000000000000ull}}, // CopyImageSubData - {{0x5800c02000300180ull, 0x0000000000000000ull}}, // GenerateMipmap - {{0x5800c02000300140ull, 0x0000000000000000ull}}, // ReadPixels + {{0x1800c02000300080ull, 0x0000000000000000ull}}, // CopyImageSubData + {{0x1800c02000300080ull, 0x0000000000000000ull}}, // GenerateMipmap + {{0x1800c02000300040ull, 0x0000000000000000ull}}, // ReadPixels {{0x0000000000000000ull, 0x0000000000000000ull}}, // GetTexImage - {{0x5800c02000300140ull, 0x0000000000000000ull}}, // GetTextureImage - {{0x5800402000000140ull, 0x0000000000000000ull}}, // DispatchCompute + {{0x1800c02000300040ull, 0x0000000000000000ull}}, // GetTextureImage + {{0x1800402000000040ull, 0x0000000000000000ull}}, // DispatchCompute {{0x0000000000000000ull, 0x0000000000000000ull}}, // DispatchComputeIndirect - {{0x5800402000000100ull, 0x0000000000000000ull}}, // MemoryBarrier + {{0x1800402000000000ull, 0x0000000000000000ull}}, // MemoryBarrier {{0x0000000000000000ull, 0x0000000000000000ull}}, // MemoryBarrierByRegion - {{0x5800402000000100ull, 0x0000000000000000ull}}, // BindImageTexture + {{0x1800402000000000ull, 0x0000000000000000ull}}, // BindImageTexture {{0x0000000000000000ull, 0x0000000000000000ull}}, // GetIntegeri_v - {{0x5800c02000300100ull, 0x0000000000000000ull}}, // ShaderStorageBlockBinding - {{0x5800402000000100ull, 0x0000000000000000ull}}, // FenceSync - {{0x5800402000000100ull, 0x0000000000000000ull}}, // ClientWaitSync - {{0x5800402000000100ull, 0x0000000000000000ull}}, // WaitSync - {{0x5800402000000100ull, 0x0000000000000000ull}}, // DeleteSync - {{0x5800402000000100ull, 0x0000000000000000ull}}, // GetSyncStatus + {{0x1800c02000300000ull, 0x0000000000000000ull}}, // ShaderStorageBlockBinding + {{0x1800402000000000ull, 0x0000000000000000ull}}, // FenceSync + {{0x1800402000000000ull, 0x0000000000000000ull}}, // ClientWaitSync + {{0x1800402000000000ull, 0x0000000000000000ull}}, // WaitSync + {{0x1800402000000000ull, 0x0000000000000000ull}}, // DeleteSync + {{0x1800402000000000ull, 0x0000000000000000ull}}, // GetSyncStatus {{0x0000000000000000ull, 0x0000000000000000ull}}, // IsTimerQuerySupported {{0x0000000000000000ull, 0x0000000000000000ull}}, // BeginTimeElapsedQuery {{0x0000000000000000ull, 0x0000000000000000ull}}, // EndTimeElapsedQuery @@ -384,17 +384,17 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = { {{0x0000000000000000ull, 0x0000000000000000ull}}, // EndOcclusionQuery {{0x0000000000000000ull, 0x0000000000000000ull}}, // BeginXfbPrimitivesQuery {{0x0000000000000000ull, 0x0000000000000000ull}}, // EndXfbPrimitivesQuery - {{0x5800402000000100ull, 0x0000000000000000ull}}, // PatchParameteri - {{0x5808402000000180ull, 0x0000000000000000ull}}, // BeginTransformFeedback - {{0x5808402000000180ull, 0x0000000000000000ull}}, // EndTransformFeedback - {{0x5808402000000180ull, 0x0000000000000000ull}}, // PauseTransformFeedback - {{0x5808402000000180ull, 0x0000000000000000ull}}, // ResumeTransformFeedback - {{0x5808402000000180ull, 0x0000000000000000ull}}, // BindTransformFeedback + {{0x1800402000000000ull, 0x0000000000000000ull}}, // PatchParameteri + {{0x1808402000000080ull, 0x0000000000000000ull}}, // BeginTransformFeedback + {{0x1808402000000080ull, 0x0000000000000000ull}}, // EndTransformFeedback + {{0x1808402000000080ull, 0x0000000000000000ull}}, // PauseTransformFeedback + {{0x1808402000000080ull, 0x0000000000000000ull}}, // ResumeTransformFeedback + {{0x1808402000000080ull, 0x0000000000000000ull}}, // BindTransformFeedback {{0x0000000000000000ull, 0x0000000000000000ull}}, // DeleteTransformFeedback {{0x0000000000000000ull, 0x0000000000000000ull}}, // GetGpuTimestampNs }; -inline constexpr SizeT kMGPipeAdmittedPullPairCount = 174; +inline constexpr SizeT kMGPipeAdmittedPullPairCount = 128; // THE PREDICATE THE STRICT KNOB ASKS (ID-117). A 69 x 128-bit table, so this costs a shift and // a test on the apply thread - the same shape MGPipeFieldMaskHas already has. @@ -428,7 +428,7 @@ static_assert(MGPipeEveryAdmittedPullIsADebtOfItsVerbsClass(), // The class sizes, as constants a test can pin without recounting the table. inline constexpr SizeT kMGPipeRecordSuppliedFieldCount = 41; -inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 4; -inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 15; +inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 6; +inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 13; inline constexpr SizeT kMGPipeFatalFieldCount = 3; static_assert(kMGPipeRecordSuppliedFieldCount + kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount == kMGPipeInputFieldCount, "the four class sizes do not partition the field set"); diff --git a/MobileGL/MG_Remote/Server/PipeApplier.cpp b/MobileGL/MG_Remote/Server/PipeApplier.cpp index 7f58bc33..28099e0f 100644 --- a/MobileGL/MG_Remote/Server/PipeApplier.cpp +++ b/MobileGL/MG_Remote/Server/PipeApplier.cpp @@ -946,6 +946,9 @@ namespace MobileGL::MG_Remote::Server { // crash or as a silent success. Contract §2 t2 says so for PatchParameteri by name. Bool ServerVerbSink::OnBeginStreamOutput(const MG_Pipe::MGPStreamOutputBegin& begin) { + auto& state = MG_Pipe::MGPipeApplier(); + state.BoundStreamOutputLifetimeId = begin.LifetimeId; + state.StreamOutputSpans[begin.LifetimeId] = begin; const MG_Backend::GlobalBackendFunctionsTable* table = Table("begin_stream_output"); if (table == nullptr) return false; if (table->GL.BeginTransformFeedback == nullptr) return false; @@ -955,9 +958,6 @@ namespace MobileGL::MG_Remote::Server { // the buffer bindings are read through the pulls. So this record's effect is not // visible until a DRAW crosses - which is why an XFB scenario whose draw is still class // C moves its first blocker to that draw rather than rendering. - auto& state = MG_Pipe::MGPipeApplier(); - state.BoundStreamOutputLifetimeId = begin.LifetimeId; - state.StreamOutputSpans[begin.LifetimeId] = begin; table->GL.BeginTransformFeedback(static_cast(begin.PrimitiveMode)); ++m_streamOutputSpans; return true; @@ -966,7 +966,11 @@ namespace MobileGL::MG_Remote::Server { Bool ServerVerbSink::OnEndStreamOutput(const MG_Pipe::MGPXfbAccounting& accounting) { const MG_Backend::GlobalBackendFunctionsTable* table = Table("end_stream_output"); if (table == nullptr) return false; - if (table->GL.EndTransformFeedback == nullptr) return false; + if (table->GL.EndTransformFeedback == nullptr) { + auto& state = MG_Pipe::MGPipeApplier(); + state.StreamOutputSpans.erase(state.BoundStreamOutputLifetimeId); + return false; + } // THE THREE ACCOUNTING FIELDS ARE NOT READ, AND THAT IS THE RULING RATHER THAN AN // OMISSION. glEndTransformFeedback takes no arguments; the numbers are the CLIENT's own // per-span accounting (contract §2 t2's companions row) and the client is where they are diff --git a/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp b/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp index aabd719d..028162bf 100644 --- a/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp +++ b/MobileGL/MG_Test/Pipe/FieldOwnershipTest.cpp @@ -263,10 +263,8 @@ TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) { // (CONTRACT-P5C.md §7 table 2) - and the only other BARRIER-PULLED rows are six of the // seven sticky forwards (the seventh, InvalidateCompileEnv, is FATAL since P5c ev). const MGPipeInputField pulledSticky[] = { - MGPipeInputField::GetBufferBindingPointCount, MGPipeInputField::GetProgramObject, MGPipeInputField::GetTextureObject, - MGPipeInputField::HasOpenTransformFeedbackSpan, MGPipeInputField::ValidateProgramName, MGPipeInputField::RecordError, }; @@ -281,7 +279,7 @@ TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) { EXPECT_TRUE(named) << kMGPipeInputFieldNames[i] << " is BARRIER-PULLED and not in the pinned object-class list"; } - EXPECT_EQ(pulledCount, 15u) << "9 non-sticky object rows + 6 sticky forwards"; + EXPECT_EQ(pulledCount, 13u) << "9 non-sticky object rows + 4 sticky forwards"; EXPECT_EQ(pulledCount, kMGPipeBarrierPulledFieldCount); EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters), MGPipeFieldOwnership::kApplierDerived); @@ -899,6 +897,41 @@ namespace { }; } // namespace +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(MGPipeFieldOwnershipOf(MGPipeInputField::GetBufferBindingPointCount), + MGPipeFieldOwnership::kApplierDerived); + MGPipeServerClearVerbBoundary(); +} + +TEST_F(FieldOwnershipTest, SplitOpenSpansAreOwnedByTheApplierAndSurviveOtherBindings) { + RoleSplitArm guard; + guard.Arm(true); + auto& state = MGPipeApplier(); + state.StreamOutputSpans.clear(); + MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays); + 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)); + state.StreamOutputSpans.erase(12); + EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(11)); + EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(12)); + EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::HasOpenTransformFeedbackSpan), + MGPipeFieldOwnership::kApplierDerived); + state.StreamOutputSpans.clear(); + state.BoundStreamOutputLifetimeId = 0; + MGPipeServerClearVerbBoundary(); +} + TEST_F(FieldOwnershipTest, RoleSplitOffFoldsTheFillSideOntoTheSharedBlock) { EXPECT_FALSE(MGPipeRoleSplitActive()); EXPECT_EQ(&MGPipeClientInputs(), &gPipeInputs);