From db8484cbb95d098fbab0fe938c56695a78f83225 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 6 Oct 2026 22:17:16 -0400 Subject: [PATCH] [Fix] (P13 W8): the transport-less monolith sends set_context_values like the split build's does, and render-state padding is zeroed so equal states share one CSO. --- MobileGL/MG_Impl/Pipe/PipeFill.cpp | 7 ++++++- .../MG_State/GLState/RenderState/RenderState.cpp | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 35450b36..3fd0fa13 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -3555,7 +3555,12 @@ namespace MobileGL::MG_Pipe { ? MG_Remote::Client::ContextValuesWireLive() : MG_Config::RecordArmAliasesFrontend(); #else - constexpr Bool contextValuesWireLive = false; + // P13 W8: a library without a transport is ALWAYS monolith's record arm, so it takes the + // eight fields from the record exactly as the split build's monolith does. This branch + // used to answer a constant false - the pre-W5 pull shape - and left the shipped (FCL) + // build pulling them by residual fill while the split build's monolith carried them; the + // recorder goldens (MG_Test/Pipe/RecorderGoldenTest.cpp) found the two streams differ. + const Bool contextValuesWireLive = MG_Config::RecordArmAliasesFrontend(); #endif // AND THE SEVENTH IS P5eFamilyIsLive (ID-106), which is the same sentence for the // binding-point family and asks bit 13's OWN consumer bit rather than the resource diff --git a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp index 8f12820e..2ccfab72 100644 --- a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp +++ b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp @@ -6,6 +6,9 @@ // SPDX-License-Identifier: LGPL-3.0-only // End of Source File Header +#include +#include +#include #include "RenderState.h" #include #include "MG_Util/Debug/Log.h" @@ -35,6 +38,16 @@ namespace MobileGL { } // namespace RenderState::RenderState() { + // ZERO PADDING FIRST. The parameters' pipeline and dynamic chunks are pushed as + // bytes and content-addressed byte for byte (CsoCache's hash and memcmp), so the + // padding between members must not carry whatever the allocator left there: two + // contexts with equal state would otherwise mint two render-state CSOs, and the + // recorder goldens (MG_Test/Pipe/RecorderGoldenTest.cpp) would not be repeatable. + // Re-constructing in place keeps every default member initializer; the type is + // trivially destructible, so the first construction needs no destructor call. + static_assert(std::is_trivially_destructible_v); + std::memset(static_cast(&m_parameters), 0, sizeof(m_parameters)); + new (&m_parameters) RenderStateParameters(); // The color writemask defaults to all-true for every draw buffer. for (auto& mask : m_parameters.ColorMasks) { mask = BoolVec4(true, true, true, true);