[Perf] (MG_Pipe): the residual fill keeps unchanged object pins and a memoised vertex-buffer set keeps its hash (rd12 Espryt monolith +1%).

This commit is contained in:
2026-10-07 13:21:23 -04:00
parent 0cc54748f0
commit 8883e496bd
2 changed files with 28 additions and 5 deletions
+9 -4
View File
@@ -133,8 +133,11 @@ namespace MobileGL::MG_Pipe {
case F::GetBoundTransformFeedbackName:
dst.m_boundTransformFeedbackName = ctx.GetBoundTransformFeedbackName();
break;
// The four object pins: assigned only when the object moved, so the residual fill of
// every draw does not pay a reference-count increment and decrement for a pointer it
// already holds (P14: one of these moves per Minecraft draw, the other three rarely).
case F::GetBoundVertexArray:
dst.m_boundVertexArray = ctx.GetBoundVertexArray();
if (dst.m_boundVertexArray != ctx.GetBoundVertexArray()) dst.m_boundVertexArray = ctx.GetBoundVertexArray();
break;
case F::GetBufferBindingSlot:
// Every global target has a slot; Index stays null - GLContext resolves it
@@ -247,10 +250,11 @@ namespace MobileGL::MG_Pipe {
dst.m_primitiveRestartIndex = ctx.GetPrimitiveRestartIndex();
break;
case F::GetProgramForDispatch:
dst.m_programForDispatch = ctx.GetProgramForDispatch();
if (dst.m_programForDispatch != ctx.GetProgramForDispatch())
dst.m_programForDispatch = ctx.GetProgramForDispatch();
break;
case F::GetProgramForDraw:
dst.m_programForDraw = ctx.GetProgramForDraw();
if (dst.m_programForDraw != ctx.GetProgramForDraw()) dst.m_programForDraw = ctx.GetProgramForDraw();
break;
case F::GetProvokingVertexMode:
dst.m_provokingVertexMode = ctx.GetProvokingVertexMode();
@@ -291,7 +295,8 @@ namespace MobileGL::MG_Pipe {
dst.m_transformFeedbackPausedPrimitiveCounter = ctx.GetTransformFeedbackPausedPrimitiveCounter();
break;
case F::GetTransformFeedbackProgram:
dst.m_transformFeedbackProgram = ctx.GetTransformFeedbackProgram();
if (dst.m_transformFeedbackProgram != ctx.GetTransformFeedbackProgram())
dst.m_transformFeedbackProgram = ctx.GetTransformFeedbackProgram();
break;
case F::GetViewport:
dst.m_viewport = ctx.GetViewport();
+19 -1
View File
@@ -211,7 +211,9 @@ namespace MobileGL::MG_Pipe {
// a Minecraft frame binds hundreds of chunk VAOs. Not for client-memory arrays, whose
// entries the draw itself supplies.
VaoMemo* memo = vao && ownedClientBuffers == nullptr ? &MemoFor(*vao) : nullptr;
Bool memoHit = false;
if (memo != nullptr && memo->BuffersValid && memo->ConfigVersion == vao->GetConfigVersion()) {
memoHit = true;
count = memo->BufferCount;
for (SizeT i = 0; i < count; ++i) {
m_entries[i] = memo->Buffers[i];
@@ -251,6 +253,7 @@ namespace MobileGL::MG_Pipe {
if (attrib.Enabled && !attrib.Buffer) memoizable = false;
}
if (memo != nullptr) {
memo->HashValid = false;
memo->BuffersValid = memoizable && count <= kVaoMemoBuffers;
memo->ConfigVersion = vao->GetConfigVersion();
memo->BufferCount = count;
@@ -258,7 +261,19 @@ namespace MobileGL::MG_Pipe {
}
}
const Uint64 hash = MGPipeVertexBufferSetContentHash(m_entries.data(), 0, count, baseInstance);
// The set's hash is a function of the entries and the base instance, so a memoised set
// keeps the one it was hashed with for as long as the base instance is the same.
Uint64 hash = 0;
if (memoHit && memo->HashValid && memo->HashBaseInstance == baseInstance) {
hash = memo->Hash;
} else {
hash = MGPipeVertexBufferSetContentHash(m_entries.data(), 0, count, baseInstance);
if (memo != nullptr && memo->BuffersValid) {
memo->Hash = hash;
memo->HashBaseInstance = baseInstance;
memo->HashValid = true;
}
}
if (!MGPipeSetHashSuppressorInstance().ShouldEmit(MGPipeSuppressorSlot::SetVertexBuffers, hash)) {
return 0;
}
@@ -399,6 +414,9 @@ namespace MobileGL::MG_Pipe {
Bool BuffersValid = false;
Uint32 ConfigVersion = 0;
Uint32 BufferCount = 0;
Bool HashValid = false;
Uint32 HashBaseInstance = 0;
Uint64 Hash = 0;
Array<MGPVertexBuffer, kVaoMemoBuffers> Buffers{};
};
VaoMemo& MemoFor(const VertexArrayObject& vao) {