mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 08:38:30 +09:00
[Feat] (Pipe): mint render-state CSOs on the pipeline subset and send only the dynamic chunks that moved - the steady-state cost of the whole render-state family is now two Uint16 compares
- MG_Impl/Pipe/CsoCache.h: 64 entries, LRU, hash -> probe -> MEMCMP -> handle. The memcmp is not optional: a bare 64-bit hash equality would let a collision alias two different render states onto one CSO, which is silent wrong pixels with no gate that can see it, and Mesa's cso_cache memcmps for exactly that reason. It runs only when the pipeline version moved, so never in the steady state. Eviction emits delete_render_state and frees the client slot. - kMGPipeBehaviourNoCsoContentAddressing (bit 63) turns off the PROBE and the handle reuse, not the records: every pipeline-version change then mints, binds and evicts, which is the whole-block content addressing the design is measured against. - The validate point's step 3: bind_render_state when the pipeline version moved (12 bytes, no hashing, no blob when the cache hits), set_dynamic_state when m_version moved, carrying only the dynamic chunks that differ from the tracker's staging mirror. An EMPTY chunk mask still sends the 32-byte header, because the version is what Magma's dynamic tail gates on and it moved. - The residual fill now skips a field a P2 call supplies, driven by the generated kMGPipeFieldEmittedBy[] and gated per subsystem on the runtime MOBILEGL_PIPE_PUSH bitmask, so the bitmask is a true per-subsystem A/B. THE STAMP IS UNCHANGED: a stamp says "this verb published this field", which is as true of an emitted field as of a copied one, and withholding it would abort every backend read of the fields the migration just took over. - PipeStats::RecordDrawPayloadBytes has been implemented, unit-tested and called by nothing since P0. This is its first emitter. - A field that reaches PipeInputs only through MGPipeDeriveRenderStateFields is skipped only when that derivation is really there. It is package A's and is a declared stub on the p2/contract tag this branch starts from, so rather than hard-code which branch this is, the filler probes once: a sentinel in a scratch block, the mirror cleared, the derivation run, the answer latched. It stays useful after A lands - if the derivation is ever deleted the filler degrades to PULLING those fields rather than rendering a default. - integration-verify, 818 entries, green: the comparator re-reads every field from the live context at every backend read, so "the assembled block equals the live context" is now proven rather than asserted, and the entry compare has stopped being a tautology.
This commit is contained in:
@@ -186,6 +186,7 @@ namespace MobileGL::MG_Pipe {
|
||||
Reset();
|
||||
m_context = &ctx;
|
||||
}
|
||||
const Bool wasPrimed = m_primed;
|
||||
|
||||
Uint64 now[kMGPipeDirtyCount];
|
||||
const RenderStateParameters& render = ctx.GetRenderStateParameters();
|
||||
@@ -285,6 +286,7 @@ namespace MobileGL::MG_Pipe {
|
||||
}
|
||||
|
||||
m_primed = true;
|
||||
m_freshlyPrimed = !wasPrimed;
|
||||
m_lastDirty = dirty;
|
||||
|
||||
if (MG_Util::PipeStats::Enabled()) {
|
||||
@@ -308,9 +310,11 @@ namespace MobileGL::MG_Pipe {
|
||||
m_framebufferBind.Reset();
|
||||
m_pack = PixelStoreParameters{};
|
||||
m_patch = PatchTrio{};
|
||||
m_staged = RenderStateParameters{};
|
||||
m_context = nullptr;
|
||||
m_lastDirty = 0;
|
||||
m_primed = false;
|
||||
m_freshlyPrimed = false;
|
||||
}
|
||||
|
||||
void ResetCounters() {
|
||||
@@ -337,6 +341,16 @@ namespace MobileGL::MG_Pipe {
|
||||
|
||||
Uint32 LastDirty() const { return m_lastDirty; }
|
||||
Bool Primed() const { return m_primed; }
|
||||
// True when the LAST Update was the first one after a Reset - a fresh context, or a
|
||||
// server reset. The emission step reads it to send a COMPLETE state rather than an
|
||||
// increment against a staging mirror that describes a context that is gone.
|
||||
Bool FreshlyPrimed() const { return m_freshlyPrimed; }
|
||||
|
||||
// "What the server has" (P2 brief D8). set_dynamic_state sends the dynamic chunks
|
||||
// that differ from this, which is the chunk-level suppressor; a chunk that
|
||||
// memcmp-matches is not sent at all.
|
||||
RenderStateParameters& Staged() { return m_staged; }
|
||||
const RenderStateParameters& Staged() const { return m_staged; }
|
||||
|
||||
private:
|
||||
static constexpr SizeT Index(MGPipeDirty bit) { return static_cast<SizeT>(bit); }
|
||||
@@ -357,9 +371,12 @@ namespace MobileGL::MG_Pipe {
|
||||
PixelStoreParameters m_pack{};
|
||||
PatchTrio m_patch{};
|
||||
|
||||
RenderStateParameters m_staged{};
|
||||
|
||||
const void* m_context = nullptr;
|
||||
Uint32 m_lastDirty = 0;
|
||||
Bool m_primed = false;
|
||||
Bool m_freshlyPrimed = false;
|
||||
|
||||
Uint64 m_fires[kMGPipeDirtyCount][kMGPipeVerbClassCount]{};
|
||||
Uint64 m_walks[kMGPipeVerbClassCount]{};
|
||||
|
||||
Reference in New Issue
Block a user