[Perf] (MG_State, MG_Backend): stop glViewport from evicting a cached VkPipeline

RenderState kept one version counter for all render state, and DirectVulkan read
it in three places: the pipeline memo key, the SetupDrawSnapshot fast-path guard,
and that guard's store. So glViewport, glScissor, glBlendColor, glStencilMask,
glClearColor, glPolygonOffset, glLineWidth and the point-size family - none of
which can alter a VkPipeline, all of which an application changes between draws -
knocked the next draw off both fast paths and made it rebuild a pipeline lookup
that was already correct.

The counter is now split. m_version still moves on every state change, because
the draw snapshot really does depend on all of it. m_pipelineStateVersion moves
only for the state a backend bakes into a pipeline object, and it is what the
three DirectVulkan sites read.

The exclusion list is the eight VkDynamicState entries PipelineFactory declares
plus the state that is not pipeline state at all (the clear values, hints, the
point-size family, clamp read colour, the primitive restart index). glStencilFunc
is the one setter that had to be split rather than classified: Func is in the
pipeline payload but Ref and ValueMask are dynamic state, so it bumps the
pipeline version only when Func actually changes.

Capabilities are deliberately NOT in the exclusion list even though several look
like dynamic state: GL_FRAMEBUFFER_SRGB feeds the render-pass hash, depth and
stencil test feed drawUsesDepthStencil, and scissor test, blend, cull face,
polygon offset fill, primitive restart, colour logic op and rasterizer discard
all feed the pipeline payload.

Two smaller draw-path wins ride along, both removing work whose answer was
already in hand. UploadAndBindVertexStreams searched all 32 VAO attribute slots
for the SharedPtr matching a binding's buffer key, once per binding per draw -
but VertexInputStateFactory writes bindingBufferKeys[b] and
bindingAttributeLocations[b] from the same loop iteration, one binding per
attribute with no merging, so the attribute at that location IS the buffer, by
construction. UploadAndBindIndexBuffer round-tripped the element-array buffer's
raw pointer back through the GL name table on every indexed draw, costing a map
lookup and an atomic refcount pair, when the binding slot's SharedPtr was already
in scope forty lines above - where a comment says exactly that about the vertex
path.

Behaviour-neutral by construction and verified as such: a 13355-case subset of
GL30-GL45 covering viewport, scissor, blend, stencil, depth, polygon offset,
clear, multisample, cull, logic op, line width and point state, plus the whole
direct_state_access suite, is identical before and after on both backends - in
the failure list and in the crashed-case set. direct_state_access stays at
Espryt 370/371 and Magma 371/371.
This commit is contained in:
BZLZHH
2026-08-05 12:49:54 -04:00
parent ba81ee114e
commit f3d52faad4
5 changed files with 70 additions and 44 deletions
+2
View File
@@ -159,6 +159,8 @@ namespace MobileGL {
// RenderState
Uint GetRenderStateParametersVersion() const;
// Only the pipeline-relevant subset - see RenderState::m_pipelineStateVersion.
Uint GetPipelineStateVersion() const;
const RenderStateParameters& GetRenderStateParameters() const;
void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height