From 786de6f7c88900c7a6dc222a5bbcc6a743055f70 Mon Sep 17 00:00:00 2001 From: John Owens Date: Wed, 9 Oct 2024 09:44:13 -0700 Subject: [PATCH] using original timing code, has a lot of debug code --- membw.html | 264 +++++++++++++------------- webgpufundamentals-timing-original.js | 115 +++++++++++ 2 files changed, 252 insertions(+), 127 deletions(-) create mode 100644 webgpufundamentals-timing-original.js diff --git a/membw.html b/membw.html index fe1be43..40fb078 100644 --- a/membw.html +++ b/membw.html @@ -8,7 +8,7 @@
- + diff --git a/webgpufundamentals-timing-original.js b/webgpufundamentals-timing-original.js new file mode 100644 index 0000000..61c11f3 --- /dev/null +++ b/webgpufundamentals-timing-original.js @@ -0,0 +1,115 @@ +function assert(cond, msg = "") { + if (!cond) { + throw new Error(msg); + } +} + +class TimingHelper { + #canTimestamp; + #device; + #querySet; + #resolveBuffer; + #resultBuffer; + #resultBuffers = []; + // state can be 'free', 'need resolve', 'wait for result' + #state = "free"; + + constructor(device) { + this.#device = device; + this.#canTimestamp = device.features.has("timestamp-query"); + if (this.#canTimestamp) { + this.#querySet = device.createQuerySet({ + type: "timestamp", + count: 2, + }); + this.#resolveBuffer = device.createBuffer({ + size: this.#querySet.count * 8, + usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC, + }); + } + } + + #beginTimestampPass(encoder, fnName, descriptor) { + if (this.#canTimestamp) { + assert(this.#state === "free", "state not free"); + this.#state = "need resolve"; + + const pass = encoder[fnName]({ + ...descriptor, + ...{ + timestampWrites: { + querySet: this.#querySet, + beginningOfPassWriteIndex: 0, + endOfPassWriteIndex: 1, + }, + }, + }); + + const resolve = () => this.#resolveTiming(encoder); + pass.end = (function (origFn) { + return function () { + origFn.call(this); + resolve(); + }; + })(pass.end); + + return pass; + } else { + return encoder[fnName](descriptor); + } + } + + beginRenderPass(encoder, descriptor = {}) { + return this.#beginTimestampPass(encoder, "beginRenderPass", descriptor); + } + + beginComputePass(encoder, descriptor = {}) { + return this.#beginTimestampPass(encoder, "beginComputePass", descriptor); + } + + #resolveTiming(encoder) { + if (!this.#canTimestamp) { + return; + } + assert(this.#state === "need resolve", "must call addTimestampToPass"); + this.#state = "wait for result"; + + this.#resultBuffer = + this.#resultBuffers.pop() || + this.#device.createBuffer({ + size: this.#resolveBuffer.size, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, + }); + + encoder.resolveQuerySet( + this.#querySet, + 0, + this.#querySet.count, + this.#resolveBuffer, + 0 + ); + encoder.copyBufferToBuffer( + this.#resolveBuffer, + 0, + this.#resultBuffer, + 0, + this.#resultBuffer.size + ); + } + + async getResult() { + if (!this.#canTimestamp) { + return 0; + } + assert(this.#state === "wait for result", "must call resolveTiming"); + this.#state = "free"; + + const resultBuffer = this.#resultBuffer; + await resultBuffer.mapAsync(GPUMapMode.READ); + const times = new BigInt64Array(resultBuffer.getMappedRange()); + const duration = Number(times[1] - times[0]); + resultBuffer.unmap(); + this.#resultBuffers.push(resultBuffer); + return duration; + } +}