@forgeax/engine-rhi-webgpu 0.1.21 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/README.md +11 -4
  2. package/dist/__tests__/r32float-capability-generation.integration.test.d.ts +2 -0
  3. package/dist/__tests__/r32float-capability-generation.integration.test.d.ts.map +1 -0
  4. package/dist/__tests__/r32float-format-capability.browser.test.d.ts +2 -0
  5. package/dist/__tests__/r32float-format-capability.browser.test.d.ts.map +1 -0
  6. package/dist/__tests__/r32float-format-capability.dawn.test.d.ts +2 -0
  7. package/dist/__tests__/r32float-format-capability.dawn.test.d.ts.map +1 -0
  8. package/dist/device.d.ts.map +1 -1
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.mjs +171 -3
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/internal/__tests__/timestamp-query.unit.test.d.ts +2 -0
  14. package/dist/internal/__tests__/timestamp-query.unit.test.d.ts.map +1 -0
  15. package/dist/internal/r32float-capability.d.ts +6 -0
  16. package/dist/internal/r32float-capability.d.ts.map +1 -0
  17. package/package.json +3 -3
  18. package/src/__tests__/dawn-real-gpu.dawn.test.ts +168 -0
  19. package/src/__tests__/r32float-capability-generation.integration.test.ts +35 -0
  20. package/src/__tests__/r32float-format-capability.browser.test.ts +22 -0
  21. package/src/__tests__/r32float-format-capability.dawn.test.ts +31 -0
  22. package/src/__tests__/rhi-webgpu.unit.test.ts +135 -0
  23. package/src/device.ts +27 -0
  24. package/src/index.ts +44 -3
  25. package/src/internal/__tests__/timestamp-query.unit.test.ts +120 -0
  26. package/src/internal/r32float-capability.ts +153 -0
  27. package/dist/.tsbuildinfo +0 -1
package/README.md CHANGED
@@ -51,13 +51,20 @@ Real-GPU integration is in [`src/__tests__/dawn-real-gpu.dawn.test.ts`](./src/__
51
51
 
52
52
  ## Timestamp write contract
53
53
 
54
+ Timestamp capture uses the WebGPU pass descriptor `timestampWrites` field on
55
+ `beginRenderPass` / `beginComputePass`. The shim maps the opaque ForgeaX
56
+ `QuerySet` to the native `GPUQuerySet` at the pass boundary. The obsolete
57
+ command-encoder `writeTimestamp` entry is intentionally not exposed: current
58
+ Dawn rejects that method even when `timestamp-query` is advertised. A device
59
+ without a usable timestamp period remains capability-negative and produces no
60
+ synthetic ticks.
54
61
  When `device.caps.timestampQuery` is true, render and compute pass descriptors
55
62
  carry the mapped query set and timestamp indices. The WebGPU adapter does not
56
63
  expose the removed command-encoder timestamp entry; callers that need an
57
64
  encoder-position marker use an empty timestamp-enabled compute pass on the same
58
- encoder. A marker failure is a structured `webgpu-runtime-error`; the
59
- shim never treats it as a no-op or synthesizes timestamp ticks. Capability-
60
- disabled devices retain the existing refusal path.
65
+ encoder. A marker failure is a structured `webgpu-runtime-error`; the shim
66
+ never treats it as a no-op or synthesizes timestamp ticks. Capability-disabled
67
+ devices retain the existing refusal path.
61
68
 
62
69
  ## Query forwarding contract
63
70
 
@@ -69,7 +76,7 @@ The shim forwards the query surface from [`@forgeax/engine-rhi`](../rhi):
69
76
  | `occlusionQuerySet` + `beginOcclusionQuery` / `endOcclusionQuery` | The pass owns the query-set state; missing set, out-of-range index, nested begin, and unmatched end produce structured errors | [`device.ts`](./src/device.ts#L542), [Dawn state/round-trip coverage](./src/__tests__/dawn-real-gpu.dawn.test.ts#L619) |
70
77
  | `resolveQuerySet` | Validates 256-byte destination alignment, `QUERY_RESOLVE` usage, range, and destination size before raw forwarding | [`device.ts`](./src/device.ts#L966), [Dawn coverage](./src/__tests__/dawn-real-gpu.dawn.test.ts#L820) |
71
78
  | Timestamp pass writes | `timestampWrites` maps opaque `QuerySet` handles to raw `GPUQuerySet`; a capability-negative device refuses creation and does not synthesize ticks | [`device.ts`](./src/device.ts#L745), [Dawn admission/readback coverage](./src/__tests__/dawn-real-gpu.dawn.test.ts#L1233) |
72
- | Command-encoder `writeTimestamp` | Capability-positive devices require a callable raw method; missing/throwing raw methods surface `webgpu-runtime-error` | [`device.ts`](./src/device.ts#L1048), [unit coverage](./src/__tests__/rhi-webgpu.unit.test.ts#L394) |
79
+ | Pass descriptor `timestampWrites` | Capability-positive devices map opaque query sets at the real render/compute pass boundary; unavailable periods remain fail-closed | [`device.ts`](./src/device.ts#L745), [unit coverage](./src/internal/__tests__/timestamp-query.unit.test.ts) |
73
80
  | `executeBundles` | Still unavailable: the public RHI has no constructible `RenderBundle` handle or creation path, so the shim returns `rhi-not-available` | [`device.ts`](./src/device.ts#L533) |
74
81
 
75
82
  > [!NOTE]
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=r32float-capability-generation.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r32float-capability-generation.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/r32float-capability-generation.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=r32float-format-capability.browser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r32float-format-capability.browser.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/r32float-format-capability.browser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=r32float-format-capability.dawn.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r32float-format-capability.dawn.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/r32float-format-capability.dawn.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAwBV,gBAAgB,EAIhB,SAAS,EAcV,MAAM,qBAAqB,CAAC;AA8L7B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAE/E;AA6qCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG;IACnD,MAAM,EAAE,SAAS,CAAC;IAClB;6CACyC;IACzC,GAAG,EAAE,SAAS,CAAC;CAChB,CA2aA;AA0BD;;iFAEiF;AACjF,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACvD,WAAW,IAAI,IAAI,CAAC;IACpB,gBAAgB,IAAI,sBAAsB,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,UAAU,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,oBAAoB,GAAG,gBAAgB,CAqGpF"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAwBV,gBAAgB,EAIhB,SAAS,EAcV,MAAM,qBAAqB,CAAC;AAqM7B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAE/E;AA6qCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG;IACnD,MAAM,EAAE,SAAS,CAAC;IAClB;6CACyC;IACzC,GAAG,EAAE,SAAS,CAAC;CAChB,CA+bA;AA0BD;;iFAEiF;AACjF,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACvD,WAAW,IAAI,IAAI,CAAC;IACpB,gBAAgB,IAAI,sBAAsB,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,UAAU,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,oBAAoB,GAAG,gBAAgB,CAqGpF"}
package/dist/index.d.ts CHANGED
@@ -13,8 +13,9 @@ import type { RequestAdapterOptions, Result, RhiAdapter, RhiCanvasContext, RhiDe
13
13
  export interface GpuLike {
14
14
  requestAdapter(options?: GPURequestAdapterOptions | undefined): Promise<GpuAdapterLike | null>;
15
15
  }
16
- /** The `GPUAdapter` subset accepted at the provider seam — only the `requestDevice` entry is consumed. */
16
+ /** The `GPUAdapter` subset accepted at the provider seam — capability limits plus `requestDevice`. */
17
17
  export interface GpuAdapterLike {
18
+ readonly limits?: GPUSupportedLimits | undefined;
18
19
  requestDevice(descriptor?: GPUDeviceDescriptor | undefined): Promise<GpuDeviceLike>;
19
20
  }
20
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { err, RhiError, ok } from '@forgeax/engine-rhi';
1
+ import { err, RhiError, ok, R32FLOAT_PROBE_STAGES, validateR32FloatReceipt, createUnavailableR32FloatReceipt } from '@forgeax/engine-rhi';
2
2
  export { RhiError as RhiErrorClass, err, ok } from '@forgeax/engine-rhi';
3
3
 
4
4
  // src/index.ts
@@ -108,6 +108,131 @@ function queueWriteBufferOutOfBounds(args) {
108
108
  })
109
109
  );
110
110
  }
111
+ var TEXTURE_BINDING = 4;
112
+ var STORAGE_BINDING = 8;
113
+ var COPY_SRC = 1;
114
+ var COPY_DST = 2;
115
+ var MAP_READ = 1;
116
+ var BUFFER_COPY_DST = 8;
117
+ async function probeR32FloatCapability(rawDevice, deviceGeneration) {
118
+ let stage = "texture-create";
119
+ let texture;
120
+ let readback;
121
+ rawDevice.pushErrorScope("validation");
122
+ try {
123
+ texture = rawDevice.createTexture({
124
+ size: { width: 2, height: 2, depthOrArrayLayers: 1 },
125
+ format: "r32float",
126
+ mipLevelCount: 2,
127
+ usage: TEXTURE_BINDING | STORAGE_BINDING | COPY_SRC | COPY_DST
128
+ });
129
+ stage = "mip-view";
130
+ const sourceView = texture.createView({ baseMipLevel: 0, mipLevelCount: 1 });
131
+ const destinationView = texture.createView({ baseMipLevel: 1, mipLevelCount: 1 });
132
+ stage = "sampled-storage-bind-group";
133
+ const layout = rawDevice.createBindGroupLayout({
134
+ entries: [
135
+ {
136
+ binding: 0,
137
+ visibility: 4,
138
+ texture: { sampleType: "unfilterable-float", viewDimension: "2d" }
139
+ },
140
+ {
141
+ binding: 1,
142
+ visibility: 4,
143
+ storageTexture: { access: "write-only", format: "r32float", viewDimension: "2d" }
144
+ }
145
+ ]
146
+ });
147
+ const bindGroup = rawDevice.createBindGroup({
148
+ layout,
149
+ entries: [
150
+ { binding: 0, resource: sourceView },
151
+ { binding: 1, resource: destinationView }
152
+ ]
153
+ });
154
+ stage = "pipeline-bind";
155
+ const shader = rawDevice.createShaderModule({
156
+ code: `
157
+ @group(0) @binding(0) var source: texture_2d<f32>;
158
+ @group(0) @binding(1) var destination: texture_storage_2d<r32float, write>;
159
+ @compute @workgroup_size(1) fn main() {
160
+ let value = textureLoad(source, vec2i(0, 0), 0).r;
161
+ textureStore(destination, vec2i(0, 0), vec4f(value));
162
+ }
163
+ `
164
+ });
165
+ const pipeline = rawDevice.createComputePipeline({
166
+ layout: rawDevice.createPipelineLayout({ bindGroupLayouts: [layout] }),
167
+ compute: { module: shader, entryPoint: "main" }
168
+ });
169
+ const encoder = rawDevice.createCommandEncoder({ label: "r32float-profile" });
170
+ const pass = encoder.beginComputePass();
171
+ pass.setPipeline(pipeline);
172
+ pass.setBindGroup(0, bindGroup);
173
+ pass.dispatchWorkgroups(1);
174
+ pass.end();
175
+ stage = "finish";
176
+ readback = rawDevice.createBuffer({ size: 256, usage: MAP_READ | BUFFER_COPY_DST });
177
+ encoder.copyTextureToBuffer(
178
+ { texture, mipLevel: 1 },
179
+ { buffer: readback, bytesPerRow: 256, rowsPerImage: 1 },
180
+ { width: 1, height: 1, depthOrArrayLayers: 1 }
181
+ );
182
+ const commandBuffer = encoder.finish();
183
+ stage = "submit";
184
+ rawDevice.queue.submit([commandBuffer]);
185
+ stage = "completion";
186
+ await rawDevice.queue.onSubmittedWorkDone();
187
+ const validationError = await rawDevice.popErrorScope();
188
+ if (validationError !== null) {
189
+ throw new Error(`WebGPU validation: ${validationError.message}`);
190
+ }
191
+ stage = "readback";
192
+ await readback.mapAsync(MAP_READ);
193
+ const values = Array.from(new Float32Array(readback.getMappedRange(0, 4).slice(0)));
194
+ readback.unmap();
195
+ const receipt = {
196
+ profile: "r32float-mip-sampled-storage",
197
+ verdict: "admitted",
198
+ evidence: "real",
199
+ deviceGeneration,
200
+ stages: R32FLOAT_PROBE_STAGES.map((entry) => ({
201
+ stage: entry,
202
+ verdict: "admitted",
203
+ evidence: "real"
204
+ })),
205
+ sampleType: "unfilterable-float",
206
+ usages: ["texture-binding", "storage-binding", "copy-src"],
207
+ readback: { byteLength: 4, values },
208
+ probeExecutions: 1
209
+ };
210
+ const validated = validateR32FloatReceipt(receipt);
211
+ return validated.ok ? ok(validated.value) : validated;
212
+ } catch (cause) {
213
+ const message = cause instanceof Error ? cause.message : String(cause);
214
+ createUnavailableR32FloatReceipt({
215
+ deviceGeneration,
216
+ failedStage: stage,
217
+ detail: message
218
+ });
219
+ return err(
220
+ new RhiError({
221
+ code: "rhi-texture-format-capability-unavailable",
222
+ expected: `r32float profile stage ${stage} to complete on the live WebGPU device`,
223
+ hint: "retain fallback-only rendering and inspect the device validation error",
224
+ detail: {
225
+ stage,
226
+ deviceGeneration,
227
+ reason: message
228
+ }
229
+ })
230
+ );
231
+ } finally {
232
+ texture?.destroy();
233
+ readback?.destroy();
234
+ }
235
+ }
111
236
  function resolveTimestampQueries(args) {
112
237
  try {
113
238
  args.rawEncoder.resolveQuerySet(
@@ -183,6 +308,9 @@ var CP_KEYS = ["label", "layout", "compute"];
183
308
  var QS_KEYS = ["label", "type", "count"];
184
309
  var QUERY_SET_COUNT_LIMIT = 4096;
185
310
  var RAW_DEVICE_MAP = /* @__PURE__ */ new WeakMap();
311
+ var RAW_DEVICE_GENERATION_MAP = /* @__PURE__ */ new WeakMap();
312
+ var R32FLOAT_PROBE_CACHE = /* @__PURE__ */ new WeakMap();
313
+ var NEXT_DEVICE_GENERATION = 1;
186
314
  var BUFFER_RAW_MAP = /* @__PURE__ */ new WeakMap();
187
315
  var TEXTURE_VIEW_RAW_MAP = /* @__PURE__ */ new WeakMap();
188
316
  var ENCODER_STATE = /* @__PURE__ */ new WeakMap();
@@ -1030,11 +1158,27 @@ function makeRhiDevice(rawDevice) {
1030
1158
  const features = rawDevice.features;
1031
1159
  const limits = rawDevice.limits;
1032
1160
  const queue = makeQueue(rawDevice.queue);
1161
+ const deviceGeneration = RAW_DEVICE_GENERATION_MAP.get(rawDevice) ?? (() => {
1162
+ const generation = NEXT_DEVICE_GENERATION++;
1163
+ RAW_DEVICE_GENERATION_MAP.set(rawDevice, generation);
1164
+ return generation;
1165
+ })();
1033
1166
  const device = {
1034
1167
  caps,
1035
1168
  features,
1036
1169
  limits,
1170
+ probeTextureFormatCapability() {
1171
+ const cached = R32FLOAT_PROBE_CACHE.get(device);
1172
+ if (cached !== void 0) return cached;
1173
+ const probe = probeR32FloatCapability(rawDevice, deviceGeneration);
1174
+ R32FLOAT_PROBE_CACHE.set(device, probe);
1175
+ return probe;
1176
+ },
1037
1177
  queue,
1178
+ // The raw backend owns the only real loss-injection seam. Keep this
1179
+ // Promise as a transparent observation boundary; a test provider must
1180
+ // operate on the backend before this shim and must never be added to the
1181
+ // public RHI surface.
1038
1182
  lost: rawDevice.lost,
1039
1183
  createBuffer(desc) {
1040
1184
  const out = rawDevice.createBuffer(
@@ -1570,6 +1714,28 @@ function translateErrorEventToRhiError(event) {
1570
1714
  }
1571
1715
 
1572
1716
  // src/index.ts
1717
+ var DYNAMIC_DEVICE_LIMIT_KEYS = [
1718
+ "maxDynamicUniformBuffersPerPipelineLayout",
1719
+ "maxDynamicStorageBuffersPerPipelineLayout"
1720
+ ];
1721
+ var SYNTHETIC_DAWN_DYNAMIC_LIMIT_DEFAULT = 1e6;
1722
+ function normalizeDeviceDescriptor(adapter, descriptor) {
1723
+ const adapterLimits = adapter.limits;
1724
+ if (adapterLimits === void 0 || adapterLimits === null) return descriptor;
1725
+ const requiredLimits = { ...descriptor?.requiredLimits ?? {} };
1726
+ let changed = false;
1727
+ for (const key of DYNAMIC_DEVICE_LIMIT_KEYS) {
1728
+ const value = adapterLimits[key];
1729
+ if (!Number.isFinite(value) || value < 1) continue;
1730
+ const requested = requiredLimits[key];
1731
+ if (requested !== void 0 && (requested <= value || requested !== SYNTHETIC_DAWN_DYNAMIC_LIMIT_DEFAULT)) {
1732
+ continue;
1733
+ }
1734
+ requiredLimits[key] = value;
1735
+ changed = true;
1736
+ }
1737
+ return changed ? { ...descriptor ?? {}, requiredLimits } : descriptor;
1738
+ }
1573
1739
  function classifyRequestDeviceError(e) {
1574
1740
  const msg = e instanceof Error ? e.message : String(e);
1575
1741
  if (/feature/i.test(msg)) return featureNotEnabled();
@@ -1589,7 +1755,9 @@ async function requestDevice(opts = {}) {
1589
1755
  }
1590
1756
  let rawDevice;
1591
1757
  try {
1592
- rawDevice = await adapter.requestDevice(opts.deviceDescriptor);
1758
+ rawDevice = await adapter.requestDevice(
1759
+ normalizeDeviceDescriptor(adapter, opts.deviceDescriptor)
1760
+ );
1593
1761
  } catch (e) {
1594
1762
  return classifyRequestDeviceError(e);
1595
1763
  }
@@ -1679,7 +1847,7 @@ function makeRhiAdapter(rawAdapter) {
1679
1847
  let rawDevice;
1680
1848
  try {
1681
1849
  rawDevice = await rawAdapter.requestDevice(
1682
- opts
1850
+ normalizeDeviceDescriptor(rawAdapter, opts)
1683
1851
  );
1684
1852
  } catch (e) {
1685
1853
  return classifyRequestDeviceError(e);