perf(webgpu): byteCount-bounded readback for over-provisioned buffers (#133)
WebGPUBuffer::EnqueueReadback / PollReadback always copied the full buffer `size` GPU→staging→wasm. Over-provisioned event-queue buffers (e.g. Forts3D's GPU physics event drain) paid the full-capacity copy every drain even when only a small live prefix held data. Add an optional `byteCount` parameter (default 0 = whole buffer, so the existing full-buffer callers are unchanged) bounding the readback to the live prefix. Pass the same byteCount to the paired PollReadback so the matching number of bytes lands in `.value`. JS bridge: the staging buffer is now sized to the full device-buffer capacity (not the first call's byteSize) so a varying prefix length never overflows it, while the copyBufferToBuffer + mapAsync/getMappedRange are bounded to the requested prefix — that's where the copy saving lands. Verified end-to-end in the browser via RayQueryPick: the full readback still resolves correctly, and a follow-up 8-byte prefix read copies only hit+customIndex while primitiveIndex keeps its poison sentinel, proving the copy was bounded. Native `crafter-build test` suite: 24 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a4fdbf7d30
commit
931500ddc3
3 changed files with 64 additions and 17 deletions
|
|
@ -189,8 +189,17 @@ int main() {
|
|||
push.origin[2] = origin0 + float(kHitZ) * kSpacing;
|
||||
push.dir[0] = -1.0f; push.dir[1] = 0.0f; push.dir[2] = 0.0f;
|
||||
|
||||
// Drive byteCount-bounded prefix readback (issue #133) once the full read
|
||||
// has verified the hit: re-read ONLY the first 8 bytes (hit +
|
||||
// instanceCustomIndex) with byteCount=8 after poisoning the host mirror,
|
||||
// and confirm the two prefix fields land while primitiveIndex (bytes 8..11)
|
||||
// stays poisoned — i.e. the copy was actually bounded, not full-capacity.
|
||||
constexpr std::uint32_t kPoison = 0xEEEEEEEEu;
|
||||
constexpr std::uint32_t kPrefixLen = 2 * sizeof(std::uint32_t); // hit + customIndex
|
||||
|
||||
static int frame = 0;
|
||||
static bool dispatched = false;
|
||||
static bool prefixSent = false;
|
||||
static bool reported = false;
|
||||
EventListener<void> tick(&window.onBeforeUpdate, [&]() {
|
||||
if (reported) return;
|
||||
|
|
@ -199,7 +208,7 @@ int main() {
|
|||
pickShader.Dispatch(&push, sizeof(push), pickHandles, 1, 1, 1);
|
||||
pickBuf.EnqueueReadback();
|
||||
dispatched = true;
|
||||
} else if (dispatched && pickBuf.PollReadback()) {
|
||||
} else if (dispatched && !prefixSent && pickBuf.PollReadback()) {
|
||||
const PickResult& r = pickBuf.value[0];
|
||||
const bool ok = (r.hit == 1u) && (r.instanceCustomIndex == kExpectedCustomIndex);
|
||||
std::println("[RayQueryPick] result: hit={} customIndex={} prim={} t={}",
|
||||
|
|
@ -210,6 +219,20 @@ int main() {
|
|||
std::println("[RayQueryPick] FAIL — expected hit=1 customIndex={}, got hit={} customIndex={}",
|
||||
kExpectedCustomIndex, r.hit, r.instanceCustomIndex);
|
||||
}
|
||||
// Now kick off the bounded prefix re-read. Poison the whole mirror
|
||||
// first; the prefix poll must overwrite only bytes [0,8).
|
||||
pickBuf.value[0] = { kPoison, kPoison, kPoison, 0.0f };
|
||||
pickBuf.EnqueueReadback(/*resetBytes*/ 0, /*byteCount*/ kPrefixLen);
|
||||
prefixSent = true;
|
||||
} else if (prefixSent && pickBuf.PollReadback(/*byteCount*/ kPrefixLen)) {
|
||||
const PickResult& r = pickBuf.value[0];
|
||||
const bool prefixOk = (r.hit == 1u)
|
||||
&& (r.instanceCustomIndex == kExpectedCustomIndex)
|
||||
&& (r.primitiveIndex == kPoison); // tail untouched
|
||||
std::println("[RayQueryPick] prefix readback (byteCount={}): hit={} customIndex={} prim=0x{:08X}",
|
||||
kPrefixLen, r.hit, r.instanceCustomIndex, r.primitiveIndex);
|
||||
std::println("[RayQueryPick] {} — byteCount-bounded readback copied only the live prefix",
|
||||
prefixOk ? "PASS" : "FAIL");
|
||||
// The render loop runs after main's _Exit, where stdio is never
|
||||
// flushed implicitly — push the verdict out explicitly.
|
||||
std::fflush(stdout);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue