@forgeax/engine-rhi-null 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.
- package/LICENSE +202 -0
- package/README.md +128 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/device-lost-owner.test-d.d.ts +2 -0
- package/dist/__tests__/device-lost-owner.test-d.d.ts.map +1 -0
- package/dist/adapter.d.ts +9 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/bookkeeping.d.ts +86 -0
- package/dist/bookkeeping.d.ts.map +1 -0
- package/dist/canvas-context.d.ts +22 -0
- package/dist/canvas-context.d.ts.map +1 -0
- package/dist/command-encoder.d.ts +27 -0
- package/dist/command-encoder.d.ts.map +1 -0
- package/dist/device.d.ts +66 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +470 -0
- package/dist/index.mjs.map +1 -0
- package/dist/pass-encoders.d.ts +65 -0
- package/dist/pass-encoders.d.ts.map +1 -0
- package/dist/queue.d.ts +10 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/shader.d.ts +14 -0
- package/dist/shader.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/__tests__/device-lost-owner.test-d.ts +48 -0
- package/src/adapter.ts +40 -0
- package/src/bookkeeping.ts +179 -0
- package/src/canvas-context.ts +71 -0
- package/src/command-encoder.ts +145 -0
- package/src/device.ts +259 -0
- package/src/index.ts +63 -0
- package/src/pass-encoders.ts +211 -0
- package/src/queue.ts +62 -0
- package/src/shader.ts +37 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CanvasConfiguration, Result, RhiCanvasContext, RhiError as RhiErrorType, Texture } from '@forgeax/engine-rhi';
|
|
2
|
+
/**
|
|
3
|
+
* Headless canvas context. configure succeeds vacuously; getCurrentTexture
|
|
4
|
+
* mints a legal opaque-handle Texture brand so the swap-chain acquisition path
|
|
5
|
+
* never blocks frame rendering in headless CI.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RhiNullCanvasContext implements RhiCanvasContext {
|
|
8
|
+
configure(_desc: CanvasConfiguration): Result<void, RhiErrorType>;
|
|
9
|
+
unconfigure(): void;
|
|
10
|
+
getConfiguration(): CanvasConfiguration | undefined;
|
|
11
|
+
getCurrentTexture(): Result<Texture, RhiErrorType>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Acquire a canvas context. The headless backend returns ok(context) so the
|
|
15
|
+
* createRenderer context-acquisition step succeeds. The context's
|
|
16
|
+
* getCurrentTexture mints a legal Texture brand once a bookkeeper is attached.
|
|
17
|
+
*
|
|
18
|
+
* R-1: this is mounted on the rhi singleton so Channel 1's facade never
|
|
19
|
+
* crashes on a missing acquireCanvasContext.
|
|
20
|
+
*/
|
|
21
|
+
export declare function acquireCanvasContext(_canvas?: HTMLCanvasElement | OffscreenCanvas | null | undefined): Result<RhiCanvasContext, RhiErrorType>;
|
|
22
|
+
//# sourceMappingURL=canvas-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-context.d.ts","sourceRoot":"","sources":["../src/canvas-context.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EACN,gBAAgB,EAChB,QAAQ,IAAI,YAAY,EACxB,OAAO,EACR,MAAM,qBAAqB,CAAC;AAG7B;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D,SAAS,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;IAIjE,WAAW,IAAI,IAAI;IAEnB,gBAAgB,IAAI,mBAAmB,GAAG,SAAS;IAInD,iBAAiB,IAAI,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC;CAMnD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI,GAAG,SAAS,GAC/D,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAExC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Buffer, CommandBuffer, ComputePassDescriptor, QuerySet, Result, RhiCommandEncoder, RhiComputePassEncoder, RhiError as RhiErrorType, RhiRenderPassEncoder } from '@forgeax/engine-rhi';
|
|
2
|
+
import type { Bookkeeper } from './bookkeeping';
|
|
3
|
+
import type { RhiNullDevice } from './device';
|
|
4
|
+
/**
|
|
5
|
+
* Headless command encoder. begin*Pass returns a no-op pass encoder bound to
|
|
6
|
+
* the issuing device's ledger; recording methods are no-ops; finish mints a
|
|
7
|
+
* CommandBuffer brand.
|
|
8
|
+
*/
|
|
9
|
+
export declare class RhiNullCommandEncoder implements RhiCommandEncoder {
|
|
10
|
+
private readonly bookkeeper;
|
|
11
|
+
private readonly counter;
|
|
12
|
+
constructor(bookkeeper: Bookkeeper, device: RhiNullDevice);
|
|
13
|
+
beginRenderPass(desc: GPURenderPassDescriptor): RhiRenderPassEncoder;
|
|
14
|
+
beginComputePass(desc?: ComputePassDescriptor | undefined): RhiComputePassEncoder;
|
|
15
|
+
copyBufferToBuffer(_source: Buffer, _sourceOffsetOrDestination: number | Buffer, _destinationOrSize?: Buffer | number | undefined, _destinationOffset?: number | undefined, _size?: number | undefined): void;
|
|
16
|
+
copyBufferToTexture(_source: GPUTexelCopyBufferInfo, _destination: GPUTexelCopyTextureInfo, _copySize: GPUExtent3DStrict): void;
|
|
17
|
+
copyTextureToBuffer(_source: GPUTexelCopyTextureInfo, _destination: GPUTexelCopyBufferInfo, _copySize: GPUExtent3DStrict): void;
|
|
18
|
+
copyTextureToTexture(_source: GPUTexelCopyTextureInfo, _destination: GPUTexelCopyTextureInfo, _copySize: GPUExtent3DStrict): void;
|
|
19
|
+
clearBuffer(_buffer: Buffer, _offset?: number | undefined, _size?: number | undefined): void;
|
|
20
|
+
resolveQuerySet(_querySet: QuerySet, _firstQuery: number, _queryCount: number, _destination: Buffer, _destinationOffset: number): Result<void, RhiErrorType>;
|
|
21
|
+
writeTimestamp(_querySet: QuerySet, _queryIndex: number): void;
|
|
22
|
+
pushDebugGroup(_groupLabel: string): void;
|
|
23
|
+
popDebugGroup(): void;
|
|
24
|
+
insertDebugMarker(_markerLabel: string): void;
|
|
25
|
+
finish(): Result<CommandBuffer, RhiErrorType>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=command-encoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-encoder.d.ts","sourceRoot":"","sources":["../src/command-encoder.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,MAAM,EACN,aAAa,EACb,qBAAqB,EACrB,QAAQ,EACR,MAAM,EACN,iBAAiB,EACjB,qBAAqB,EACrB,QAAQ,IAAI,YAAY,EACxB,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA2C9C;;;;GAIG;AACH,qBAAa,qBAAsB,YAAW,iBAAiB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAE1B,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa;IAKzD,eAAe,CAAC,IAAI,EAAE,uBAAuB,GAAG,oBAAoB;IAKpE,gBAAgB,CAAC,IAAI,CAAC,EAAE,qBAAqB,GAAG,SAAS,GAAG,qBAAqB;IAKjF,kBAAkB,CAChB,OAAO,EAAE,MAAM,EACf,0BAA0B,EAAE,MAAM,GAAG,MAAM,EAC3C,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAChD,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,EACvC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GACzB,IAAI;IAEP,mBAAmB,CACjB,OAAO,EAAE,sBAAsB,EAC/B,YAAY,EAAE,uBAAuB,EACrC,SAAS,EAAE,iBAAiB,GAC3B,IAAI;IAEP,mBAAmB,CACjB,OAAO,EAAE,uBAAuB,EAChC,YAAY,EAAE,sBAAsB,EACpC,SAAS,EAAE,iBAAiB,GAC3B,IAAI;IAEP,oBAAoB,CAClB,OAAO,EAAE,uBAAuB,EAChC,YAAY,EAAE,uBAAuB,EACrC,SAAS,EAAE,iBAAiB,GAC3B,IAAI;IAEP,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAE5F,eAAe,CACb,SAAS,EAAE,QAAQ,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;IAI7B,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAE9D,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAEzC,aAAa,IAAI,IAAI;IAErB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAE7C,MAAM,IAAI,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;CAG9C"}
|
package/dist/device.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { BindGroup, BindGroupDescriptor, BindGroupLayout, BindGroupLayoutDescriptor, Buffer, BufferDescriptor, CommandEncoderDescriptor, ComputePipeline, ComputePipelineDescriptor, PipelineLayout, PipelineLayoutDescriptor, QuerySet, QuerySetDescriptor, RenderPipeline, RenderPipelineDescriptor, Result, RhiCaps, RhiCommandEncoder, RhiDevice, RhiError as RhiErrorType, RhiFeatures, RhiLimits, RhiQueue, Sampler, SamplerDescriptor, Texture, TextureDescriptor, TextureView, TextureViewDescriptor } from '@forgeax/engine-rhi';
|
|
2
|
+
import { Bookkeeper } from './bookkeeping';
|
|
3
|
+
type RhiNullDeviceLost = Awaited<RhiDevice['lost']>;
|
|
4
|
+
/**
|
|
5
|
+
* Factory that builds a command encoder bound to a device's ledger. Injected at
|
|
6
|
+
* device construction (rather than imported here) so device.ts carries no
|
|
7
|
+
* dependency on command-encoder.ts; the singleton assembly (index.ts) supplies
|
|
8
|
+
* the real factory. The Bookkeeper and RhiNullDevice are passed so the encoder
|
|
9
|
+
* threads draw / dispatch counts + binding validation through the same per-device
|
|
10
|
+
* ledger AND writes aggregated frame stats to the device for M3 unit-test readback.
|
|
11
|
+
*/
|
|
12
|
+
export type CommandEncoderFactory = (bookkeeper: Bookkeeper, device: RhiNullDevice) => RhiCommandEncoder;
|
|
13
|
+
/**
|
|
14
|
+
* Headless no-op RhiDevice. Every create* mints a legal brand and records it;
|
|
15
|
+
* every destroy* fail-fasts a double-destroy; caps reports the all-true-except-
|
|
16
|
+
* reserved profile (D-5).
|
|
17
|
+
*/
|
|
18
|
+
export declare class RhiNullDevice implements RhiDevice {
|
|
19
|
+
private readonly internalBookkeeper;
|
|
20
|
+
private readonly nullQueue;
|
|
21
|
+
private readonly encoderFactory;
|
|
22
|
+
/** Per-frame total draw count across all pass encoders executed this frame
|
|
23
|
+
* (aggregated by the command encoder on finish, then reset). M3 unit tests
|
|
24
|
+
* (w17) read this to assert draw count >= 1 (AC-06). */
|
|
25
|
+
totalDrawCount: number;
|
|
26
|
+
/** Per-frame total direct and indirect compute dispatch count. */
|
|
27
|
+
totalDispatchCount: number;
|
|
28
|
+
/** Per-frame total bind group set count (AC-06 / AC-05 readback). */
|
|
29
|
+
totalBindGroupCount: number;
|
|
30
|
+
/** Per-frame pass names executed this frame, in schedule order (AC-04). */
|
|
31
|
+
framePassNames: string[];
|
|
32
|
+
/** The per-device handle ledger — exposed so M3 tests can assert create/destroy
|
|
33
|
+
* pairing and BGL/PSO shape counts (AC-05/06/07). */
|
|
34
|
+
get bookkeeper(): Bookkeeper;
|
|
35
|
+
constructor(queue: RhiQueue, encoderFactory: CommandEncoderFactory);
|
|
36
|
+
get caps(): RhiCaps;
|
|
37
|
+
get features(): RhiFeatures;
|
|
38
|
+
get limits(): RhiLimits;
|
|
39
|
+
get queue(): RhiQueue;
|
|
40
|
+
get lost(): Promise<RhiNullDeviceLost>;
|
|
41
|
+
createBuffer(_desc: BufferDescriptor): Result<Buffer, RhiErrorType>;
|
|
42
|
+
createTexture(_desc: TextureDescriptor): Result<Texture, RhiErrorType>;
|
|
43
|
+
destroyBuffer(buf: Buffer): Result<void, RhiErrorType>;
|
|
44
|
+
destroyQuerySet(querySet: QuerySet): Result<void, RhiErrorType>;
|
|
45
|
+
destroyTexture(tex: Texture): Result<void, RhiErrorType>;
|
|
46
|
+
createTextureView(_texture: Texture, _desc: TextureViewDescriptor): Result<TextureView, RhiErrorType>;
|
|
47
|
+
createSampler(_desc?: SamplerDescriptor | undefined): Result<Sampler, RhiErrorType>;
|
|
48
|
+
createBindGroupLayout(_desc: BindGroupLayoutDescriptor): Result<BindGroupLayout, RhiErrorType>;
|
|
49
|
+
createBindGroup(_desc: BindGroupDescriptor): Result<BindGroup, RhiErrorType>;
|
|
50
|
+
createPipelineLayout(_desc: PipelineLayoutDescriptor): Result<PipelineLayout, RhiErrorType>;
|
|
51
|
+
createRenderPipeline(_desc: RenderPipelineDescriptor): Result<RenderPipeline, RhiErrorType>;
|
|
52
|
+
createComputePipeline(_desc: ComputePipelineDescriptor): Result<ComputePipeline, RhiErrorType>;
|
|
53
|
+
createQuerySet(desc: QuerySetDescriptor): Result<QuerySet, RhiErrorType>;
|
|
54
|
+
createCommandEncoder(_desc?: CommandEncoderDescriptor | undefined): Result<RhiCommandEncoder, RhiErrorType>;
|
|
55
|
+
/**
|
|
56
|
+
* Mint a pipeline handle whose object also carries the no-op
|
|
57
|
+
* `getBindGroupLayout(index)` ops method (D-2). The prod auto-layout path
|
|
58
|
+
* (debug-draw.ts) and the existing mock unit tests both call
|
|
59
|
+
* `pipeline.getBindGroupLayout(n)`; returning a legal BindGroupLayout brand
|
|
60
|
+
* (recorded in the ledger) keeps those consumers from crashing on a missing
|
|
61
|
+
* method.
|
|
62
|
+
*/
|
|
63
|
+
private makePipeline;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RhiInstance } from '@forgeax/engine-rhi';
|
|
2
|
+
import { acquireCanvasContext } from './canvas-context';
|
|
3
|
+
import { createShaderModule } from './shader';
|
|
4
|
+
/**
|
|
5
|
+
* The `rhi` singleton — RhiBackendPack-shaped entry for Channel 1 injection
|
|
6
|
+
* (`createRenderer(canvas, { rhi })`). Carries acquireCanvasContext (R-1) so
|
|
7
|
+
* the facade never crashes on a missing method, and createShaderModule (R-2) so
|
|
8
|
+
* the ready chain's shader step resolves rather than rejecting.
|
|
9
|
+
*/
|
|
10
|
+
export declare const rhi: RhiInstance & {
|
|
11
|
+
acquireCanvasContext: typeof acquireCanvasContext;
|
|
12
|
+
createShaderModule: typeof createShaderModule;
|
|
13
|
+
};
|
|
14
|
+
export { RhiNullAdapter } from './adapter';
|
|
15
|
+
export { acquireCanvasContext, RhiNullCanvasContext } from './canvas-context';
|
|
16
|
+
export { RhiNullCommandEncoder } from './command-encoder';
|
|
17
|
+
export { RhiNullDevice } from './device';
|
|
18
|
+
export { RhiNullComputePassEncoder, RhiNullRenderPassEncoder } from './pass-encoders';
|
|
19
|
+
export { RhiNullQueue } from './queue';
|
|
20
|
+
export { createShaderModule } from './shader';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAKV,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAc9C;;;;;GAKG;AACH,eAAO,MAAM,GAAG,EAAE,WAAW,GAAG;IAC9B,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;CAK/C,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { ok, err } from '@forgeax/engine-types';
|
|
2
|
+
import { RhiError } from '@forgeax/engine-rhi';
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var RhiNullRenderPassEncoder = class {
|
|
6
|
+
/** Number of draw* calls issued on this pass (AC-06 readback). */
|
|
7
|
+
drawCount = 0;
|
|
8
|
+
bindGroupCount = 0;
|
|
9
|
+
/** Most recent setVertexBuffer / setBindGroup ownership validation; ok unless
|
|
10
|
+
* a foreign handle was passed (AC-09 readback). */
|
|
11
|
+
lastValidation = ok(void 0);
|
|
12
|
+
bookkeeper;
|
|
13
|
+
counter;
|
|
14
|
+
passName;
|
|
15
|
+
constructor(bookkeeper, counter, passName) {
|
|
16
|
+
this.bookkeeper = bookkeeper;
|
|
17
|
+
this.counter = counter;
|
|
18
|
+
this.passName = passName;
|
|
19
|
+
}
|
|
20
|
+
setPipeline(_pipeline) {
|
|
21
|
+
}
|
|
22
|
+
setVertexBuffer(_slot, buffer, _offset, _size) {
|
|
23
|
+
this.lastValidation = this.bookkeeper.validateOwnership(buffer);
|
|
24
|
+
}
|
|
25
|
+
setIndexBuffer(_buffer, _format, _offset, _size) {
|
|
26
|
+
}
|
|
27
|
+
setBindGroup(_index, bindGroup, _dynamicOffsetsData, _dynamicOffsetsDataStart, _dynamicOffsetsDataLength) {
|
|
28
|
+
this.bindGroupCount++;
|
|
29
|
+
this.counter?.recordBindGroup();
|
|
30
|
+
this.lastValidation = this.bookkeeper.validateOwnership(bindGroup);
|
|
31
|
+
}
|
|
32
|
+
draw(_vertexCount, _instanceCount, _firstVertex, _firstInstance) {
|
|
33
|
+
this.drawCount++;
|
|
34
|
+
this.counter?.recordDraw();
|
|
35
|
+
}
|
|
36
|
+
drawIndexed(_indexCount, _instanceCount, _firstIndex, _baseVertex, _firstInstance) {
|
|
37
|
+
this.drawCount++;
|
|
38
|
+
this.counter?.recordDraw();
|
|
39
|
+
}
|
|
40
|
+
end() {
|
|
41
|
+
this.counter?.recordPassName(this.passName);
|
|
42
|
+
}
|
|
43
|
+
setViewport(_x, _y, _w, _h, _minDepth, _maxDepth) {
|
|
44
|
+
}
|
|
45
|
+
setScissorRect(_x, _y, _w, _h) {
|
|
46
|
+
}
|
|
47
|
+
setBlendConstant(_color) {
|
|
48
|
+
}
|
|
49
|
+
setStencilReference(_reference) {
|
|
50
|
+
}
|
|
51
|
+
drawIndirect(_indirectBuffer, _indirectOffset) {
|
|
52
|
+
this.drawCount++;
|
|
53
|
+
this.counter?.recordDraw();
|
|
54
|
+
}
|
|
55
|
+
drawIndexedIndirect(_indirectBuffer, _indirectOffset) {
|
|
56
|
+
this.drawCount++;
|
|
57
|
+
this.counter?.recordDraw();
|
|
58
|
+
}
|
|
59
|
+
pushDebugGroup(_groupLabel) {
|
|
60
|
+
}
|
|
61
|
+
popDebugGroup() {
|
|
62
|
+
}
|
|
63
|
+
insertDebugMarker(_markerLabel) {
|
|
64
|
+
}
|
|
65
|
+
executeBundles(_bundles) {
|
|
66
|
+
return ok(void 0);
|
|
67
|
+
}
|
|
68
|
+
beginOcclusionQuery(_queryIndex) {
|
|
69
|
+
return ok(void 0);
|
|
70
|
+
}
|
|
71
|
+
endOcclusionQuery() {
|
|
72
|
+
return ok(void 0);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var RhiNullComputePassEncoder = class {
|
|
76
|
+
/** Number of dispatchWorkgroups calls issued on this pass (readback). */
|
|
77
|
+
dispatchCount = 0;
|
|
78
|
+
/** Most recent setBindGroup ownership validation (AC-09 readback). */
|
|
79
|
+
lastValidation = ok(void 0);
|
|
80
|
+
bookkeeper;
|
|
81
|
+
counter;
|
|
82
|
+
passName;
|
|
83
|
+
constructor(bookkeeper, counter, passName) {
|
|
84
|
+
this.bookkeeper = bookkeeper;
|
|
85
|
+
this.counter = counter;
|
|
86
|
+
this.passName = passName;
|
|
87
|
+
}
|
|
88
|
+
setPipeline(_pipeline) {
|
|
89
|
+
}
|
|
90
|
+
setBindGroup(_index, bindGroup, _dynamicOffsets) {
|
|
91
|
+
this.lastValidation = this.bookkeeper.validateOwnership(bindGroup);
|
|
92
|
+
}
|
|
93
|
+
dispatchWorkgroups(_x, _y, _z) {
|
|
94
|
+
this.dispatchCount++;
|
|
95
|
+
this.counter?.recordDispatch();
|
|
96
|
+
}
|
|
97
|
+
dispatchWorkgroupsIndirect(indirectBuffer, _indirectOffset) {
|
|
98
|
+
this.lastValidation = this.bookkeeper.validateOwnership(indirectBuffer);
|
|
99
|
+
this.dispatchCount++;
|
|
100
|
+
this.counter?.recordDispatch();
|
|
101
|
+
}
|
|
102
|
+
end() {
|
|
103
|
+
this.counter?.recordPassName(this.passName);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// src/command-encoder.ts
|
|
108
|
+
var DeviceCounter = class {
|
|
109
|
+
constructor(device) {
|
|
110
|
+
this.device = device;
|
|
111
|
+
}
|
|
112
|
+
device;
|
|
113
|
+
recordDraw() {
|
|
114
|
+
this.device.totalDrawCount++;
|
|
115
|
+
}
|
|
116
|
+
recordDispatch() {
|
|
117
|
+
this.device.totalDispatchCount++;
|
|
118
|
+
}
|
|
119
|
+
recordBindGroup() {
|
|
120
|
+
this.device.totalBindGroupCount++;
|
|
121
|
+
}
|
|
122
|
+
recordPassName(name) {
|
|
123
|
+
this.device.framePassNames.push(name);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
function readPassLabel(desc) {
|
|
127
|
+
if (desc && typeof desc.label === "string" && desc.label.length > 0) {
|
|
128
|
+
return desc.label;
|
|
129
|
+
}
|
|
130
|
+
return "<unnamed>";
|
|
131
|
+
}
|
|
132
|
+
var RhiNullCommandEncoder = class {
|
|
133
|
+
bookkeeper;
|
|
134
|
+
counter;
|
|
135
|
+
constructor(bookkeeper, device) {
|
|
136
|
+
this.bookkeeper = bookkeeper;
|
|
137
|
+
this.counter = new DeviceCounter(device);
|
|
138
|
+
}
|
|
139
|
+
beginRenderPass(desc) {
|
|
140
|
+
const label = readPassLabel(desc);
|
|
141
|
+
return new RhiNullRenderPassEncoder(this.bookkeeper, this.counter, label);
|
|
142
|
+
}
|
|
143
|
+
beginComputePass(desc) {
|
|
144
|
+
const label = readPassLabel(desc);
|
|
145
|
+
return new RhiNullComputePassEncoder(this.bookkeeper, this.counter, label);
|
|
146
|
+
}
|
|
147
|
+
copyBufferToBuffer(_source, _sourceOffsetOrDestination, _destinationOrSize, _destinationOffset, _size) {
|
|
148
|
+
}
|
|
149
|
+
copyBufferToTexture(_source, _destination, _copySize) {
|
|
150
|
+
}
|
|
151
|
+
copyTextureToBuffer(_source, _destination, _copySize) {
|
|
152
|
+
}
|
|
153
|
+
copyTextureToTexture(_source, _destination, _copySize) {
|
|
154
|
+
}
|
|
155
|
+
clearBuffer(_buffer, _offset, _size) {
|
|
156
|
+
}
|
|
157
|
+
resolveQuerySet(_querySet, _firstQuery, _queryCount, _destination, _destinationOffset) {
|
|
158
|
+
return ok(void 0);
|
|
159
|
+
}
|
|
160
|
+
writeTimestamp(_querySet, _queryIndex) {
|
|
161
|
+
}
|
|
162
|
+
pushDebugGroup(_groupLabel) {
|
|
163
|
+
}
|
|
164
|
+
popDebugGroup() {
|
|
165
|
+
}
|
|
166
|
+
insertDebugMarker(_markerLabel) {
|
|
167
|
+
}
|
|
168
|
+
finish() {
|
|
169
|
+
return ok(this.bookkeeper.register("CommandBuffer"));
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
var BOOKKEEPING_KEY = /* @__PURE__ */ Symbol("forgeax-rhi-null-bookkeeping");
|
|
173
|
+
var Bookkeeper = class {
|
|
174
|
+
deviceId;
|
|
175
|
+
nextHandleId = 0;
|
|
176
|
+
records = /* @__PURE__ */ new Map();
|
|
177
|
+
constructor(deviceId) {
|
|
178
|
+
this.deviceId = deviceId;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Register a freshly-minted handle of the given kind, returning a plain
|
|
182
|
+
* object that carries its ledger row. The caller casts the return value to
|
|
183
|
+
* the concrete brand (`as unknown as Buffer` etc.).
|
|
184
|
+
*/
|
|
185
|
+
register(kind) {
|
|
186
|
+
const id = this.nextHandleId++;
|
|
187
|
+
const record = {
|
|
188
|
+
id,
|
|
189
|
+
kind,
|
|
190
|
+
destroyed: false,
|
|
191
|
+
sourceDeviceId: this.deviceId
|
|
192
|
+
};
|
|
193
|
+
this.records.set(id, record);
|
|
194
|
+
return { [BOOKKEEPING_KEY]: record };
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Mark a handle destroyed. Fail-fasts on a second destroy
|
|
198
|
+
* ('destroy-after-destroy') or on a handle issued by a different device
|
|
199
|
+
* ('rhi-not-available'); otherwise flips the destroyed flag and returns ok.
|
|
200
|
+
*/
|
|
201
|
+
destroy(handle) {
|
|
202
|
+
const ownership = this.validateOwnership(handle);
|
|
203
|
+
if (!ownership.ok) return ownership;
|
|
204
|
+
const destroyedCheck = isHandleDestroyed(handle);
|
|
205
|
+
if (!destroyedCheck.ok) return destroyedCheck;
|
|
206
|
+
ownership.value.destroyed = true;
|
|
207
|
+
return ok(void 0);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Report whether a handle has already been destroyed (true once destroy()
|
|
211
|
+
* has flipped its flag). Used by command-stream methods that must not
|
|
212
|
+
* consume a stale handle.
|
|
213
|
+
*/
|
|
214
|
+
isDestroyed(handle) {
|
|
215
|
+
return readRecord(handle)?.destroyed === true;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Validate that a handle was issued by THIS device. Returns the ledger row on
|
|
219
|
+
* success so callers can mutate it (e.g. flip destroyed); returns
|
|
220
|
+
* 'rhi-not-available' for a foreign handle (AC-09 — no silent pass).
|
|
221
|
+
*/
|
|
222
|
+
validateOwnership(handle) {
|
|
223
|
+
const record = readRecord(handle);
|
|
224
|
+
if (record === void 0 || record.sourceDeviceId !== this.deviceId) {
|
|
225
|
+
return err(
|
|
226
|
+
new RhiError({
|
|
227
|
+
code: "rhi-not-available",
|
|
228
|
+
expected: "handle was issued by this RhiNull device",
|
|
229
|
+
hint: "do not pass a handle created on a different RhiNull device into this device; create resources on the device they are used with"
|
|
230
|
+
})
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
return ok(record);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Return all ledger rows as a readonly array. M3 unit tests (w17) read this
|
|
237
|
+
* to assert create/destroy pairing, BGL/PSO shape counts, and resource
|
|
238
|
+
* lifecycle coverage (AC-05/06/07). Returns a snapshot of the current Map
|
|
239
|
+
* so callers can iterate without a stale reference after further mutations.
|
|
240
|
+
*/
|
|
241
|
+
allRecords() {
|
|
242
|
+
return [...this.records.values()];
|
|
243
|
+
}
|
|
244
|
+
/** Report the total number of records in the ledger. */
|
|
245
|
+
recordCount() {
|
|
246
|
+
return this.records.size;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
function readRecord(handle) {
|
|
250
|
+
if (handle === null || typeof handle !== "object") return void 0;
|
|
251
|
+
const tagged = handle;
|
|
252
|
+
return tagged[BOOKKEEPING_KEY];
|
|
253
|
+
}
|
|
254
|
+
function isHandleDestroyed(handle) {
|
|
255
|
+
if (readRecord(handle)?.destroyed === true) {
|
|
256
|
+
return err(
|
|
257
|
+
new RhiError({
|
|
258
|
+
code: "destroy-after-destroy",
|
|
259
|
+
expected: "GPU buffer/texture handle has not been destroyed yet",
|
|
260
|
+
hint: "object already destroyed; track lifecycle in caller or check isDestroyed before re-destroy"
|
|
261
|
+
})
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return ok(void 0);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/device.ts
|
|
268
|
+
var nextDeviceId = 0;
|
|
269
|
+
var RhiNullDevice = class {
|
|
270
|
+
internalBookkeeper;
|
|
271
|
+
nullQueue;
|
|
272
|
+
encoderFactory;
|
|
273
|
+
/** Per-frame total draw count across all pass encoders executed this frame
|
|
274
|
+
* (aggregated by the command encoder on finish, then reset). M3 unit tests
|
|
275
|
+
* (w17) read this to assert draw count >= 1 (AC-06). */
|
|
276
|
+
totalDrawCount = 0;
|
|
277
|
+
/** Per-frame total direct and indirect compute dispatch count. */
|
|
278
|
+
totalDispatchCount = 0;
|
|
279
|
+
/** Per-frame total bind group set count (AC-06 / AC-05 readback). */
|
|
280
|
+
totalBindGroupCount = 0;
|
|
281
|
+
/** Per-frame pass names executed this frame, in schedule order (AC-04). */
|
|
282
|
+
framePassNames = [];
|
|
283
|
+
/** The per-device handle ledger — exposed so M3 tests can assert create/destroy
|
|
284
|
+
* pairing and BGL/PSO shape counts (AC-05/06/07). */
|
|
285
|
+
get bookkeeper() {
|
|
286
|
+
return this.internalBookkeeper;
|
|
287
|
+
}
|
|
288
|
+
constructor(queue, encoderFactory) {
|
|
289
|
+
this.internalBookkeeper = new Bookkeeper(nextDeviceId++);
|
|
290
|
+
this.nullQueue = queue;
|
|
291
|
+
this.encoderFactory = encoderFactory;
|
|
292
|
+
}
|
|
293
|
+
get caps() {
|
|
294
|
+
return {
|
|
295
|
+
backendKind: "null",
|
|
296
|
+
compute: true,
|
|
297
|
+
timestampQuery: false,
|
|
298
|
+
timestampPeriodNanoseconds: null,
|
|
299
|
+
indirectDrawing: true,
|
|
300
|
+
textureCompressionBc: false,
|
|
301
|
+
textureCompressionEtc2: false,
|
|
302
|
+
textureCompressionAstc: false,
|
|
303
|
+
// 3 wgpu-native-only reserved flags stay false on non-native backends
|
|
304
|
+
// (D-5); the headless backend is not a native runtime.
|
|
305
|
+
multiDrawIndirect: false,
|
|
306
|
+
pushConstants: false,
|
|
307
|
+
textureBindingArray: false,
|
|
308
|
+
samplerAliasing: true,
|
|
309
|
+
firstInstanceIndirect: true,
|
|
310
|
+
storageBuffer: true,
|
|
311
|
+
storageTexture: true,
|
|
312
|
+
rgba16floatRenderable: true,
|
|
313
|
+
rg11b10ufloatRenderable: true,
|
|
314
|
+
float32Filterable: true,
|
|
315
|
+
maxColorAttachments: 8
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
get features() {
|
|
319
|
+
return EMPTY_FEATURES;
|
|
320
|
+
}
|
|
321
|
+
get limits() {
|
|
322
|
+
return EMPTY_LIMITS;
|
|
323
|
+
}
|
|
324
|
+
get queue() {
|
|
325
|
+
return this.nullQueue;
|
|
326
|
+
}
|
|
327
|
+
// forgeax-async-whitelist: dom-native — spec `GPUDevice.lost` Promise
|
|
328
|
+
// passthrough. The headless backend never loses a device (no GPU), so the
|
|
329
|
+
// Promise stays unsettled for the lifetime of the device, mirroring a live
|
|
330
|
+
// device that never transitions to the lost state.
|
|
331
|
+
get lost() {
|
|
332
|
+
return NEVER;
|
|
333
|
+
}
|
|
334
|
+
createBuffer(_desc) {
|
|
335
|
+
return ok(this.internalBookkeeper.register("Buffer"));
|
|
336
|
+
}
|
|
337
|
+
createTexture(_desc) {
|
|
338
|
+
return ok(this.internalBookkeeper.register("Texture"));
|
|
339
|
+
}
|
|
340
|
+
destroyBuffer(buf) {
|
|
341
|
+
return this.internalBookkeeper.destroy(buf);
|
|
342
|
+
}
|
|
343
|
+
destroyQuerySet(querySet) {
|
|
344
|
+
return this.internalBookkeeper.destroy(querySet);
|
|
345
|
+
}
|
|
346
|
+
destroyTexture(tex) {
|
|
347
|
+
return this.internalBookkeeper.destroy(tex);
|
|
348
|
+
}
|
|
349
|
+
createTextureView(_texture, _desc) {
|
|
350
|
+
return ok(this.internalBookkeeper.register("TextureView"));
|
|
351
|
+
}
|
|
352
|
+
createSampler(_desc) {
|
|
353
|
+
return ok(this.internalBookkeeper.register("Sampler"));
|
|
354
|
+
}
|
|
355
|
+
createBindGroupLayout(_desc) {
|
|
356
|
+
return ok(this.internalBookkeeper.register("BindGroupLayout"));
|
|
357
|
+
}
|
|
358
|
+
createBindGroup(_desc) {
|
|
359
|
+
return ok(this.internalBookkeeper.register("BindGroup"));
|
|
360
|
+
}
|
|
361
|
+
createPipelineLayout(_desc) {
|
|
362
|
+
return ok(this.internalBookkeeper.register("PipelineLayout"));
|
|
363
|
+
}
|
|
364
|
+
createRenderPipeline(_desc) {
|
|
365
|
+
return ok(this.makePipeline("RenderPipeline"));
|
|
366
|
+
}
|
|
367
|
+
createComputePipeline(_desc) {
|
|
368
|
+
return ok(this.makePipeline("ComputePipeline"));
|
|
369
|
+
}
|
|
370
|
+
createQuerySet(desc) {
|
|
371
|
+
if (desc.type === "timestamp") {
|
|
372
|
+
return err(
|
|
373
|
+
new RhiError({
|
|
374
|
+
code: "feature-not-enabled",
|
|
375
|
+
expected: "caps.timestampQuery === true (timestamp-query feature)",
|
|
376
|
+
hint: "RhiNull is structural-only and cannot produce GPU timestamp ticks"
|
|
377
|
+
})
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return ok(this.internalBookkeeper.register("QuerySet"));
|
|
381
|
+
}
|
|
382
|
+
createCommandEncoder(_desc) {
|
|
383
|
+
return ok(this.encoderFactory(this.internalBookkeeper, this));
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Mint a pipeline handle whose object also carries the no-op
|
|
387
|
+
* `getBindGroupLayout(index)` ops method (D-2). The prod auto-layout path
|
|
388
|
+
* (debug-draw.ts) and the existing mock unit tests both call
|
|
389
|
+
* `pipeline.getBindGroupLayout(n)`; returning a legal BindGroupLayout brand
|
|
390
|
+
* (recorded in the ledger) keeps those consumers from crashing on a missing
|
|
391
|
+
* method.
|
|
392
|
+
*/
|
|
393
|
+
makePipeline(kind) {
|
|
394
|
+
const handle = this.internalBookkeeper.register(kind);
|
|
395
|
+
const getBindGroupLayout = (_index) => this.internalBookkeeper.register("BindGroupLayout");
|
|
396
|
+
return Object.assign(handle, { getBindGroupLayout });
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var EMPTY_FEATURES = /* @__PURE__ */ new Set();
|
|
400
|
+
var EMPTY_LIMITS = {};
|
|
401
|
+
var NEVER = new Promise(() => {
|
|
402
|
+
});
|
|
403
|
+
var RhiNullQueue = class {
|
|
404
|
+
writeBuffer(_buffer, _bufferOffset, _data, _dataOffset, _size) {
|
|
405
|
+
return ok(void 0);
|
|
406
|
+
}
|
|
407
|
+
writeTexture(_destination, _data, _dataLayout, _size) {
|
|
408
|
+
return ok(void 0);
|
|
409
|
+
}
|
|
410
|
+
copyExternalImageToTexture(_source, _destination, _copySize) {
|
|
411
|
+
return ok(void 0);
|
|
412
|
+
}
|
|
413
|
+
submit(_commandBuffers) {
|
|
414
|
+
return ok(void 0);
|
|
415
|
+
}
|
|
416
|
+
// forgeax-async-whitelist: dom-native — spec `GPUQueue.onSubmittedWorkDone`
|
|
417
|
+
// never rejects. The headless backend has no pending GPU work, so it resolves
|
|
418
|
+
// immediately (AC-12: read-back idioms must not hang).
|
|
419
|
+
onSubmittedWorkDone() {
|
|
420
|
+
return Promise.resolve(void 0);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// src/adapter.ts
|
|
425
|
+
var RhiNullAdapter = class {
|
|
426
|
+
features = /* @__PURE__ */ new Set();
|
|
427
|
+
limits = {};
|
|
428
|
+
// forgeax-async-whitelist is not needed: this returns Promise<Result<...>>
|
|
429
|
+
// per the spec contract; never rejects.
|
|
430
|
+
requestDevice(_opts) {
|
|
431
|
+
const device = new RhiNullDevice(
|
|
432
|
+
new RhiNullQueue(),
|
|
433
|
+
(bookkeeper, dev) => new RhiNullCommandEncoder(bookkeeper, dev)
|
|
434
|
+
);
|
|
435
|
+
return Promise.resolve(ok(device));
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
var RhiNullCanvasContext = class {
|
|
439
|
+
configure(_desc) {
|
|
440
|
+
return ok(void 0);
|
|
441
|
+
}
|
|
442
|
+
unconfigure() {
|
|
443
|
+
}
|
|
444
|
+
getConfiguration() {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
getCurrentTexture() {
|
|
448
|
+
return ok({});
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
function acquireCanvasContext(_canvas) {
|
|
452
|
+
return ok(new RhiNullCanvasContext());
|
|
453
|
+
}
|
|
454
|
+
function createShaderModule(_device, _desc) {
|
|
455
|
+
return Promise.resolve(ok({}));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/index.ts
|
|
459
|
+
function requestAdapter(_opts, _compatibleSurface) {
|
|
460
|
+
return Promise.resolve(ok(new RhiNullAdapter()));
|
|
461
|
+
}
|
|
462
|
+
var rhi = {
|
|
463
|
+
requestAdapter,
|
|
464
|
+
acquireCanvasContext,
|
|
465
|
+
createShaderModule
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
export { RhiNullAdapter, RhiNullCanvasContext, RhiNullCommandEncoder, RhiNullComputePassEncoder, RhiNullDevice, RhiNullQueue, RhiNullRenderPassEncoder, acquireCanvasContext, createShaderModule, rhi };
|
|
469
|
+
//# sourceMappingURL=index.mjs.map
|
|
470
|
+
//# sourceMappingURL=index.mjs.map
|