@forgeax/engine-rhi-webgpu 0.1.2

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 (45) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +124 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/__mocks__/gpu-device.d.ts +233 -0
  5. package/dist/__tests__/__mocks__/gpu-device.d.ts.map +1 -0
  6. package/dist/__tests__/dawn-real-gpu.dawn.test.d.ts +2 -0
  7. package/dist/__tests__/dawn-real-gpu.dawn.test.d.ts.map +1 -0
  8. package/dist/__tests__/queue-write-range.browser.test.d.ts +2 -0
  9. package/dist/__tests__/queue-write-range.browser.test.d.ts.map +1 -0
  10. package/dist/__tests__/rgba16float-live-probe.browser.test.d.ts +2 -0
  11. package/dist/__tests__/rgba16float-live-probe.browser.test.d.ts.map +1 -0
  12. package/dist/__tests__/rgba16float-live-probe.d.ts +12 -0
  13. package/dist/__tests__/rgba16float-live-probe.d.ts.map +1 -0
  14. package/dist/__tests__/rgba16float-live-probe.dawn.test.d.ts +2 -0
  15. package/dist/__tests__/rgba16float-live-probe.dawn.test.d.ts.map +1 -0
  16. package/dist/__tests__/rhi-webgpu.unit.test.d.ts +2 -0
  17. package/dist/__tests__/rhi-webgpu.unit.test.d.ts.map +1 -0
  18. package/dist/device.d.ts +62 -0
  19. package/dist/device.d.ts.map +1 -0
  20. package/dist/errors.d.ts +47 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/index.d.ts +183 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.mjs +1704 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/internal/__tests__/timestamp-query.unit.test.d.ts +2 -0
  27. package/dist/internal/__tests__/timestamp-query.unit.test.d.ts.map +1 -0
  28. package/dist/internal/error-translation.d.ts +16 -0
  29. package/dist/internal/error-translation.d.ts.map +1 -0
  30. package/dist/internal/timestamp-query.d.ts +39 -0
  31. package/dist/internal/timestamp-query.d.ts.map +1 -0
  32. package/package.json +58 -0
  33. package/src/__tests__/__mocks__/gpu-device.ts +564 -0
  34. package/src/__tests__/dawn-real-gpu.dawn.test.ts +1488 -0
  35. package/src/__tests__/queue-write-range.browser.test.ts +60 -0
  36. package/src/__tests__/rgba16float-live-probe.browser.test.ts +13 -0
  37. package/src/__tests__/rgba16float-live-probe.dawn.test.ts +15 -0
  38. package/src/__tests__/rgba16float-live-probe.ts +44 -0
  39. package/src/__tests__/rhi-webgpu.unit.test.ts +2409 -0
  40. package/src/device.ts +1974 -0
  41. package/src/errors.ts +145 -0
  42. package/src/index.ts +599 -0
  43. package/src/internal/__tests__/timestamp-query.unit.test.ts +88 -0
  44. package/src/internal/error-translation.ts +187 -0
  45. package/src/internal/timestamp-query.ts +167 -0
@@ -0,0 +1,60 @@
1
+ import type { RhiDevice } from '@forgeax/engine-rhi';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { rhi } from '../index';
4
+
5
+ async function requestRhiDevice(): Promise<RhiDevice | undefined> {
6
+ if (typeof navigator === 'undefined' || navigator.gpu === undefined) return undefined;
7
+ const adapter = await rhi.requestAdapter();
8
+ expect(adapter.ok).toBe(true);
9
+ if (!adapter.ok) return undefined;
10
+ const device = await adapter.value.requestDevice();
11
+ expect(device.ok).toBe(true);
12
+ if (!device.ok) return undefined;
13
+ return device.value;
14
+ }
15
+
16
+ describe('browser WebGPU queue.writeBuffer typed range', () => {
17
+ it('round-trips the exact selected typed-array elements', async () => {
18
+ const device = await requestRhiDevice();
19
+ if (device === undefined) return;
20
+ const target = device.createBuffer({
21
+ label: 'browser-write-range-target',
22
+ size: 32,
23
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
24
+ });
25
+ const readback = device.createBuffer({
26
+ label: 'browser-write-range-readback',
27
+ size: 32,
28
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
29
+ });
30
+ expect(target.ok && readback.ok).toBe(true);
31
+ if (!target.ok || !readback.ok) return;
32
+
33
+ const write = device.queue.writeBuffer(
34
+ target.value,
35
+ 0,
36
+ new Float32Array([10, 20, 30, 40]),
37
+ 1,
38
+ 2,
39
+ );
40
+ expect(write.ok).toBe(true);
41
+ if (!write.ok) return;
42
+ const encoder = device.createCommandEncoder({ label: 'browser-write-range-copy' });
43
+ expect(encoder.ok).toBe(true);
44
+ if (!encoder.ok) return;
45
+ encoder.value.copyBufferToBuffer(target.value, 0, readback.value, 0, 32);
46
+ const finish = encoder.value.finish();
47
+ expect(finish.ok).toBe(true);
48
+ if (!finish.ok) return;
49
+ expect(device.queue.submit([finish.value]).ok).toBe(true);
50
+ await device.queue.onSubmittedWorkDone();
51
+ const mapped = await readback.value.mapAsync(GPUMapMode.READ);
52
+ expect(mapped.ok).toBe(true);
53
+ if (!mapped.ok) return;
54
+ const range = mapped.value.getMappedRange();
55
+ expect(range.ok).toBe(true);
56
+ if (!range.ok) return;
57
+ expect(Array.from(new Float32Array(range.value.slice(0)))).toEqual([20, 30, 0, 0, 0, 0, 0, 0]);
58
+ mapped.value.unmap();
59
+ });
60
+ });
@@ -0,0 +1,13 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { runRgba16floatLiveProbe } from './rgba16float-live-probe';
3
+
4
+ describe('browser rgba16float live render/readback/recovery probe', () => {
5
+ it('reads the packed render target on the initial and fresh recovery device', async () => {
6
+ const evidence = await runRgba16floatLiveProbe();
7
+ expect(evidence.backend).toBe('webgpu');
8
+ expect(evidence.initial.pixel).toEqual([0.25, 0.5, 0.75, 1]);
9
+ expect(evidence.loss.reason).toBe('destroyed');
10
+ expect(evidence.recovered.pixel).toEqual(evidence.initial.pixel);
11
+ expect(typeof evidence.initial.timestampQuery).toBe('boolean');
12
+ });
13
+ });
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { runRgba16floatLiveProbe } from './rgba16float-live-probe';
3
+
4
+ describe('Dawn rgba16float live render/readback/recovery probe', () => {
5
+ it('reads the packed render target on the initial and fresh recovery device', async () => {
6
+ const evidence = await runRgba16floatLiveProbe();
7
+ expect(evidence.backend).toBe('webgpu');
8
+ expect(evidence.initial.pixel).toEqual([0.25, 0.5, 0.75, 1]);
9
+ expect(evidence.loss.reason).toBe('destroyed');
10
+ expect(evidence.recovered.pixel).toEqual(evidence.initial.pixel);
11
+ expect(typeof evidence.initial.timestampQuery).toBe('boolean');
12
+ // biome-ignore lint/suspicious/noConsole: emitted as live Dawn admission evidence
13
+ console.log(JSON.stringify({ kind: 'rgba16float-live-probe', ...evidence }));
14
+ });
15
+ });
@@ -0,0 +1,44 @@
1
+ import type { RhiDevice } from '@forgeax/engine-rhi';
2
+ import {
3
+ probeRgba16floatRenderTarget,
4
+ type Rgba16floatRenderTargetProbe,
5
+ } from '@forgeax/engine-rhi';
6
+ import { _internal_getRawDevice, rhi } from '../index';
7
+
8
+ export interface Rgba16floatLiveProbeEvidence {
9
+ readonly backend: string;
10
+ readonly initial: Rgba16floatRenderTargetProbe;
11
+ readonly loss: { readonly reason: 'destroyed' | 'unknown'; readonly message: string };
12
+ readonly recovered: Rgba16floatRenderTargetProbe;
13
+ }
14
+
15
+ async function probeFreshDevice(): Promise<{
16
+ readonly backend: string;
17
+ readonly device: RhiDevice;
18
+ readonly report: Rgba16floatRenderTargetProbe;
19
+ }> {
20
+ const adapter = await rhi.requestAdapter();
21
+ if (!adapter.ok) throw adapter.error;
22
+ const device = await adapter.value.requestDevice();
23
+ if (!device.ok) throw device.error;
24
+ const probed = await probeRgba16floatRenderTarget(device.value);
25
+ if (!probed.ok) throw probed.error;
26
+ return { backend: device.value.caps.backendKind, device: device.value, report: probed.value };
27
+ }
28
+
29
+ export async function runRgba16floatLiveProbe(): Promise<Rgba16floatLiveProbeEvidence> {
30
+ const initial = await probeFreshDevice();
31
+ const rawDevice = _internal_getRawDevice(initial.device);
32
+ if (rawDevice === undefined)
33
+ throw new Error('live WebGPU probe requires its backend-owned device');
34
+ const lost = initial.device.lost;
35
+ rawDevice.destroy();
36
+ const loss = await lost;
37
+ const recovered = await probeFreshDevice();
38
+ return {
39
+ backend: initial.backend,
40
+ initial: initial.report,
41
+ loss,
42
+ recovered: recovered.report,
43
+ };
44
+ }