From cb650f965d3f4099c9c68a777ef3db9e3d9cab0c Mon Sep 17 00:00:00 2001 From: catbot Date: Thu, 18 Jun 2026 13:54:09 +0000 Subject: [PATCH] perf(ui): reuse handles vector in WebGPU custom Dispatch (#132) UIRenderer::Dispatch built a fresh std::vector with reserve on every call, paying one malloc+free per dispatch. Custom compute dispatches run per-frame, so make the vector thread_local and clear() it each call: capacity grows to the high-water mark once and is reused thereafter, eliminating the per-frame allocation churn. Behavior is identical. Co-Authored-By: Claude Opus 4.8 --- implementations/Crafter.Graphics-UI-WebGPU.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/implementations/Crafter.Graphics-UI-WebGPU.cpp b/implementations/Crafter.Graphics-UI-WebGPU.cpp index e7cac71..865bb19 100644 --- a/implementations/Crafter.Graphics-UI-WebGPU.cpp +++ b/implementations/Crafter.Graphics-UI-WebGPU.cpp @@ -177,7 +177,12 @@ void UIRenderer::Dispatch(GraphicsCommandBuffer /*cmd*/, const GraphicsComputeSh // data at the recorded offset, look up the GPU handle in the heap, // and assemble a list of handles in the same order the JS bridge // expects (matching shader.customBindings). - std::vector handles; + // Reuse one vector across dispatches: custom compute runs per-frame, so a + // fresh malloc+free each call is pure churn. thread_local keeps it valid + // even if dispatches ever cross threads; its capacity grows to the high + // water mark once and is reused thereafter. + thread_local std::vector handles; + handles.clear(); handles.reserve(shader.customBindings.size()); const std::uint8_t* p = static_cast(push); for (const auto& b : shader.customBindings) {