@simulatte/webgpu 0.3.1 → 0.3.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/CHANGELOG.md +27 -12
- package/LICENSE +191 -0
- package/README.md +55 -41
- package/api-contract.md +67 -49
- package/architecture.md +317 -0
- package/assets/package-layers.svg +3 -3
- package/docs/doe-api-reference.html +1842 -0
- package/doe-api-design.md +237 -0
- package/examples/doe-api/README.md +19 -0
- package/examples/doe-api/buffers-readback.js +3 -2
- package/examples/{doe-routines/compute-once-like-input.js → doe-api/compute-one-shot-like-input.js} +1 -1
- package/examples/{doe-routines/compute-once-matmul.js → doe-api/compute-one-shot-matmul.js} +2 -2
- package/examples/{doe-routines/compute-once-multiple-inputs.js → doe-api/compute-one-shot-multiple-inputs.js} +1 -1
- package/examples/{doe-routines/compute-once.js → doe-api/compute-one-shot.js} +1 -1
- package/examples/doe-api/{compile-and-dispatch.js → kernel-create-and-dispatch.js} +4 -6
- package/examples/doe-api/{compute-dispatch.js → kernel-run.js} +4 -6
- package/headless-webgpu-comparison.md +3 -3
- package/jsdoc-style-guide.md +435 -0
- package/native/doe_napi.c +1481 -84
- package/package.json +18 -6
- package/prebuilds/darwin-arm64/doe_napi.node +0 -0
- package/prebuilds/darwin-arm64/libwebgpu_doe.dylib +0 -0
- package/prebuilds/darwin-arm64/metadata.json +5 -5
- package/prebuilds/linux-x64/metadata.json +1 -1
- package/scripts/generate-doe-api-docs.js +1607 -0
- package/scripts/generate-readme-assets.js +3 -3
- package/src/build_metadata.js +7 -4
- package/src/bun-ffi.js +1229 -474
- package/src/bun.js +5 -1
- package/src/compute.d.ts +16 -7
- package/src/compute.js +84 -53
- package/src/full.d.ts +16 -7
- package/src/full.js +12 -10
- package/src/index.js +679 -1324
- package/src/runtime_cli.js +17 -17
- package/src/shared/capabilities.js +144 -0
- package/src/shared/compiler-errors.js +78 -0
- package/src/shared/encoder-surface.js +295 -0
- package/src/shared/full-surface.js +514 -0
- package/src/shared/public-surface.js +82 -0
- package/src/shared/resource-lifecycle.js +120 -0
- package/src/shared/validation.js +495 -0
- package/src/webgpu_constants.js +30 -0
- package/support-contracts.md +2 -2
- package/compat-scope.md +0 -46
- package/layering-plan.md +0 -259
- package/src/auto_bind_group_layout.js +0 -32
- package/src/doe.d.ts +0 -184
- package/src/doe.js +0 -641
- package/zig-source-inventory.md +0 -468
package/src/bun-ffi.js
CHANGED
|
@@ -4,89 +4,113 @@ import { dirname, resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { createDoeRuntime, runDawnVsDoeCompare } from "./runtime_cli.js";
|
|
6
6
|
import { loadDoeBuildMetadata } from "./build_metadata.js";
|
|
7
|
-
import {
|
|
7
|
+
import { globals } from "./webgpu_constants.js";
|
|
8
|
+
import {
|
|
9
|
+
UINT32_MAX,
|
|
10
|
+
failValidation,
|
|
11
|
+
describeResourceLabel,
|
|
12
|
+
initResource,
|
|
13
|
+
assertObject,
|
|
14
|
+
assertArray,
|
|
15
|
+
assertBoolean,
|
|
16
|
+
assertNonEmptyString,
|
|
17
|
+
assertIntegerInRange,
|
|
18
|
+
assertOptionalIntegerInRange,
|
|
19
|
+
assertLiveResource,
|
|
20
|
+
destroyResource,
|
|
21
|
+
validatePositiveInteger,
|
|
22
|
+
} from "./shared/resource-lifecycle.js";
|
|
23
|
+
import {
|
|
24
|
+
publishLimits,
|
|
25
|
+
publishFeatures,
|
|
26
|
+
} from "./shared/capabilities.js";
|
|
27
|
+
import {
|
|
28
|
+
ALL_BUFFER_USAGE_BITS,
|
|
29
|
+
assertBufferDescriptor,
|
|
30
|
+
assertTextureSize,
|
|
31
|
+
assertBindGroupResource as normalizeBindGroupResource,
|
|
32
|
+
normalizeTextureDimension,
|
|
33
|
+
normalizeBindGroupLayoutEntry,
|
|
34
|
+
autoLayoutEntriesFromNativeBindings,
|
|
35
|
+
} from "./shared/validation.js";
|
|
36
|
+
import {
|
|
37
|
+
setupGlobalsOnTarget,
|
|
38
|
+
requestAdapterFromCreate,
|
|
39
|
+
requestDeviceFromRequestAdapter,
|
|
40
|
+
buildProviderInfo,
|
|
41
|
+
libraryFlavor,
|
|
42
|
+
} from "./shared/public-surface.js";
|
|
43
|
+
import {
|
|
44
|
+
shaderCheckFailure,
|
|
45
|
+
enrichNativeCompilerError,
|
|
46
|
+
compilerErrorFromMessage,
|
|
47
|
+
} from "./shared/compiler-errors.js";
|
|
48
|
+
import {
|
|
49
|
+
createFullSurfaceClasses,
|
|
50
|
+
} from "./shared/full-surface.js";
|
|
51
|
+
import {
|
|
52
|
+
createEncoderClasses,
|
|
53
|
+
} from "./shared/encoder-surface.js";
|
|
8
54
|
|
|
9
55
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
56
|
const PACKAGE_ROOT = resolve(__dirname, "..");
|
|
11
57
|
|
|
58
|
+
export { globals };
|
|
59
|
+
|
|
12
60
|
const CALLBACK_MODE_ALLOW_PROCESS_EVENTS = 2;
|
|
61
|
+
const WGPU_STATUS_SUCCESS = 1;
|
|
13
62
|
const REQUEST_ADAPTER_STATUS_SUCCESS = 1;
|
|
14
63
|
const REQUEST_DEVICE_STATUS_SUCCESS = 1;
|
|
15
64
|
const MAP_ASYNC_STATUS_SUCCESS = 1;
|
|
16
65
|
const STYPE_SHADER_SOURCE_WGSL = 0x00000002;
|
|
17
66
|
const PROCESS_EVENTS_TIMEOUT_NS = 5_000_000_000;
|
|
67
|
+
let processEventsTimeoutNs = PROCESS_EVENTS_TIMEOUT_NS;
|
|
68
|
+
const SAMPLER_BINDING_TYPE = Object.freeze({
|
|
69
|
+
filtering: 2,
|
|
70
|
+
"non-filtering": 3,
|
|
71
|
+
comparison: 4,
|
|
72
|
+
});
|
|
73
|
+
const TEXTURE_SAMPLE_TYPE = Object.freeze({
|
|
74
|
+
float: 2,
|
|
75
|
+
"unfilterable-float": 3,
|
|
76
|
+
depth: 4,
|
|
77
|
+
sint: 5,
|
|
78
|
+
uint: 6,
|
|
79
|
+
});
|
|
80
|
+
const TEXTURE_VIEW_DIMENSION = Object.freeze({
|
|
81
|
+
"1d": 1,
|
|
82
|
+
"2d": 2,
|
|
83
|
+
"2d-array": 3,
|
|
84
|
+
cube: 4,
|
|
85
|
+
"cube-array": 5,
|
|
86
|
+
"3d": 6,
|
|
87
|
+
});
|
|
88
|
+
const STORAGE_TEXTURE_ACCESS = Object.freeze({
|
|
89
|
+
"write-only": 2,
|
|
90
|
+
"read-only": 3,
|
|
91
|
+
"read-write": 4,
|
|
92
|
+
});
|
|
18
93
|
|
|
19
94
|
// Struct layout constants for 64-bit platforms (LP64 / LLP64).
|
|
20
95
|
const PTR_SIZE = 8;
|
|
21
96
|
const SIZE_T_SIZE = 8;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
FRAGMENT: 0x2,
|
|
40
|
-
COMPUTE: 0x4,
|
|
41
|
-
},
|
|
42
|
-
GPUMapMode: {
|
|
43
|
-
READ: 0x0001,
|
|
44
|
-
WRITE: 0x0002,
|
|
45
|
-
},
|
|
46
|
-
GPUTextureUsage: {
|
|
47
|
-
COPY_SRC: 0x01,
|
|
48
|
-
COPY_DST: 0x02,
|
|
49
|
-
TEXTURE_BINDING: 0x04,
|
|
50
|
-
STORAGE_BINDING: 0x08,
|
|
51
|
-
RENDER_ATTACHMENT: 0x10,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const DOE_LIMITS = Object.freeze({
|
|
56
|
-
maxTextureDimension1D: 16384,
|
|
57
|
-
maxTextureDimension2D: 16384,
|
|
58
|
-
maxTextureDimension3D: 2048,
|
|
59
|
-
maxTextureArrayLayers: 2048,
|
|
60
|
-
maxBindGroups: 4,
|
|
61
|
-
maxBindGroupsPlusVertexBuffers: 24,
|
|
62
|
-
maxBindingsPerBindGroup: 1000,
|
|
63
|
-
maxDynamicUniformBuffersPerPipelineLayout: 8,
|
|
64
|
-
maxDynamicStorageBuffersPerPipelineLayout: 4,
|
|
65
|
-
maxSampledTexturesPerShaderStage: 16,
|
|
66
|
-
maxSamplersPerShaderStage: 16,
|
|
67
|
-
maxStorageBuffersPerShaderStage: 8,
|
|
68
|
-
maxStorageTexturesPerShaderStage: 4,
|
|
69
|
-
maxUniformBuffersPerShaderStage: 12,
|
|
70
|
-
maxUniformBufferBindingSize: 65536,
|
|
71
|
-
maxStorageBufferBindingSize: 134217728,
|
|
72
|
-
minUniformBufferOffsetAlignment: 256,
|
|
73
|
-
minStorageBufferOffsetAlignment: 32,
|
|
74
|
-
maxVertexBuffers: 8,
|
|
75
|
-
maxBufferSize: 268435456,
|
|
76
|
-
maxVertexAttributes: 16,
|
|
77
|
-
maxVertexBufferArrayStride: 2048,
|
|
78
|
-
maxInterStageShaderVariables: 16,
|
|
79
|
-
maxColorAttachments: 8,
|
|
80
|
-
maxColorAttachmentBytesPerSample: 32,
|
|
81
|
-
maxComputeWorkgroupStorageSize: 32768,
|
|
82
|
-
maxComputeInvocationsPerWorkgroup: 1024,
|
|
83
|
-
maxComputeWorkgroupSizeX: 1024,
|
|
84
|
-
maxComputeWorkgroupSizeY: 1024,
|
|
85
|
-
maxComputeWorkgroupSizeZ: 64,
|
|
86
|
-
maxComputeWorkgroupsPerDimension: 65535,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const DOE_FEATURES = Object.freeze(new Set(["shader-f16"]));
|
|
97
|
+
const WGPU_BUFFER_DESCRIPTOR_SIZE = 48;
|
|
98
|
+
const WGPU_SHADER_SOURCE_WGSL_SIZE = 32;
|
|
99
|
+
const WGPU_SHADER_MODULE_DESCRIPTOR_SIZE = 24;
|
|
100
|
+
const WGPU_COMPUTE_PIPELINE_DESCRIPTOR_SIZE = 80;
|
|
101
|
+
const WGPU_RENDER_PIPELINE_DESCRIPTOR_SIZE = 168;
|
|
102
|
+
const WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_SIZE = 40;
|
|
103
|
+
const WGPU_BIND_GROUP_DESCRIPTOR_SIZE = 48;
|
|
104
|
+
const WGPU_PIPELINE_LAYOUT_DESCRIPTOR_SIZE = 48;
|
|
105
|
+
const WGPU_RENDER_PASS_DESCRIPTOR_SIZE = 64;
|
|
106
|
+
const WGPU_LIMITS_SIZE = 152;
|
|
107
|
+
const WGPU_RENDER_VERTEX_STATE_SIZE = 64;
|
|
108
|
+
const WGPU_RENDER_COLOR_TARGET_STATE_SIZE = 32;
|
|
109
|
+
const WGPU_RENDER_FRAGMENT_STATE_SIZE = 64;
|
|
110
|
+
const WGPU_VERTEX_ATTRIBUTE_SIZE = 32;
|
|
111
|
+
const WGPU_VERTEX_BUFFER_LAYOUT_SIZE = 40;
|
|
112
|
+
const WGPU_DEPTH_STENCIL_STATE_SIZE = 72;
|
|
113
|
+
const WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_SIZE = 48;
|
|
90
114
|
|
|
91
115
|
// ---------------------------------------------------------------------------
|
|
92
116
|
// Library resolution
|
|
@@ -98,8 +122,8 @@ function resolveDoeLibraryPath() {
|
|
|
98
122
|
const ext = LIB_EXT[process.platform] ?? "so";
|
|
99
123
|
const candidates = [
|
|
100
124
|
process.env.DOE_WEBGPU_LIB,
|
|
101
|
-
resolve(PACKAGE_ROOT, "prebuilds", `${process.platform}-${process.arch}`, `libwebgpu_doe.${ext}`),
|
|
102
125
|
resolve(PACKAGE_ROOT, "..", "..", "zig", "zig-out", "lib", `libwebgpu_doe.${ext}`),
|
|
126
|
+
resolve(PACKAGE_ROOT, "prebuilds", `${process.platform}-${process.arch}`, `libwebgpu_doe.${ext}`),
|
|
103
127
|
resolve(process.cwd(), "zig", "zig-out", "lib", `libwebgpu_doe.${ext}`),
|
|
104
128
|
];
|
|
105
129
|
for (const c of candidates) {
|
|
@@ -131,8 +155,16 @@ function openLibrary(path) {
|
|
|
131
155
|
// Adapter/Device (flat helpers)
|
|
132
156
|
doeRequestAdapterFlat: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.u64 },
|
|
133
157
|
doeRequestDeviceFlat: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.u64 },
|
|
158
|
+
doeNativeAdapterHasFeature: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.u32 },
|
|
159
|
+
doeNativeAdapterGetLimits: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.u32 },
|
|
160
|
+
doeNativeDeviceHasFeature: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.u32 },
|
|
161
|
+
doeNativeDeviceGetLimits: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.u32 },
|
|
134
162
|
wgpuAdapterRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
163
|
+
wgpuAdapterHasFeature: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.u32 },
|
|
164
|
+
wgpuAdapterGetLimits: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.u32 },
|
|
135
165
|
wgpuDeviceRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
166
|
+
wgpuDeviceHasFeature: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.u32 },
|
|
167
|
+
wgpuDeviceGetLimits: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.u32 },
|
|
136
168
|
wgpuDeviceGetQueue: { args: [FFIType.ptr], returns: FFIType.ptr },
|
|
137
169
|
|
|
138
170
|
// Buffer
|
|
@@ -153,6 +185,7 @@ function openLibrary(path) {
|
|
|
153
185
|
// Shader
|
|
154
186
|
wgpuDeviceCreateShaderModule: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
|
|
155
187
|
wgpuShaderModuleRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
188
|
+
doeNativeShaderModuleGetBindings: { args: [FFIType.ptr, FFIType.ptr, FFIType.u64], returns: FFIType.u64 },
|
|
156
189
|
|
|
157
190
|
// Compute pipeline
|
|
158
191
|
wgpuDeviceCreateComputePipeline: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
|
|
@@ -172,6 +205,8 @@ function openLibrary(path) {
|
|
|
172
205
|
wgpuCommandEncoderRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
173
206
|
wgpuCommandEncoderBeginComputePass: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
|
|
174
207
|
wgpuCommandEncoderCopyBufferToBuffer: { args: [FFIType.ptr, FFIType.ptr, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.u64], returns: FFIType.void },
|
|
208
|
+
wgpuCommandEncoderCopyTextureToBuffer: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.void },
|
|
209
|
+
doeNativeCommandEncoderCopyTextureToBuffer: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.u64, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.u32], returns: FFIType.void },
|
|
175
210
|
wgpuCommandEncoderFinish: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
|
|
176
211
|
wgpuCommandBufferRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
177
212
|
|
|
@@ -200,7 +235,11 @@ function openLibrary(path) {
|
|
|
200
235
|
// Render pass
|
|
201
236
|
wgpuCommandEncoderBeginRenderPass: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
|
|
202
237
|
wgpuRenderPassEncoderSetPipeline: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.void },
|
|
238
|
+
wgpuRenderPassEncoderSetBindGroup: { args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.u64, FFIType.ptr], returns: FFIType.void },
|
|
239
|
+
wgpuRenderPassEncoderSetVertexBuffer: { args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.u64, FFIType.u64], returns: FFIType.void },
|
|
240
|
+
wgpuRenderPassEncoderSetIndexBuffer: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.u64, FFIType.u64], returns: FFIType.void },
|
|
203
241
|
wgpuRenderPassEncoderDraw: { args: [FFIType.ptr, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.u32], returns: FFIType.void },
|
|
242
|
+
wgpuRenderPassEncoderDrawIndexed: { args: [FFIType.ptr, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.i32, FFIType.u32], returns: FFIType.void },
|
|
204
243
|
wgpuRenderPassEncoderEnd: { args: [FFIType.ptr], returns: FFIType.void },
|
|
205
244
|
wgpuRenderPassEncoderRelease: { args: [FFIType.ptr], returns: FFIType.void },
|
|
206
245
|
};
|
|
@@ -209,6 +248,67 @@ function openLibrary(path) {
|
|
|
209
248
|
args: [FFIType.ptr, FFIType.u32],
|
|
210
249
|
returns: FFIType.ptr,
|
|
211
250
|
};
|
|
251
|
+
symbols.doeNativeCheckShaderSource = {
|
|
252
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
253
|
+
returns: FFIType.u32,
|
|
254
|
+
};
|
|
255
|
+
symbols.doeNativeCopyLastErrorMessage = {
|
|
256
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
257
|
+
returns: FFIType.u64,
|
|
258
|
+
};
|
|
259
|
+
symbols.doeNativeCopyLastErrorStage = {
|
|
260
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
261
|
+
returns: FFIType.u64,
|
|
262
|
+
};
|
|
263
|
+
symbols.doeNativeCopyLastErrorKind = {
|
|
264
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
265
|
+
returns: FFIType.u64,
|
|
266
|
+
};
|
|
267
|
+
symbols.doeNativeGetLastErrorLine = {
|
|
268
|
+
args: [],
|
|
269
|
+
returns: FFIType.u32,
|
|
270
|
+
};
|
|
271
|
+
symbols.doeNativeGetLastErrorColumn = {
|
|
272
|
+
args: [],
|
|
273
|
+
returns: FFIType.u32,
|
|
274
|
+
};
|
|
275
|
+
symbols.doeNativeDeviceCreateQuerySet = {
|
|
276
|
+
args: [FFIType.ptr, FFIType.u32, FFIType.u32],
|
|
277
|
+
returns: FFIType.ptr,
|
|
278
|
+
};
|
|
279
|
+
symbols.doeNativeCommandEncoderWriteTimestamp = {
|
|
280
|
+
args: [FFIType.ptr, FFIType.ptr, FFIType.u32],
|
|
281
|
+
returns: FFIType.void,
|
|
282
|
+
};
|
|
283
|
+
symbols.doeNativeCommandEncoderResolveQuerySet = {
|
|
284
|
+
args: [FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.u32, FFIType.ptr, FFIType.u64],
|
|
285
|
+
returns: FFIType.void,
|
|
286
|
+
};
|
|
287
|
+
symbols.doeNativeQuerySetDestroy = {
|
|
288
|
+
args: [FFIType.ptr],
|
|
289
|
+
returns: FFIType.void,
|
|
290
|
+
};
|
|
291
|
+
symbols.doeNativeQueueFlush = {
|
|
292
|
+
args: [FFIType.ptr],
|
|
293
|
+
returns: FFIType.void,
|
|
294
|
+
};
|
|
295
|
+
symbols.doeNativeComputeDispatchFlush = {
|
|
296
|
+
args: [
|
|
297
|
+
FFIType.ptr, // queue
|
|
298
|
+
FFIType.ptr, // pipeline
|
|
299
|
+
FFIType.ptr, // bindGroups (ptr array)
|
|
300
|
+
FFIType.u32, // bgCount
|
|
301
|
+
FFIType.u32, // x
|
|
302
|
+
FFIType.u32, // y
|
|
303
|
+
FFIType.u32, // z
|
|
304
|
+
FFIType.ptr, // copySrc
|
|
305
|
+
FFIType.u64, // copySrcOff
|
|
306
|
+
FFIType.ptr, // copyDst
|
|
307
|
+
FFIType.u64, // copyDstOff
|
|
308
|
+
FFIType.u64, // copySize
|
|
309
|
+
],
|
|
310
|
+
returns: FFIType.void,
|
|
311
|
+
};
|
|
212
312
|
}
|
|
213
313
|
return dlopen(path, symbols);
|
|
214
314
|
}
|
|
@@ -221,6 +321,194 @@ function openLibrary(path) {
|
|
|
221
321
|
// ---------------------------------------------------------------------------
|
|
222
322
|
|
|
223
323
|
const encoder = new TextEncoder();
|
|
324
|
+
const decoder = new TextDecoder();
|
|
325
|
+
|
|
326
|
+
const LIMIT_OFFSETS = Object.freeze({
|
|
327
|
+
maxTextureDimension1D: 8,
|
|
328
|
+
maxTextureDimension2D: 12,
|
|
329
|
+
maxTextureDimension3D: 16,
|
|
330
|
+
maxTextureArrayLayers: 20,
|
|
331
|
+
maxBindGroups: 24,
|
|
332
|
+
maxBindGroupsPlusVertexBuffers: 28,
|
|
333
|
+
maxBindingsPerBindGroup: 32,
|
|
334
|
+
maxDynamicUniformBuffersPerPipelineLayout: 36,
|
|
335
|
+
maxDynamicStorageBuffersPerPipelineLayout: 40,
|
|
336
|
+
maxSampledTexturesPerShaderStage: 44,
|
|
337
|
+
maxSamplersPerShaderStage: 48,
|
|
338
|
+
maxStorageBuffersPerShaderStage: 52,
|
|
339
|
+
maxStorageTexturesPerShaderStage: 56,
|
|
340
|
+
maxUniformBuffersPerShaderStage: 60,
|
|
341
|
+
maxUniformBufferBindingSize: 64,
|
|
342
|
+
maxStorageBufferBindingSize: 72,
|
|
343
|
+
minUniformBufferOffsetAlignment: 80,
|
|
344
|
+
minStorageBufferOffsetAlignment: 84,
|
|
345
|
+
maxVertexBuffers: 88,
|
|
346
|
+
maxBufferSize: 96,
|
|
347
|
+
maxVertexAttributes: 104,
|
|
348
|
+
maxVertexBufferArrayStride: 108,
|
|
349
|
+
maxInterStageShaderVariables: 112,
|
|
350
|
+
maxColorAttachments: 116,
|
|
351
|
+
maxColorAttachmentBytesPerSample: 120,
|
|
352
|
+
maxComputeWorkgroupStorageSize: 124,
|
|
353
|
+
maxComputeInvocationsPerWorkgroup: 128,
|
|
354
|
+
maxComputeWorkgroupSizeX: 132,
|
|
355
|
+
maxComputeWorkgroupSizeY: 136,
|
|
356
|
+
maxComputeWorkgroupSizeZ: 140,
|
|
357
|
+
maxComputeWorkgroupsPerDimension: 144,
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
function copyLastErrorMessage() {
|
|
361
|
+
const fn = wgpu?.symbols?.doeNativeCopyLastErrorMessage;
|
|
362
|
+
if (typeof fn !== "function") return "";
|
|
363
|
+
const buf = new Uint8Array(4096);
|
|
364
|
+
const len = Number(fn(buf, BigInt(buf.length)));
|
|
365
|
+
if (len <= 1) return "";
|
|
366
|
+
return decoder.decode(buf.subarray(0, Math.max(0, len - 1)));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function decodeLimits(raw) {
|
|
370
|
+
const view = new DataView(raw);
|
|
371
|
+
return Object.freeze({
|
|
372
|
+
maxTextureDimension1D: view.getUint32(LIMIT_OFFSETS.maxTextureDimension1D, true),
|
|
373
|
+
maxTextureDimension2D: view.getUint32(LIMIT_OFFSETS.maxTextureDimension2D, true),
|
|
374
|
+
maxTextureDimension3D: view.getUint32(LIMIT_OFFSETS.maxTextureDimension3D, true),
|
|
375
|
+
maxTextureArrayLayers: view.getUint32(LIMIT_OFFSETS.maxTextureArrayLayers, true),
|
|
376
|
+
maxBindGroups: view.getUint32(LIMIT_OFFSETS.maxBindGroups, true),
|
|
377
|
+
maxBindGroupsPlusVertexBuffers: view.getUint32(LIMIT_OFFSETS.maxBindGroupsPlusVertexBuffers, true),
|
|
378
|
+
maxBindingsPerBindGroup: view.getUint32(LIMIT_OFFSETS.maxBindingsPerBindGroup, true),
|
|
379
|
+
maxDynamicUniformBuffersPerPipelineLayout: view.getUint32(LIMIT_OFFSETS.maxDynamicUniformBuffersPerPipelineLayout, true),
|
|
380
|
+
maxDynamicStorageBuffersPerPipelineLayout: view.getUint32(LIMIT_OFFSETS.maxDynamicStorageBuffersPerPipelineLayout, true),
|
|
381
|
+
maxSampledTexturesPerShaderStage: view.getUint32(LIMIT_OFFSETS.maxSampledTexturesPerShaderStage, true),
|
|
382
|
+
maxSamplersPerShaderStage: view.getUint32(LIMIT_OFFSETS.maxSamplersPerShaderStage, true),
|
|
383
|
+
maxStorageBuffersPerShaderStage: view.getUint32(LIMIT_OFFSETS.maxStorageBuffersPerShaderStage, true),
|
|
384
|
+
maxStorageTexturesPerShaderStage: view.getUint32(LIMIT_OFFSETS.maxStorageTexturesPerShaderStage, true),
|
|
385
|
+
maxUniformBuffersPerShaderStage: view.getUint32(LIMIT_OFFSETS.maxUniformBuffersPerShaderStage, true),
|
|
386
|
+
maxUniformBufferBindingSize: Number(view.getBigUint64(LIMIT_OFFSETS.maxUniformBufferBindingSize, true)),
|
|
387
|
+
maxStorageBufferBindingSize: Number(view.getBigUint64(LIMIT_OFFSETS.maxStorageBufferBindingSize, true)),
|
|
388
|
+
minUniformBufferOffsetAlignment: view.getUint32(LIMIT_OFFSETS.minUniformBufferOffsetAlignment, true),
|
|
389
|
+
minStorageBufferOffsetAlignment: view.getUint32(LIMIT_OFFSETS.minStorageBufferOffsetAlignment, true),
|
|
390
|
+
maxVertexBuffers: view.getUint32(LIMIT_OFFSETS.maxVertexBuffers, true),
|
|
391
|
+
maxBufferSize: Number(view.getBigUint64(LIMIT_OFFSETS.maxBufferSize, true)),
|
|
392
|
+
maxVertexAttributes: view.getUint32(LIMIT_OFFSETS.maxVertexAttributes, true),
|
|
393
|
+
maxVertexBufferArrayStride: view.getUint32(LIMIT_OFFSETS.maxVertexBufferArrayStride, true),
|
|
394
|
+
maxInterStageShaderVariables: view.getUint32(LIMIT_OFFSETS.maxInterStageShaderVariables, true),
|
|
395
|
+
maxColorAttachments: view.getUint32(LIMIT_OFFSETS.maxColorAttachments, true),
|
|
396
|
+
maxColorAttachmentBytesPerSample: view.getUint32(LIMIT_OFFSETS.maxColorAttachmentBytesPerSample, true),
|
|
397
|
+
maxComputeWorkgroupStorageSize: view.getUint32(LIMIT_OFFSETS.maxComputeWorkgroupStorageSize, true),
|
|
398
|
+
maxComputeInvocationsPerWorkgroup: view.getUint32(LIMIT_OFFSETS.maxComputeInvocationsPerWorkgroup, true),
|
|
399
|
+
maxComputeWorkgroupSizeX: view.getUint32(LIMIT_OFFSETS.maxComputeWorkgroupSizeX, true),
|
|
400
|
+
maxComputeWorkgroupSizeY: view.getUint32(LIMIT_OFFSETS.maxComputeWorkgroupSizeY, true),
|
|
401
|
+
maxComputeWorkgroupSizeZ: view.getUint32(LIMIT_OFFSETS.maxComputeWorkgroupSizeZ, true),
|
|
402
|
+
maxComputeWorkgroupsPerDimension: view.getUint32(LIMIT_OFFSETS.maxComputeWorkgroupsPerDimension, true),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function queryLimits(handle, fnName) {
|
|
407
|
+
const fn = wgpu?.symbols?.[fnName];
|
|
408
|
+
if (typeof fn !== "function" || !handle) return publishLimits(null);
|
|
409
|
+
const raw = new ArrayBuffer(WGPU_LIMITS_SIZE);
|
|
410
|
+
const status = Number(fn(handle, new Uint8Array(raw)));
|
|
411
|
+
if (status !== WGPU_STATUS_SUCCESS) return publishLimits(null);
|
|
412
|
+
return publishLimits(decodeLimits(raw));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function queryLimitsByPreference(handle, fnNames) {
|
|
416
|
+
for (const fnName of fnNames) {
|
|
417
|
+
const fn = wgpu?.symbols?.[fnName];
|
|
418
|
+
if (typeof fn !== "function" || !handle) continue;
|
|
419
|
+
const raw = new ArrayBuffer(WGPU_LIMITS_SIZE);
|
|
420
|
+
const status = Number(fn(handle, new Uint8Array(raw)));
|
|
421
|
+
if (status !== WGPU_STATUS_SUCCESS) continue;
|
|
422
|
+
return publishLimits(decodeLimits(raw));
|
|
423
|
+
}
|
|
424
|
+
return publishLimits(null);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function adapterLimits(handle) {
|
|
428
|
+
return queryLimitsByPreference(handle, ["doeNativeAdapterGetLimits", "wgpuAdapterGetLimits"]);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function deviceLimits(handle) {
|
|
432
|
+
return queryLimitsByPreference(handle, ["doeNativeDeviceGetLimits", "wgpuDeviceGetLimits"]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function adapterFeatures(handle) {
|
|
436
|
+
const fn = wgpu?.symbols?.doeNativeAdapterHasFeature ?? wgpu?.symbols?.wgpuAdapterHasFeature;
|
|
437
|
+
return publishFeatures(
|
|
438
|
+
typeof fn === "function" && handle
|
|
439
|
+
? (feature) => Number(fn(handle, feature)) !== 0
|
|
440
|
+
: null,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function deviceFeatures(handle) {
|
|
445
|
+
const fn = wgpu?.symbols?.doeNativeDeviceHasFeature ?? wgpu?.symbols?.wgpuDeviceHasFeature;
|
|
446
|
+
return publishFeatures(
|
|
447
|
+
typeof fn === "function" && handle
|
|
448
|
+
? (feature) => Number(fn(handle, feature)) !== 0
|
|
449
|
+
: null,
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function copyNativeErrorMeta(symbolName) {
|
|
454
|
+
const fn = wgpu?.symbols?.[symbolName];
|
|
455
|
+
if (typeof fn !== "function") return "";
|
|
456
|
+
const scratch = new Uint8Array(256);
|
|
457
|
+
const len = Number(fn(scratch, scratch.length));
|
|
458
|
+
if (!len) return "";
|
|
459
|
+
return decoder.decode(scratch.subarray(0, Math.min(len, scratch.length - 1)));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const fastPathStats = { dispatchFlush: 0, flushAndMap: 0 };
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Read structured error fields (stage, kind, line, column) from the native
|
|
466
|
+
* last-error ABI. Uses `doeNativeGetLastErrorLine` / `doeNativeGetLastErrorColumn`
|
|
467
|
+
* when available; falls back to string copy functions for stage/kind.
|
|
468
|
+
* Returns null when the native symbols are absent (pre-structured-error builds).
|
|
469
|
+
*/
|
|
470
|
+
function readLastErrorFields() {
|
|
471
|
+
const stageFn = wgpu?.symbols?.doeNativeCopyLastErrorStage;
|
|
472
|
+
const kindFn = wgpu?.symbols?.doeNativeCopyLastErrorKind;
|
|
473
|
+
if (typeof stageFn !== "function" && typeof kindFn !== "function") return null;
|
|
474
|
+
const stage = copyNativeErrorMeta("doeNativeCopyLastErrorStage");
|
|
475
|
+
const kind = copyNativeErrorMeta("doeNativeCopyLastErrorKind");
|
|
476
|
+
const lineFn = wgpu?.symbols?.doeNativeGetLastErrorLine;
|
|
477
|
+
const colFn = wgpu?.symbols?.doeNativeGetLastErrorColumn;
|
|
478
|
+
const line = typeof lineFn === "function" ? Number(lineFn()) : 0;
|
|
479
|
+
const column = typeof colFn === "function" ? Number(colFn()) : 0;
|
|
480
|
+
return {
|
|
481
|
+
stage: stage || undefined,
|
|
482
|
+
kind: kind || undefined,
|
|
483
|
+
line: line > 0 ? line : undefined,
|
|
484
|
+
column: column > 0 ? column : undefined,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function preflightShaderSource(code) {
|
|
489
|
+
const fn = wgpu?.symbols?.doeNativeCheckShaderSource;
|
|
490
|
+
if (typeof fn !== "function") {
|
|
491
|
+
return { ok: true, stage: "", kind: "", message: "", reasons: [] };
|
|
492
|
+
}
|
|
493
|
+
const codeBytes = encoder.encode(code);
|
|
494
|
+
const ok = Number(fn(codeBytes, codeBytes.length)) !== 0;
|
|
495
|
+
if (ok) return { ok: true, stage: "", kind: "", message: "", reasons: [] };
|
|
496
|
+
const message = copyNativeErrorMeta("doeNativeCopyLastErrorMessage");
|
|
497
|
+
const lineFn = wgpu?.symbols?.doeNativeGetLastErrorLine;
|
|
498
|
+
const colFn = wgpu?.symbols?.doeNativeGetLastErrorColumn;
|
|
499
|
+
const line = typeof lineFn === "function" ? Number(lineFn()) : 0;
|
|
500
|
+
const column = typeof colFn === "function" ? Number(colFn()) : 0;
|
|
501
|
+
const out = {
|
|
502
|
+
ok: false,
|
|
503
|
+
stage: copyNativeErrorMeta("doeNativeCopyLastErrorStage"),
|
|
504
|
+
kind: copyNativeErrorMeta("doeNativeCopyLastErrorKind"),
|
|
505
|
+
message,
|
|
506
|
+
reasons: message ? [message] : [],
|
|
507
|
+
};
|
|
508
|
+
if (line > 0) out.line = line;
|
|
509
|
+
if (column > 0) out.column = column;
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
224
512
|
|
|
225
513
|
function writeStringView(view, offset, strBytes) {
|
|
226
514
|
if (strBytes) {
|
|
@@ -238,7 +526,7 @@ function writePtr(view, offset, ptr) {
|
|
|
238
526
|
|
|
239
527
|
// WGPUBufferDescriptor: { nextInChain:ptr@0, label:sv@8, usage:u64@24, size:u64@32, mappedAtCreation:u32@40 } = 48
|
|
240
528
|
function buildBufferDescriptor(descriptor) {
|
|
241
|
-
const buf = new ArrayBuffer(
|
|
529
|
+
const buf = new ArrayBuffer(WGPU_BUFFER_DESCRIPTOR_SIZE);
|
|
242
530
|
const v = new DataView(buf);
|
|
243
531
|
// nextInChain = null
|
|
244
532
|
writePtr(v, 0, null);
|
|
@@ -258,14 +546,14 @@ function buildBufferDescriptor(descriptor) {
|
|
|
258
546
|
function buildShaderModuleDescriptor(code) {
|
|
259
547
|
const codeBytes = encoder.encode(code);
|
|
260
548
|
|
|
261
|
-
const wgslBuf = new ArrayBuffer(
|
|
549
|
+
const wgslBuf = new ArrayBuffer(WGPU_SHADER_SOURCE_WGSL_SIZE);
|
|
262
550
|
const wgslView = new DataView(wgslBuf);
|
|
263
551
|
writePtr(wgslView, 0, null);
|
|
264
552
|
wgslView.setUint32(8, STYPE_SHADER_SOURCE_WGSL, true);
|
|
265
553
|
writeStringView(wgslView, 16, codeBytes);
|
|
266
554
|
const wgslArr = new Uint8Array(wgslBuf);
|
|
267
555
|
|
|
268
|
-
const descBuf = new ArrayBuffer(
|
|
556
|
+
const descBuf = new ArrayBuffer(WGPU_SHADER_MODULE_DESCRIPTOR_SIZE);
|
|
269
557
|
const descView = new DataView(descBuf);
|
|
270
558
|
writePtr(descView, 0, bunPtr(wgslArr));
|
|
271
559
|
writeStringView(descView, 8, null);
|
|
@@ -279,7 +567,7 @@ function buildShaderModuleDescriptor(code) {
|
|
|
279
567
|
// Total descriptor: 24 + 8 (layout) + 48 (compute) = 80
|
|
280
568
|
function buildComputePipelineDescriptor(shaderModulePtr, entryPoint, layoutPtr) {
|
|
281
569
|
const epBytes = encoder.encode(entryPoint);
|
|
282
|
-
const buf = new ArrayBuffer(
|
|
570
|
+
const buf = new ArrayBuffer(WGPU_COMPUTE_PIPELINE_DESCRIPTOR_SIZE);
|
|
283
571
|
const v = new DataView(buf);
|
|
284
572
|
// nextInChain
|
|
285
573
|
writePtr(v, 0, null);
|
|
@@ -300,6 +588,113 @@ function buildComputePipelineDescriptor(shaderModulePtr, entryPoint, layoutPtr)
|
|
|
300
588
|
return { desc: new Uint8Array(buf), _refs: [epBytes] };
|
|
301
589
|
}
|
|
302
590
|
|
|
591
|
+
function buildRenderPipelineDescriptor(descriptor) {
|
|
592
|
+
const vertexEntryBytes = encoder.encode(descriptor.vertexEntryPoint);
|
|
593
|
+
const fragmentEntryBytes = encoder.encode(descriptor.fragmentEntryPoint);
|
|
594
|
+
const vertexBuffers = descriptor.vertexBuffers ?? [];
|
|
595
|
+
|
|
596
|
+
const colorTargetBuf = new ArrayBuffer(WGPU_RENDER_COLOR_TARGET_STATE_SIZE);
|
|
597
|
+
const colorTargetView = new DataView(colorTargetBuf);
|
|
598
|
+
writePtr(colorTargetView, 0, null);
|
|
599
|
+
colorTargetView.setUint32(8, TEXTURE_FORMAT_MAP[descriptor.colorFormat] ?? 0x00000016, true);
|
|
600
|
+
writePtr(colorTargetView, 16, null);
|
|
601
|
+
colorTargetView.setBigUint64(24, 0xFn, true);
|
|
602
|
+
const colorTargetArr = new Uint8Array(colorTargetBuf);
|
|
603
|
+
|
|
604
|
+
const fragmentBuf = new ArrayBuffer(WGPU_RENDER_FRAGMENT_STATE_SIZE);
|
|
605
|
+
const fragmentView = new DataView(fragmentBuf);
|
|
606
|
+
writePtr(fragmentView, 0, null);
|
|
607
|
+
writePtr(fragmentView, 8, descriptor.fragmentModule);
|
|
608
|
+
writeStringView(fragmentView, 16, fragmentEntryBytes);
|
|
609
|
+
fragmentView.setBigUint64(32, 0n, true);
|
|
610
|
+
writePtr(fragmentView, 40, null);
|
|
611
|
+
fragmentView.setBigUint64(48, 1n, true);
|
|
612
|
+
writePtr(fragmentView, 56, bunPtr(colorTargetArr));
|
|
613
|
+
const fragmentArr = new Uint8Array(fragmentBuf);
|
|
614
|
+
|
|
615
|
+
let vertexAttributeArr = null;
|
|
616
|
+
let vertexBufferArr = null;
|
|
617
|
+
if (vertexBuffers.length > 0) {
|
|
618
|
+
let totalAttributeCount = 0;
|
|
619
|
+
for (const buffer of vertexBuffers) {
|
|
620
|
+
totalAttributeCount += (buffer.attributes ?? []).length;
|
|
621
|
+
}
|
|
622
|
+
vertexAttributeArr = new Uint8Array(totalAttributeCount * WGPU_VERTEX_ATTRIBUTE_SIZE);
|
|
623
|
+
vertexBufferArr = new Uint8Array(vertexBuffers.length * WGPU_VERTEX_BUFFER_LAYOUT_SIZE);
|
|
624
|
+
const attrView = new DataView(vertexAttributeArr.buffer);
|
|
625
|
+
const layoutView = new DataView(vertexBufferArr.buffer);
|
|
626
|
+
let attrIndex = 0;
|
|
627
|
+
for (let bufferIndex = 0; bufferIndex < vertexBuffers.length; bufferIndex += 1) {
|
|
628
|
+
const buffer = vertexBuffers[bufferIndex] ?? {};
|
|
629
|
+
const attributes = buffer.attributes ?? [];
|
|
630
|
+
const layoutOffset = bufferIndex * WGPU_VERTEX_BUFFER_LAYOUT_SIZE;
|
|
631
|
+
writePtr(layoutView, layoutOffset + 0, null);
|
|
632
|
+
layoutView.setUint32(layoutOffset + 8, VERTEX_STEP_MODE_MAP[buffer.stepMode ?? "vertex"] ?? VERTEX_STEP_MODE_MAP.vertex, true);
|
|
633
|
+
layoutView.setBigUint64(layoutOffset + 16, BigInt(buffer.arrayStride ?? 0), true);
|
|
634
|
+
layoutView.setBigUint64(layoutOffset + 24, BigInt(attributes.length), true);
|
|
635
|
+
writePtr(layoutView, layoutOffset + 32, attributes.length > 0 ? bunPtr(vertexAttributeArr) + attrIndex * WGPU_VERTEX_ATTRIBUTE_SIZE : null);
|
|
636
|
+
for (const attribute of attributes) {
|
|
637
|
+
const attrOffset = attrIndex * WGPU_VERTEX_ATTRIBUTE_SIZE;
|
|
638
|
+
writePtr(attrView, attrOffset + 0, null);
|
|
639
|
+
attrView.setUint32(attrOffset + 8, VERTEX_FORMAT_MAP[attribute.format] ?? 0, true);
|
|
640
|
+
attrView.setBigUint64(attrOffset + 16, BigInt(attribute.offset ?? 0), true);
|
|
641
|
+
attrView.setUint32(attrOffset + 24, attribute.shaderLocation ?? 0, true);
|
|
642
|
+
attrIndex += 1;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
let depthStencilArr = null;
|
|
648
|
+
if (descriptor.depthStencil) {
|
|
649
|
+
const depthStencilBuf = new ArrayBuffer(WGPU_DEPTH_STENCIL_STATE_SIZE);
|
|
650
|
+
const depthStencilView = new DataView(depthStencilBuf);
|
|
651
|
+
writePtr(depthStencilView, 0, null);
|
|
652
|
+
depthStencilView.setUint32(8, TEXTURE_FORMAT_MAP[descriptor.depthStencil.format] ?? TEXTURE_FORMAT_MAP.depth32float, true);
|
|
653
|
+
depthStencilView.setUint32(12, descriptor.depthStencil.depthWriteEnabled ? 1 : 0, true);
|
|
654
|
+
depthStencilView.setUint32(16, COMPARE_FUNC_MAP[descriptor.depthStencil.depthCompare ?? "always"] ?? COMPARE_FUNC_MAP.always, true);
|
|
655
|
+
depthStencilView.setUint32(48, 0xFFFFFFFF, true);
|
|
656
|
+
depthStencilView.setUint32(52, 0xFFFFFFFF, true);
|
|
657
|
+
depthStencilArr = new Uint8Array(depthStencilBuf);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const primitive = descriptor.primitive ?? {};
|
|
661
|
+
const multisample = descriptor.multisample ?? {};
|
|
662
|
+
const buf = new ArrayBuffer(WGPU_RENDER_PIPELINE_DESCRIPTOR_SIZE);
|
|
663
|
+
const view = new DataView(buf);
|
|
664
|
+
writePtr(view, 0, null);
|
|
665
|
+
writeStringView(view, 8, null);
|
|
666
|
+
writePtr(view, 24, descriptor.layout);
|
|
667
|
+
writePtr(view, 32, null);
|
|
668
|
+
writePtr(view, 40, descriptor.vertexModule);
|
|
669
|
+
writeStringView(view, 48, vertexEntryBytes);
|
|
670
|
+
view.setBigUint64(64, 0n, true);
|
|
671
|
+
writePtr(view, 72, null);
|
|
672
|
+
view.setBigUint64(80, BigInt(vertexBuffers.length), true);
|
|
673
|
+
writePtr(view, 88, vertexBuffers.length > 0 ? bunPtr(vertexBufferArr) : null);
|
|
674
|
+
writePtr(view, 96, null);
|
|
675
|
+
view.setUint32(104, {
|
|
676
|
+
"point-list": 0x00000001,
|
|
677
|
+
"line-list": 0x00000002,
|
|
678
|
+
"line-strip": 0x00000003,
|
|
679
|
+
"triangle-list": 0x00000004,
|
|
680
|
+
"triangle-strip": 0x00000005,
|
|
681
|
+
}[primitive.topology ?? "triangle-list"] ?? 0x00000004, true);
|
|
682
|
+
view.setUint32(108, 0, true);
|
|
683
|
+
view.setUint32(112, { ccw: 0x00000001, cw: 0x00000002 }[primitive.frontFace ?? "ccw"] ?? 0x00000001, true);
|
|
684
|
+
view.setUint32(116, { none: 0x00000001, front: 0x00000002, back: 0x00000003 }[primitive.cullMode ?? "none"] ?? 0x00000001, true);
|
|
685
|
+
view.setUint32(120, primitive.unclippedDepth ? 1 : 0, true);
|
|
686
|
+
writePtr(view, 128, depthStencilArr ? bunPtr(depthStencilArr) : null);
|
|
687
|
+
writePtr(view, 136, null);
|
|
688
|
+
view.setUint32(144, multisample.count ?? 1, true);
|
|
689
|
+
view.setUint32(148, multisample.mask ?? 0xFFFF_FFFF, true);
|
|
690
|
+
view.setUint32(152, multisample.alphaToCoverageEnabled ? 1 : 0, true);
|
|
691
|
+
writePtr(view, 160, bunPtr(fragmentArr));
|
|
692
|
+
return {
|
|
693
|
+
desc: new Uint8Array(buf),
|
|
694
|
+
_refs: [vertexEntryBytes, fragmentEntryBytes, colorTargetArr, fragmentArr, vertexAttributeArr, vertexBufferArr, depthStencilArr].filter(Boolean),
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
303
698
|
// WGPUBindGroupLayoutEntry: { nextInChain:ptr@0, binding:u32@8, visibility:u64@12(actually u32@12 + pad), ...complex }
|
|
304
699
|
// The full entry is large. We build a minimal version matching what doe_napi.c marshals.
|
|
305
700
|
// For simplicity, we build the entry array matching the C struct layout.
|
|
@@ -342,11 +737,26 @@ function buildBindGroupLayoutDescriptor(entries) {
|
|
|
342
737
|
// buffer.minBindingSize: u64@48
|
|
343
738
|
entryView.setBigUint64(off + 48, BigInt(e.buffer.minBindingSize || 0), true);
|
|
344
739
|
}
|
|
345
|
-
|
|
740
|
+
if (e.sampler) {
|
|
741
|
+
writePtr(entryView, off + 56, null);
|
|
742
|
+
entryView.setUint32(off + 64, SAMPLER_BINDING_TYPE[e.sampler.type] || 2, true);
|
|
743
|
+
}
|
|
744
|
+
if (e.texture) {
|
|
745
|
+
writePtr(entryView, off + 72, null);
|
|
746
|
+
entryView.setUint32(off + 80, TEXTURE_SAMPLE_TYPE[e.texture.sampleType] || 2, true);
|
|
747
|
+
entryView.setUint32(off + 84, TEXTURE_VIEW_DIMENSION[e.texture.viewDimension] || 2, true);
|
|
748
|
+
entryView.setUint32(off + 88, e.texture.multisampled ? 1 : 0, true);
|
|
749
|
+
}
|
|
750
|
+
if (e.storageTexture) {
|
|
751
|
+
writePtr(entryView, off + 96, null);
|
|
752
|
+
entryView.setUint32(off + 104, STORAGE_TEXTURE_ACCESS[e.storageTexture.access] || 2, true);
|
|
753
|
+
entryView.setUint32(off + 108, TEXTURE_FORMATS[e.storageTexture.format] || 18, true);
|
|
754
|
+
entryView.setUint32(off + 112, TEXTURE_VIEW_DIMENSION[e.storageTexture.viewDimension] || 2, true);
|
|
755
|
+
}
|
|
346
756
|
}
|
|
347
757
|
|
|
348
758
|
// WGPUBindGroupLayoutDescriptor: { nextInChain:ptr@0, label:sv@8, entryCount:size_t@24, entries:ptr@32 } = 40
|
|
349
|
-
const descBuf = new ArrayBuffer(
|
|
759
|
+
const descBuf = new ArrayBuffer(WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_SIZE);
|
|
350
760
|
const descView = new DataView(descBuf);
|
|
351
761
|
writePtr(descView, 0, null);
|
|
352
762
|
writeStringView(descView, 8, null);
|
|
@@ -370,16 +780,16 @@ function buildBindGroupDescriptor(layoutPtr, entries) {
|
|
|
370
780
|
const off = i * BIND_GROUP_ENTRY_SIZE;
|
|
371
781
|
writePtr(entryView, off + 0, null);
|
|
372
782
|
entryView.setUint32(off + 8, e.binding, true);
|
|
373
|
-
const bufferPtr = e.resource?.buffer
|
|
783
|
+
const bufferPtr = e.resource?.buffer ?? null;
|
|
374
784
|
writePtr(entryView, off + 16, bufferPtr);
|
|
375
785
|
entryView.setBigUint64(off + 24, BigInt(e.resource?.offset ?? 0), true);
|
|
376
786
|
entryView.setBigUint64(off + 32, e.resource?.size !== undefined ? BigInt(e.resource.size) : WHOLE_SIZE, true);
|
|
377
|
-
writePtr(entryView, off + 40, null);
|
|
378
|
-
writePtr(entryView, off + 48, null);
|
|
787
|
+
writePtr(entryView, off + 40, e.resource?.sampler ?? null);
|
|
788
|
+
writePtr(entryView, off + 48, e.resource?.textureView ?? null);
|
|
379
789
|
}
|
|
380
790
|
|
|
381
791
|
// WGPUBindGroupDescriptor: { nextInChain:ptr@0, label:sv@8, layout:ptr@24, entryCount:size_t@32, entries:ptr@40 } = 48
|
|
382
|
-
const descBuf = new ArrayBuffer(
|
|
792
|
+
const descBuf = new ArrayBuffer(WGPU_BIND_GROUP_DESCRIPTOR_SIZE);
|
|
383
793
|
const descView = new DataView(descBuf);
|
|
384
794
|
writePtr(descView, 0, null);
|
|
385
795
|
writeStringView(descView, 8, null);
|
|
@@ -398,7 +808,7 @@ function buildPipelineLayoutDescriptor(layouts) {
|
|
|
398
808
|
ptrs[i] = BigInt(layouts[i]);
|
|
399
809
|
}
|
|
400
810
|
|
|
401
|
-
const descBuf = new ArrayBuffer(
|
|
811
|
+
const descBuf = new ArrayBuffer(WGPU_PIPELINE_LAYOUT_DESCRIPTOR_SIZE);
|
|
402
812
|
const descView = new DataView(descBuf);
|
|
403
813
|
writePtr(descView, 0, null);
|
|
404
814
|
writeStringView(descView, 8, null);
|
|
@@ -440,19 +850,104 @@ function buildPipelineLayoutDescriptor(layouts) {
|
|
|
440
850
|
const TEXTURE_DESC_SIZE = 80;
|
|
441
851
|
|
|
442
852
|
const TEXTURE_FORMAT_MAP = {
|
|
443
|
-
|
|
444
|
-
|
|
853
|
+
r8unorm: 0x01, r8snorm: 0x02, r8uint: 0x03, r8sint: 0x04,
|
|
854
|
+
r16uint: 0x07, r16sint: 0x08, r16float: 0x09,
|
|
855
|
+
rg8unorm: 0x0A, rg8snorm: 0x0B, rg8uint: 0x0C, rg8sint: 0x0D,
|
|
856
|
+
r32float: 0x0E, r32uint: 0x0F, r32sint: 0x10,
|
|
857
|
+
rg16uint: 0x13, rg16sint: 0x14, rg16float: 0x15,
|
|
858
|
+
rgba8unorm: 0x16, "rgba8unorm-srgb": 0x17, rgba8snorm: 0x18, rgba8uint: 0x19, rgba8sint: 0x1A,
|
|
859
|
+
bgra8unorm: 0x1B, "bgra8unorm-srgb": 0x1C,
|
|
860
|
+
rgb10a2uint: 0x1D, rgb10a2unorm: 0x1E, rg11b10ufloat: 0x1F, rgb9e5ufloat: 0x20,
|
|
861
|
+
rg32float: 0x21, rg32uint: 0x22, rg32sint: 0x23,
|
|
862
|
+
rgba16uint: 0x24, rgba16sint: 0x25, rgba16float: 0x26,
|
|
863
|
+
rgba32float: 0x27, rgba32uint: 0x28, rgba32sint: 0x29,
|
|
864
|
+
stencil8: 0x2C, depth16unorm: 0x2D,
|
|
865
|
+
depth24plus: 0x2E, "depth24plus-stencil8": 0x2F,
|
|
866
|
+
depth32float: 0x30, "depth32float-stencil8": 0x31,
|
|
867
|
+
// BC compressed formats (texture-compression-bc feature)
|
|
868
|
+
"bc1-rgba-unorm": 0x32, "bc1-rgba-unorm-srgb": 0x33,
|
|
869
|
+
"bc2-rgba-unorm": 0x34, "bc2-rgba-unorm-srgb": 0x35,
|
|
870
|
+
"bc3-rgba-unorm": 0x36, "bc3-rgba-unorm-srgb": 0x37,
|
|
871
|
+
"bc4-r-unorm": 0x38, "bc4-r-snorm": 0x39,
|
|
872
|
+
"bc5-rg-unorm": 0x3A, "bc5-rg-snorm": 0x3B,
|
|
873
|
+
"bc6h-rgb-ufloat": 0x3C, "bc6h-rgb-float": 0x3D,
|
|
874
|
+
"bc7-rgba-unorm": 0x3E, "bc7-rgba-unorm-srgb": 0x3F,
|
|
875
|
+
// ETC2/EAC compressed formats (texture-compression-etc2 feature)
|
|
876
|
+
"etc2-rgb8unorm": 0x40, "etc2-rgb8unorm-srgb": 0x41,
|
|
877
|
+
"etc2-rgb8a1unorm": 0x42, "etc2-rgb8a1unorm-srgb": 0x43,
|
|
878
|
+
"etc2-rgba8unorm": 0x44, "etc2-rgba8unorm-srgb": 0x45,
|
|
879
|
+
"eac-r11unorm": 0x46, "eac-r11snorm": 0x47,
|
|
880
|
+
"eac-rg11unorm": 0x48, "eac-rg11snorm": 0x49,
|
|
881
|
+
// ASTC compressed formats (texture-compression-astc feature)
|
|
882
|
+
"astc-4x4-unorm": 0x4A, "astc-4x4-unorm-srgb": 0x4B,
|
|
883
|
+
"astc-5x4-unorm": 0x4C, "astc-5x4-unorm-srgb": 0x4D,
|
|
884
|
+
"astc-5x5-unorm": 0x4E, "astc-5x5-unorm-srgb": 0x4F,
|
|
885
|
+
"astc-6x5-unorm": 0x50, "astc-6x5-unorm-srgb": 0x51,
|
|
886
|
+
"astc-6x6-unorm": 0x52, "astc-6x6-unorm-srgb": 0x53,
|
|
887
|
+
"astc-8x5-unorm": 0x54, "astc-8x5-unorm-srgb": 0x55,
|
|
888
|
+
"astc-8x6-unorm": 0x56, "astc-8x6-unorm-srgb": 0x57,
|
|
889
|
+
"astc-8x8-unorm": 0x58, "astc-8x8-unorm-srgb": 0x59,
|
|
890
|
+
"astc-10x5-unorm": 0x5A, "astc-10x5-unorm-srgb": 0x5B,
|
|
891
|
+
"astc-10x6-unorm": 0x5C, "astc-10x6-unorm-srgb": 0x5D,
|
|
892
|
+
"astc-10x8-unorm": 0x5E, "astc-10x8-unorm-srgb": 0x5F,
|
|
893
|
+
"astc-10x10-unorm": 0x60, "astc-10x10-unorm-srgb": 0x61,
|
|
894
|
+
"astc-12x10-unorm": 0x62, "astc-12x10-unorm-srgb": 0x63,
|
|
895
|
+
"astc-12x12-unorm": 0x64, "astc-12x12-unorm-srgb": 0x65,
|
|
445
896
|
};
|
|
446
897
|
|
|
898
|
+
// Alias used by bind group layout storage texture format lookup
|
|
899
|
+
const TEXTURE_FORMATS = TEXTURE_FORMAT_MAP;
|
|
900
|
+
|
|
901
|
+
const VERTEX_FORMAT_MAP = {
|
|
902
|
+
float32: 0x00000019,
|
|
903
|
+
float32x2: 0x0000001A,
|
|
904
|
+
float32x3: 0x0000001B,
|
|
905
|
+
float32x4: 0x0000001C,
|
|
906
|
+
uint32: 0x00000021,
|
|
907
|
+
uint32x2: 0x00000022,
|
|
908
|
+
uint32x3: 0x00000023,
|
|
909
|
+
uint32x4: 0x00000024,
|
|
910
|
+
sint32: 0x00000025,
|
|
911
|
+
sint32x2: 0x00000026,
|
|
912
|
+
sint32x3: 0x00000027,
|
|
913
|
+
sint32x4: 0x00000028,
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
const VERTEX_STEP_MODE_MAP = {
|
|
917
|
+
vertex: 0x00000001,
|
|
918
|
+
instance: 0x00000002,
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
const COMPARE_FUNC_MAP = {
|
|
922
|
+
never: 0x00000001,
|
|
923
|
+
less: 0x00000002,
|
|
924
|
+
equal: 0x00000003,
|
|
925
|
+
"less-equal": 0x00000004,
|
|
926
|
+
greater: 0x00000005,
|
|
927
|
+
"not-equal": 0x00000006,
|
|
928
|
+
"greater-equal": 0x00000007,
|
|
929
|
+
always: 0x00000008,
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
const INDEX_FORMAT_MAP = {
|
|
933
|
+
uint16: 0x00000001,
|
|
934
|
+
uint32: 0x00000002,
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
const TEXTURE_DIMENSION_MAP = Object.freeze({
|
|
938
|
+
"1d": 1,
|
|
939
|
+
"2d": 2,
|
|
940
|
+
"3d": 3,
|
|
941
|
+
});
|
|
942
|
+
|
|
447
943
|
function buildTextureDescriptor(descriptor) {
|
|
448
944
|
const buf = new ArrayBuffer(TEXTURE_DESC_SIZE);
|
|
449
945
|
const v = new DataView(buf);
|
|
450
946
|
writePtr(v, 0, null);
|
|
451
947
|
writeStringView(v, 8, null);
|
|
452
948
|
v.setBigUint64(24, BigInt(descriptor.usage || 0), true);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
v.setUint32(32, 2, true);
|
|
949
|
+
const dimension = descriptor.dimension ?? "2d";
|
|
950
|
+
v.setUint32(32, typeof dimension === "number" ? dimension : (TEXTURE_DIMENSION_MAP[dimension] ?? 2), true);
|
|
456
951
|
const w = descriptor.size?.[0] ?? descriptor.size?.width ?? descriptor.size ?? 1;
|
|
457
952
|
const h = descriptor.size?.[1] ?? descriptor.size?.height ?? 1;
|
|
458
953
|
const d = descriptor.size?.[2] ?? descriptor.size?.depthOrArrayLayers ?? 1;
|
|
@@ -460,7 +955,7 @@ function buildTextureDescriptor(descriptor) {
|
|
|
460
955
|
v.setUint32(40, h, true);
|
|
461
956
|
v.setUint32(44, d, true);
|
|
462
957
|
const fmt = descriptor.format || "rgba8unorm";
|
|
463
|
-
v.setUint32(48, TEXTURE_FORMAT_MAP[fmt] ??
|
|
958
|
+
v.setUint32(48, TEXTURE_FORMAT_MAP[fmt] ?? 0x16, true);
|
|
464
959
|
v.setUint32(52, descriptor.mipLevelCount || 1, true);
|
|
465
960
|
v.setUint32(56, 1, true); // sampleCount
|
|
466
961
|
v.setBigUint64(64, 0n, true); // viewFormatCount
|
|
@@ -496,6 +991,9 @@ function buildSamplerDescriptor(descriptor) {
|
|
|
496
991
|
// { nextInChain:ptr@0, view:ptr@8, depthSlice:u32@16, pad@20, resolveTarget:ptr@24,
|
|
497
992
|
// loadOp:u32@32, storeOp:u32@36, clearValue:{r:f64@40, g:f64@48, b:f64@56, a:f64@64} } = 72
|
|
498
993
|
const RENDER_PASS_COLOR_ATTACHMENT_SIZE = 72;
|
|
994
|
+
const TEXEL_COPY_TEXTURE_INFO_SIZE = 32;
|
|
995
|
+
const TEXEL_COPY_BUFFER_INFO_SIZE = 24;
|
|
996
|
+
const EXTENT3D_SIZE = 12;
|
|
499
997
|
|
|
500
998
|
// WGPURenderPassDescriptor:
|
|
501
999
|
// { nextInChain:ptr@0, label:sv@8, colorAttachmentCount:size_t@24, colorAttachments:ptr@32,
|
|
@@ -521,17 +1019,64 @@ function buildRenderPassDescriptor(descriptor) {
|
|
|
521
1019
|
attView.setFloat64(off + 64, cv.a ?? 1, true);
|
|
522
1020
|
}
|
|
523
1021
|
|
|
524
|
-
|
|
1022
|
+
let depthStencilAttachmentArr = null;
|
|
1023
|
+
if (descriptor.depthStencilAttachment?.view) {
|
|
1024
|
+
const depthBuf = new ArrayBuffer(WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_SIZE);
|
|
1025
|
+
const depthView = new DataView(depthBuf);
|
|
1026
|
+
writePtr(depthView, 0, descriptor.depthStencilAttachment.view._native);
|
|
1027
|
+
depthView.setUint32(8, 1, true); // clear
|
|
1028
|
+
depthView.setUint32(12, 1, true); // store
|
|
1029
|
+
depthView.setFloat32(16, descriptor.depthStencilAttachment.depthClearValue ?? 1.0, true);
|
|
1030
|
+
depthView.setUint32(20, descriptor.depthStencilAttachment.depthReadOnly ? 1 : 0, true);
|
|
1031
|
+
depthView.setUint32(24, 1, true); // clear
|
|
1032
|
+
depthView.setUint32(28, 1, true); // store
|
|
1033
|
+
depthView.setUint32(32, descriptor.depthStencilAttachment.stencilClearValue ?? 0, true);
|
|
1034
|
+
depthView.setUint32(36, descriptor.depthStencilAttachment.stencilReadOnly ? 1 : 0, true);
|
|
1035
|
+
depthStencilAttachmentArr = new Uint8Array(depthBuf);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const descBuf = new ArrayBuffer(WGPU_RENDER_PASS_DESCRIPTOR_SIZE);
|
|
525
1039
|
const descView = new DataView(descBuf);
|
|
526
1040
|
writePtr(descView, 0, null);
|
|
527
1041
|
writeStringView(descView, 8, null);
|
|
528
1042
|
descView.setBigUint64(24, BigInt(colorAttachments.length), true);
|
|
529
1043
|
writePtr(descView, 32, colorAttachments.length > 0 ? bunPtr(attBuf) : null);
|
|
530
|
-
writePtr(descView, 40, null);
|
|
1044
|
+
writePtr(descView, 40, depthStencilAttachmentArr ? bunPtr(depthStencilAttachmentArr) : null);
|
|
531
1045
|
writePtr(descView, 48, null); // occlusionQuerySet
|
|
532
1046
|
writePtr(descView, 56, null); // timestampWrites
|
|
533
1047
|
|
|
534
|
-
return { desc: new Uint8Array(descBuf), _refs: [attBuf] };
|
|
1048
|
+
return { desc: new Uint8Array(descBuf), _refs: [attBuf, depthStencilAttachmentArr].filter(Boolean) };
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
function buildTexelCopyTextureInfo(source) {
|
|
1052
|
+
const buf = new ArrayBuffer(TEXEL_COPY_TEXTURE_INFO_SIZE);
|
|
1053
|
+
const view = new DataView(buf);
|
|
1054
|
+
writePtr(view, 0, source.texture);
|
|
1055
|
+
view.setUint32(8, source.mipLevel ?? 0, true);
|
|
1056
|
+
view.setUint32(12, source.origin?.x ?? 0, true);
|
|
1057
|
+
view.setUint32(16, source.origin?.y ?? 0, true);
|
|
1058
|
+
view.setUint32(20, source.origin?.z ?? 0, true);
|
|
1059
|
+
view.setUint32(24, source.aspect ?? 1, true);
|
|
1060
|
+
return { desc: new Uint8Array(buf), srcRefs: null };
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
function buildTexelCopyBufferInfo(destination) {
|
|
1064
|
+
const buf = new ArrayBuffer(TEXEL_COPY_BUFFER_INFO_SIZE);
|
|
1065
|
+
const view = new DataView(buf);
|
|
1066
|
+
view.setBigUint64(0, BigInt(destination.offset ?? 0), true);
|
|
1067
|
+
view.setUint32(8, destination.bytesPerRow ?? 0, true);
|
|
1068
|
+
view.setUint32(12, destination.rowsPerImage ?? 0, true);
|
|
1069
|
+
writePtr(view, 16, destination.buffer);
|
|
1070
|
+
return { desc: new Uint8Array(buf), dstRefs: null };
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function buildExtent3D(size) {
|
|
1074
|
+
const buf = new ArrayBuffer(EXTENT3D_SIZE);
|
|
1075
|
+
const view = new DataView(buf);
|
|
1076
|
+
view.setUint32(0, size.width, true);
|
|
1077
|
+
view.setUint32(4, size.height, true);
|
|
1078
|
+
view.setUint32(8, size.depthOrArrayLayers ?? 1, true);
|
|
1079
|
+
return new Uint8Array(buf);
|
|
535
1080
|
}
|
|
536
1081
|
|
|
537
1082
|
// ---------------------------------------------------------------------------
|
|
@@ -542,7 +1087,7 @@ function buildRenderPassDescriptor(descriptor) {
|
|
|
542
1087
|
// not supported on all backends (e.g. Vulkan/Dawn).
|
|
543
1088
|
// ---------------------------------------------------------------------------
|
|
544
1089
|
|
|
545
|
-
function processEventsUntilDone(instancePtr, isDone, timeoutNs =
|
|
1090
|
+
function processEventsUntilDone(instancePtr, isDone, timeoutNs = processEventsTimeoutNs) {
|
|
546
1091
|
const start = Number(process.hrtime.bigint());
|
|
547
1092
|
while (!isDone()) {
|
|
548
1093
|
wgpu.symbols.wgpuInstanceProcessEvents(instancePtr);
|
|
@@ -552,6 +1097,46 @@ function processEventsUntilDone(instancePtr, isDone, timeoutNs = PROCESS_EVENTS_
|
|
|
552
1097
|
}
|
|
553
1098
|
}
|
|
554
1099
|
|
|
1100
|
+
function shaderModuleBindings(shaderModule) {
|
|
1101
|
+
const fn = wgpu?.symbols?.doeNativeShaderModuleGetBindings;
|
|
1102
|
+
if (typeof fn !== "function" || !shaderModule?._native) return null;
|
|
1103
|
+
const count = Number(fn(shaderModule._native, null, 0n));
|
|
1104
|
+
if (count <= 0) return [];
|
|
1105
|
+
const raw = new ArrayBuffer(count * 20);
|
|
1106
|
+
fn(shaderModule._native, new Uint8Array(raw), BigInt(count));
|
|
1107
|
+
const view = new DataView(raw);
|
|
1108
|
+
const bindings = [];
|
|
1109
|
+
for (let index = 0; index < count; index += 1) {
|
|
1110
|
+
const offset = index * 20;
|
|
1111
|
+
const group = view.getUint32(offset + 0, true);
|
|
1112
|
+
const binding = view.getUint32(offset + 4, true);
|
|
1113
|
+
const kind = view.getUint32(offset + 8, true);
|
|
1114
|
+
const addrSpace = view.getUint32(offset + 12, true);
|
|
1115
|
+
const access = view.getUint32(offset + 16, true);
|
|
1116
|
+
bindings.push({
|
|
1117
|
+
group,
|
|
1118
|
+
binding,
|
|
1119
|
+
type: ["buffer", "sampler", "texture", "storage_texture"][kind] ?? "unknown",
|
|
1120
|
+
space: ["function", "private", "workgroup", "uniform", "storage", "handle"][addrSpace] ?? "unknown",
|
|
1121
|
+
access: ["read", "write", "read_write"][access] ?? "unknown",
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
return bindings;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function requireAutoLayoutEntriesFromNative(shaderModule, visibility, path) {
|
|
1128
|
+
const bindings = shaderModuleBindings(shaderModule);
|
|
1129
|
+
if (!Array.isArray(bindings)) {
|
|
1130
|
+
throw new Error(`${path}: layout: "auto" requires native shader binding metadata on this package surface`);
|
|
1131
|
+
}
|
|
1132
|
+
return autoLayoutEntriesFromNativeBindings(bindings, visibility);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
function nativeFailureMessage(prefix) {
|
|
1136
|
+
const detail = copyLastErrorMessage();
|
|
1137
|
+
return detail ? `${prefix}: ${detail}` : prefix;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
555
1140
|
function requestAdapterSync(instancePtr) {
|
|
556
1141
|
let resolvedAdapter = null;
|
|
557
1142
|
let resolvedStatus = null;
|
|
@@ -570,7 +1155,7 @@ function requestAdapterSync(instancePtr) {
|
|
|
570
1155
|
if (futureId === 0 || futureId === 0n) throw new Error("[fawn-webgpu] requestAdapter future unavailable");
|
|
571
1156
|
processEventsUntilDone(instancePtr, () => done);
|
|
572
1157
|
if (resolvedStatus !== REQUEST_ADAPTER_STATUS_SUCCESS || !resolvedAdapter) {
|
|
573
|
-
throw new Error(`[fawn-webgpu] requestAdapter failed (status=${resolvedStatus})`);
|
|
1158
|
+
throw new Error(nativeFailureMessage(`[fawn-webgpu] requestAdapter failed (status=${resolvedStatus})`));
|
|
574
1159
|
}
|
|
575
1160
|
return resolvedAdapter;
|
|
576
1161
|
} finally {
|
|
@@ -596,7 +1181,7 @@ function requestDeviceSync(instancePtr, adapterPtr) {
|
|
|
596
1181
|
if (futureId === 0 || futureId === 0n) throw new Error("[fawn-webgpu] requestDevice future unavailable");
|
|
597
1182
|
processEventsUntilDone(instancePtr, () => done);
|
|
598
1183
|
if (resolvedStatus !== REQUEST_DEVICE_STATUS_SUCCESS || !resolvedDevice) {
|
|
599
|
-
throw new Error(`[fawn-webgpu] requestDevice failed (status=${resolvedStatus})`);
|
|
1184
|
+
throw new Error(nativeFailureMessage(`[fawn-webgpu] requestDevice failed (status=${resolvedStatus})`));
|
|
600
1185
|
}
|
|
601
1186
|
return resolvedDevice;
|
|
602
1187
|
} finally {
|
|
@@ -609,7 +1194,7 @@ function bufferMapSync(instancePtr, bufferPtr, mode, offset, size) {
|
|
|
609
1194
|
const status = wgpu.symbols.doeBufferMapSyncFlat(
|
|
610
1195
|
instancePtr, bufferPtr, BigInt(mode), BigInt(offset), BigInt(size));
|
|
611
1196
|
if (status !== MAP_ASYNC_STATUS_SUCCESS) {
|
|
612
|
-
throw new Error(`[fawn-webgpu] bufferMapAsync failed (status=${status})`);
|
|
1197
|
+
throw new Error(nativeFailureMessage(`[fawn-webgpu] bufferMapAsync failed (status=${status})`));
|
|
613
1198
|
}
|
|
614
1199
|
return;
|
|
615
1200
|
}
|
|
@@ -626,7 +1211,7 @@ function bufferMapSync(instancePtr, bufferPtr, mode, offset, size) {
|
|
|
626
1211
|
if (futureId === 0 || futureId === 0n) throw new Error("[fawn-webgpu] bufferMapAsync future unavailable");
|
|
627
1212
|
processEventsUntilDone(instancePtr, () => done);
|
|
628
1213
|
if (mapStatus !== MAP_ASYNC_STATUS_SUCCESS) {
|
|
629
|
-
throw new Error(`[fawn-webgpu] bufferMapAsync failed (status=${mapStatus})`);
|
|
1214
|
+
throw new Error(nativeFailureMessage(`[fawn-webgpu] bufferMapAsync failed (status=${mapStatus})`));
|
|
630
1215
|
}
|
|
631
1216
|
} finally {
|
|
632
1217
|
cb.close();
|
|
@@ -652,11 +1237,17 @@ function waitForSubmittedWorkDoneSync(instancePtr, queuePtr) {
|
|
|
652
1237
|
null,
|
|
653
1238
|
);
|
|
654
1239
|
if (futureId === 0 || futureId === 0n) {
|
|
655
|
-
|
|
1240
|
+
const error = new Error("[fawn-webgpu] queue work-done future unavailable");
|
|
1241
|
+
error.code = "DOE_QUEUE_UNAVAILABLE";
|
|
1242
|
+
throw error;
|
|
656
1243
|
}
|
|
657
|
-
processEventsUntilDone(instancePtr, () => done);
|
|
1244
|
+
processEventsUntilDone(instancePtr, () => done, processEventsTimeoutNs);
|
|
658
1245
|
if (queueStatus !== REQUEST_DEVICE_STATUS_SUCCESS) {
|
|
659
|
-
|
|
1246
|
+
const error = new Error(nativeFailureMessage(`[fawn-webgpu] queue work-done failed (status=${queueStatus})`));
|
|
1247
|
+
if (queueStatus === 0) {
|
|
1248
|
+
error.code = "DOE_QUEUE_UNAVAILABLE";
|
|
1249
|
+
}
|
|
1250
|
+
throw error;
|
|
660
1251
|
}
|
|
661
1252
|
} finally {
|
|
662
1253
|
cb.close();
|
|
@@ -667,32 +1258,250 @@ function waitForSubmittedWorkDoneSync(instancePtr, queuePtr) {
|
|
|
667
1258
|
// WebGPU wrapper classes — matches index.js surface exactly
|
|
668
1259
|
// ---------------------------------------------------------------------------
|
|
669
1260
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
1261
|
+
function ensureBunCommandEncoderNative(encoder) {
|
|
1262
|
+
encoder._assertOpen("GPUCommandEncoder");
|
|
1263
|
+
if (encoder._native) return;
|
|
1264
|
+
encoder._native = wgpu.symbols.wgpuDeviceCreateCommandEncoder(
|
|
1265
|
+
assertLiveResource(encoder._device, "GPUCommandEncoder", "GPUDevice"), null);
|
|
1266
|
+
for (const cmd of encoder._commands) {
|
|
1267
|
+
if (cmd.t === 0) {
|
|
1268
|
+
const pass = wgpu.symbols.wgpuCommandEncoderBeginComputePass(encoder._native, null);
|
|
1269
|
+
wgpu.symbols.wgpuComputePassEncoderSetPipeline(pass, cmd.p);
|
|
1270
|
+
for (let i = 0; i < cmd.bg.length; i += 1) {
|
|
1271
|
+
if (cmd.bg[i]) {
|
|
1272
|
+
wgpu.symbols.wgpuComputePassEncoderSetBindGroup(pass, i, cmd.bg[i], BigInt(0), null);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
wgpu.symbols.wgpuComputePassEncoderDispatchWorkgroups(pass, cmd.x, cmd.y, cmd.z);
|
|
1276
|
+
wgpu.symbols.wgpuComputePassEncoderEnd(pass);
|
|
1277
|
+
wgpu.symbols.wgpuComputePassEncoderRelease(pass);
|
|
1278
|
+
} else if (cmd.t === 1) {
|
|
1279
|
+
wgpu.symbols.wgpuCommandEncoderCopyBufferToBuffer(
|
|
1280
|
+
encoder._native, cmd.s, BigInt(cmd.so), cmd.d, BigInt(cmd.do), BigInt(cmd.sz));
|
|
1281
|
+
}
|
|
677
1282
|
}
|
|
1283
|
+
encoder._commands = [];
|
|
1284
|
+
}
|
|
678
1285
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
bufferMapSync(this._instance, this._native, mode, offset, size);
|
|
685
|
-
this._mapMode = mode;
|
|
1286
|
+
function readIndirectDispatchCounts(bufferNative, offset) {
|
|
1287
|
+
const dataPtr = wgpu.symbols.wgpuBufferGetConstMappedRange(bufferNative, BigInt(offset), BigInt(12));
|
|
1288
|
+
if (!dataPtr) {
|
|
1289
|
+
throw new Error("[fawn-webgpu] indirect dispatch buffer is not CPU-readable");
|
|
686
1290
|
}
|
|
1291
|
+
const countsBytes = new Uint8Array(toArrayBuffer(dataPtr, 0, 12)).slice(0);
|
|
1292
|
+
const counts = new DataView(countsBytes.buffer, countsBytes.byteOffset, countsBytes.byteLength);
|
|
1293
|
+
return {
|
|
1294
|
+
x: counts.getUint32(0, true),
|
|
1295
|
+
y: counts.getUint32(4, true),
|
|
1296
|
+
z: counts.getUint32(8, true),
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
const bunEncoderBackend = {
|
|
1301
|
+
computePassInit(pass) {
|
|
1302
|
+
pass._pipeline = null;
|
|
1303
|
+
pass._bindGroups = [];
|
|
1304
|
+
pass._ended = false;
|
|
1305
|
+
},
|
|
1306
|
+
computePassAssertOpen(pass, path) {
|
|
1307
|
+
if (pass._ended) failValidation(path, "compute pass is already ended");
|
|
1308
|
+
if (pass._encoder._finished) failValidation(path, "command encoder is already finished");
|
|
1309
|
+
},
|
|
1310
|
+
computePassSetPipeline(pass, pipelineNative) {
|
|
1311
|
+
pass._pipeline = pipelineNative;
|
|
1312
|
+
},
|
|
1313
|
+
computePassSetBindGroup(pass, index, bindGroupNative) {
|
|
1314
|
+
pass._bindGroups[index] = bindGroupNative;
|
|
1315
|
+
},
|
|
1316
|
+
computePassDispatchWorkgroups(pass, x, y, z) {
|
|
1317
|
+
if (pass._pipeline == null) {
|
|
1318
|
+
failValidation("GPUComputePassEncoder.dispatchWorkgroups", "setPipeline() must be called before dispatch");
|
|
1319
|
+
}
|
|
1320
|
+
pass._encoder._commands.push({ t: 0, p: pass._pipeline, bg: [...pass._bindGroups], x, y, z });
|
|
1321
|
+
},
|
|
1322
|
+
computePassDispatchWorkgroupsIndirect(pass, indirectBufferNative, indirectOffset) {
|
|
1323
|
+
if (pass._pipeline == null) {
|
|
1324
|
+
failValidation("GPUComputePassEncoder.dispatchWorkgroupsIndirect", "setPipeline() must be called before dispatch");
|
|
1325
|
+
}
|
|
1326
|
+
const counts = readIndirectDispatchCounts(indirectBufferNative, indirectOffset);
|
|
1327
|
+
pass._encoder._commands.push({ t: 0, p: pass._pipeline, bg: [...pass._bindGroups], x: counts.x, y: counts.y, z: counts.z });
|
|
1328
|
+
},
|
|
1329
|
+
computePassEnd(pass) {
|
|
1330
|
+
pass._ended = true;
|
|
1331
|
+
},
|
|
1332
|
+
renderPassInit(pass, native) {
|
|
1333
|
+
pass._native = native;
|
|
1334
|
+
pass._ended = false;
|
|
1335
|
+
},
|
|
1336
|
+
renderPassAssertOpen(pass, path) {
|
|
1337
|
+
if (pass._ended) failValidation(path, "render pass is already ended");
|
|
1338
|
+
if (pass._encoder._finished) failValidation(path, "command encoder is already finished");
|
|
1339
|
+
},
|
|
1340
|
+
renderPassSetPipeline(pass, pipelineNative) {
|
|
1341
|
+
wgpu.symbols.wgpuRenderPassEncoderSetPipeline(
|
|
1342
|
+
assertLiveResource(pass, "GPURenderPassEncoder.setPipeline", "GPURenderPassEncoder"),
|
|
1343
|
+
pipelineNative,
|
|
1344
|
+
);
|
|
1345
|
+
},
|
|
1346
|
+
renderPassSetBindGroup(pass, index, bindGroupNative) {
|
|
1347
|
+
wgpu.symbols.wgpuRenderPassEncoderSetBindGroup(
|
|
1348
|
+
assertLiveResource(pass, "GPURenderPassEncoder.setBindGroup", "GPURenderPassEncoder"),
|
|
1349
|
+
index,
|
|
1350
|
+
bindGroupNative,
|
|
1351
|
+
BigInt(0),
|
|
1352
|
+
null,
|
|
1353
|
+
);
|
|
1354
|
+
},
|
|
1355
|
+
renderPassSetVertexBuffer(pass, slot, bufferNative, offset, size) {
|
|
1356
|
+
wgpu.symbols.wgpuRenderPassEncoderSetVertexBuffer(
|
|
1357
|
+
assertLiveResource(pass, "GPURenderPassEncoder.setVertexBuffer", "GPURenderPassEncoder"),
|
|
1358
|
+
slot,
|
|
1359
|
+
bufferNative,
|
|
1360
|
+
BigInt(offset),
|
|
1361
|
+
BigInt(size ?? 0),
|
|
1362
|
+
);
|
|
1363
|
+
},
|
|
1364
|
+
renderPassSetIndexBuffer(pass, bufferNative, format, offset, size) {
|
|
1365
|
+
wgpu.symbols.wgpuRenderPassEncoderSetIndexBuffer(
|
|
1366
|
+
assertLiveResource(pass, "GPURenderPassEncoder.setIndexBuffer", "GPURenderPassEncoder"),
|
|
1367
|
+
bufferNative,
|
|
1368
|
+
INDEX_FORMAT_MAP[format] ?? INDEX_FORMAT_MAP.uint16,
|
|
1369
|
+
BigInt(offset),
|
|
1370
|
+
BigInt(size ?? 0),
|
|
1371
|
+
);
|
|
1372
|
+
},
|
|
1373
|
+
renderPassDraw(pass, vertexCount, instanceCount, firstVertex, firstInstance) {
|
|
1374
|
+
wgpu.symbols.wgpuRenderPassEncoderDraw(pass._native, vertexCount, instanceCount, firstVertex, firstInstance);
|
|
1375
|
+
},
|
|
1376
|
+
renderPassDrawIndexed(pass, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) {
|
|
1377
|
+
wgpu.symbols.wgpuRenderPassEncoderDrawIndexed(
|
|
1378
|
+
assertLiveResource(pass, "GPURenderPassEncoder.drawIndexed", "GPURenderPassEncoder"),
|
|
1379
|
+
indexCount,
|
|
1380
|
+
instanceCount,
|
|
1381
|
+
firstIndex,
|
|
1382
|
+
baseVertex,
|
|
1383
|
+
firstInstance,
|
|
1384
|
+
);
|
|
1385
|
+
},
|
|
1386
|
+
renderPassEnd(pass) {
|
|
1387
|
+
wgpu.symbols.wgpuRenderPassEncoderEnd(assertLiveResource(pass, "GPURenderPassEncoder.end", "GPURenderPassEncoder"));
|
|
1388
|
+
pass._ended = true;
|
|
1389
|
+
},
|
|
1390
|
+
commandEncoderInit(encoder) {
|
|
1391
|
+
encoder._commands = [];
|
|
1392
|
+
encoder._native = null;
|
|
1393
|
+
encoder._finished = false;
|
|
1394
|
+
},
|
|
1395
|
+
commandEncoderAssertOpen(encoder, path) {
|
|
1396
|
+
if (encoder._finished) failValidation(path, "command encoder is already finished");
|
|
1397
|
+
},
|
|
1398
|
+
commandEncoderBeginComputePass(encoder, _descriptor, classes) {
|
|
1399
|
+
return new classes.DoeGPUComputePassEncoder(null, encoder);
|
|
1400
|
+
},
|
|
1401
|
+
commandEncoderBeginRenderPass(encoder, descriptor, classes) {
|
|
1402
|
+
ensureBunCommandEncoderNative(encoder);
|
|
1403
|
+
const { desc, _refs } = buildRenderPassDescriptor(descriptor);
|
|
1404
|
+
const pass = wgpu.symbols.wgpuCommandEncoderBeginRenderPass(encoder._native, desc);
|
|
1405
|
+
void _refs;
|
|
1406
|
+
return new classes.DoeGPURenderPassEncoder(pass, encoder);
|
|
1407
|
+
},
|
|
1408
|
+
commandEncoderCopyBufferToBuffer(encoder, srcNative, srcOffset, dstNative, dstOffset, size) {
|
|
1409
|
+
if (encoder._native) {
|
|
1410
|
+
wgpu.symbols.wgpuCommandEncoderCopyBufferToBuffer(
|
|
1411
|
+
encoder._native, srcNative, BigInt(srcOffset), dstNative, BigInt(dstOffset), BigInt(size));
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
encoder._commands.push({ t: 1, s: srcNative, so: srcOffset, d: dstNative, do: dstOffset, sz: size });
|
|
1415
|
+
},
|
|
1416
|
+
commandEncoderWriteTimestamp(encoder, querySetNative, queryIndex) {
|
|
1417
|
+
ensureBunCommandEncoderNative(encoder);
|
|
1418
|
+
if (typeof wgpu.symbols.doeNativeCommandEncoderWriteTimestamp === "function") {
|
|
1419
|
+
wgpu.symbols.doeNativeCommandEncoderWriteTimestamp(encoder._native, querySetNative, queryIndex);
|
|
1420
|
+
}
|
|
1421
|
+
},
|
|
1422
|
+
commandEncoderResolveQuerySet(encoder, querySetNative, firstQuery, queryCount, destinationNative, destinationOffset) {
|
|
1423
|
+
ensureBunCommandEncoderNative(encoder);
|
|
1424
|
+
if (typeof wgpu.symbols.doeNativeCommandEncoderResolveQuerySet === "function") {
|
|
1425
|
+
wgpu.symbols.doeNativeCommandEncoderResolveQuerySet(
|
|
1426
|
+
encoder._native, querySetNative, firstQuery, queryCount, destinationNative, BigInt(destinationOffset));
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1429
|
+
commandEncoderCopyTextureToBuffer(encoder, source, destination, copySize) {
|
|
1430
|
+
ensureBunCommandEncoderNative(encoder);
|
|
1431
|
+
if (typeof wgpu.symbols.doeNativeCommandEncoderCopyTextureToBuffer === "function") {
|
|
1432
|
+
wgpu.symbols.doeNativeCommandEncoderCopyTextureToBuffer(
|
|
1433
|
+
encoder._native,
|
|
1434
|
+
source.texture,
|
|
1435
|
+
source.mipLevel ?? 0,
|
|
1436
|
+
destination.buffer,
|
|
1437
|
+
BigInt(destination.offset ?? 0),
|
|
1438
|
+
destination.bytesPerRow ?? 0,
|
|
1439
|
+
destination.rowsPerImage ?? 0,
|
|
1440
|
+
copySize.width,
|
|
1441
|
+
copySize.height,
|
|
1442
|
+
copySize.depthOrArrayLayers ?? 1,
|
|
1443
|
+
);
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
const { desc: srcDesc } = buildTexelCopyTextureInfo({
|
|
1447
|
+
...source,
|
|
1448
|
+
texture: source.texture,
|
|
1449
|
+
});
|
|
1450
|
+
const { desc: dstDesc } = buildTexelCopyBufferInfo({
|
|
1451
|
+
...destination,
|
|
1452
|
+
buffer: destination.buffer,
|
|
1453
|
+
});
|
|
1454
|
+
const extent = buildExtent3D(copySize);
|
|
1455
|
+
wgpu.symbols.wgpuCommandEncoderCopyTextureToBuffer(encoder._native, srcDesc, dstDesc, extent);
|
|
1456
|
+
},
|
|
1457
|
+
commandEncoderFinish(encoder) {
|
|
1458
|
+
encoder._finished = true;
|
|
1459
|
+
if (encoder._native) {
|
|
1460
|
+
const cmd = wgpu.symbols.wgpuCommandEncoderFinish(encoder._native, null);
|
|
1461
|
+
encoder._native = null;
|
|
1462
|
+
return { _native: cmd, _batched: false };
|
|
1463
|
+
}
|
|
1464
|
+
return { _commands: encoder._commands, _batched: true };
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
1467
|
+
|
|
1468
|
+
const {
|
|
1469
|
+
DoeGPUComputePassEncoder,
|
|
1470
|
+
DoeGPUCommandEncoder,
|
|
1471
|
+
DoeGPURenderPassEncoder,
|
|
1472
|
+
} = createEncoderClasses(bunEncoderBackend);
|
|
687
1473
|
|
|
688
|
-
|
|
689
|
-
|
|
1474
|
+
const fullSurfaceBackend = {
|
|
1475
|
+
initBufferState(buffer) {
|
|
1476
|
+
buffer._mapMode = 0;
|
|
1477
|
+
buffer._mappedWriteRanges = [];
|
|
1478
|
+
},
|
|
1479
|
+
bufferMarkMappedAtCreation(buffer) {
|
|
1480
|
+
buffer._mapMode = 0x0002;
|
|
1481
|
+
buffer._mappedWriteRanges = [];
|
|
1482
|
+
},
|
|
1483
|
+
bufferMapAsync(wrapper, native, mode, offset, size) {
|
|
1484
|
+
if (wrapper._queue?.hasPendingSubmissions()) {
|
|
1485
|
+
const queueNative = assertLiveResource(wrapper._queue, "GPUBuffer.mapAsync", "GPUQueue");
|
|
1486
|
+
if (typeof wgpu.symbols.doeNativeQueueFlush === "function") {
|
|
1487
|
+
wgpu.symbols.doeNativeQueueFlush(queueNative);
|
|
1488
|
+
fastPathStats.flushAndMap += 1;
|
|
1489
|
+
} else {
|
|
1490
|
+
waitForSubmittedWorkDoneSync(wrapper._instance, queueNative);
|
|
1491
|
+
}
|
|
1492
|
+
wrapper._queue.markSubmittedWorkDone();
|
|
1493
|
+
}
|
|
1494
|
+
bufferMapSync(wrapper._instance, native, mode, offset, size);
|
|
1495
|
+
wrapper._mapMode = mode;
|
|
1496
|
+
},
|
|
1497
|
+
bufferGetMappedRange(wrapper, native, offset, size) {
|
|
1498
|
+
const isWrite = (wrapper._mapMode & 0x0002) !== 0;
|
|
690
1499
|
if (isWrite) {
|
|
691
|
-
const dataPtr = wgpu.symbols.wgpuBufferGetMappedRange(
|
|
1500
|
+
const dataPtr = wgpu.symbols.wgpuBufferGetMappedRange(native, BigInt(offset), BigInt(size));
|
|
692
1501
|
if (!dataPtr) throw new Error("[fawn-webgpu] getMappedRange (write) returned NULL");
|
|
693
1502
|
return toArrayBuffer(dataPtr, 0, size);
|
|
694
1503
|
}
|
|
695
|
-
const dataPtr = wgpu.symbols.wgpuBufferGetConstMappedRange(
|
|
1504
|
+
const dataPtr = wgpu.symbols.wgpuBufferGetConstMappedRange(native, BigInt(offset), BigInt(size));
|
|
696
1505
|
if (!dataPtr) throw new Error("[fawn-webgpu] getMappedRange returned NULL");
|
|
697
1506
|
if (DOE_LIBRARY_FLAVOR === "doe-dropin") {
|
|
698
1507
|
return toArrayBuffer(dataPtr, 0, size);
|
|
@@ -701,337 +1510,309 @@ class DoeGPUBuffer {
|
|
|
701
1510
|
const copy = new ArrayBuffer(size);
|
|
702
1511
|
new Uint8Array(copy).set(new Uint8Array(nativeView));
|
|
703
1512
|
return copy;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
wgpu.symbols.
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
beginComputePass(_descriptor) {
|
|
745
|
-
const pass = wgpu.symbols.wgpuCommandEncoderBeginComputePass(this._native, null);
|
|
746
|
-
return new DoeGPUComputePassEncoder(pass);
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
beginRenderPass(descriptor) {
|
|
750
|
-
const { desc, _refs } = buildRenderPassDescriptor(descriptor);
|
|
751
|
-
const pass = wgpu.symbols.wgpuCommandEncoderBeginRenderPass(this._native, desc);
|
|
752
|
-
void _refs;
|
|
753
|
-
return new DoeGPURenderPassEncoder(pass);
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
copyBufferToBuffer(src, srcOffset, dst, dstOffset, size) {
|
|
757
|
-
wgpu.symbols.wgpuCommandEncoderCopyBufferToBuffer(
|
|
758
|
-
this._native, src._native, BigInt(srcOffset), dst._native, BigInt(dstOffset), BigInt(size));
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
finish() {
|
|
762
|
-
const cmd = wgpu.symbols.wgpuCommandEncoderFinish(this._native, null);
|
|
763
|
-
return { _native: cmd };
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
class DoeGPUQueue {
|
|
768
|
-
constructor(native, instance) {
|
|
769
|
-
this._native = native;
|
|
770
|
-
this._instance = instance;
|
|
771
|
-
this._pendingSubmissions = 0;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
hasPendingSubmissions() {
|
|
775
|
-
return this._pendingSubmissions > 0;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
markSubmittedWorkDone() {
|
|
779
|
-
this._pendingSubmissions = 0;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
submit(commandBuffers) {
|
|
783
|
-
const ptrs = new BigUint64Array(commandBuffers.length);
|
|
784
|
-
for (let i = 0; i < commandBuffers.length; i++) {
|
|
785
|
-
ptrs[i] = BigInt(commandBuffers[i]._native);
|
|
1513
|
+
},
|
|
1514
|
+
bufferUnmap(native, wrapper) {
|
|
1515
|
+
wgpu.symbols.wgpuBufferUnmap(native);
|
|
1516
|
+
wrapper._mapMode = 0;
|
|
1517
|
+
wrapper._mappedWriteRanges = [];
|
|
1518
|
+
},
|
|
1519
|
+
bufferDestroy(native) {
|
|
1520
|
+
wgpu.symbols.wgpuBufferRelease(native);
|
|
1521
|
+
},
|
|
1522
|
+
initQueueState(queue) {
|
|
1523
|
+
queue._pendingSubmissions = 0;
|
|
1524
|
+
},
|
|
1525
|
+
queueHasPendingSubmissions(queue) {
|
|
1526
|
+
return queue._pendingSubmissions > 0;
|
|
1527
|
+
},
|
|
1528
|
+
queueMarkSubmittedWorkDone(queue) {
|
|
1529
|
+
queue._pendingSubmissions = 0;
|
|
1530
|
+
},
|
|
1531
|
+
queueSubmit(queue, queueNative, buffers) {
|
|
1532
|
+
const deviceNative = assertLiveResource(queue._device, "GPUQueue.submit", "GPUDevice");
|
|
1533
|
+
queue._pendingSubmissions += 1;
|
|
1534
|
+
const dispatchFlush = wgpu.symbols.doeNativeComputeDispatchFlush;
|
|
1535
|
+
if (dispatchFlush && buffers.length === 1 && buffers[0]?._batched) {
|
|
1536
|
+
const cmds = buffers[0]._commands;
|
|
1537
|
+
if (cmds.length >= 1 && cmds.length <= 2 && cmds[0]?.t === 0 && (cmds.length === 1 || cmds[1]?.t === 1)) {
|
|
1538
|
+
const cmd0 = cmds[0];
|
|
1539
|
+
const bgPtrs = new BigUint64Array(cmd0.bg.length);
|
|
1540
|
+
for (let i = 0; i < cmd0.bg.length; i += 1) {
|
|
1541
|
+
bgPtrs[i] = BigInt(cmd0.bg[i] ?? 0);
|
|
1542
|
+
}
|
|
1543
|
+
const cmd1 = cmds.length === 2 ? cmds[1] : null;
|
|
1544
|
+
dispatchFlush(
|
|
1545
|
+
queueNative, cmd0.p, bgPtrs, cmd0.bg.length,
|
|
1546
|
+
cmd0.x, cmd0.y, cmd0.z,
|
|
1547
|
+
cmd1?.s ?? null, BigInt(cmd1?.so ?? 0),
|
|
1548
|
+
cmd1?.d ?? null, BigInt(cmd1?.do ?? 0), BigInt(cmd1?.sz ?? 0));
|
|
1549
|
+
if (cmd1) queue.markSubmittedWorkDone();
|
|
1550
|
+
fastPathStats.dispatchFlush += 1;
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
786
1553
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1554
|
+
if (buffers.every((cb) => cb?._batched && Array.isArray(cb._commands))) {
|
|
1555
|
+
const allCommands = [];
|
|
1556
|
+
for (const cb of buffers) allCommands.push(...cb._commands);
|
|
1557
|
+
const encoder = wgpu.symbols.wgpuDeviceCreateCommandEncoder(deviceNative, null);
|
|
1558
|
+
for (const cmd of allCommands) {
|
|
1559
|
+
if (cmd.t === 0) {
|
|
1560
|
+
const pass = wgpu.symbols.wgpuCommandEncoderBeginComputePass(encoder, null);
|
|
1561
|
+
wgpu.symbols.wgpuComputePassEncoderSetPipeline(pass, cmd.p);
|
|
1562
|
+
for (let i = 0; i < cmd.bg.length; i += 1) {
|
|
1563
|
+
if (cmd.bg[i]) wgpu.symbols.wgpuComputePassEncoderSetBindGroup(pass, i, cmd.bg[i], BigInt(0), null);
|
|
1564
|
+
}
|
|
1565
|
+
wgpu.symbols.wgpuComputePassEncoderDispatchWorkgroups(pass, cmd.x, cmd.y, cmd.z);
|
|
1566
|
+
wgpu.symbols.wgpuComputePassEncoderEnd(pass);
|
|
1567
|
+
wgpu.symbols.wgpuComputePassEncoderRelease(pass);
|
|
1568
|
+
} else if (cmd.t === 1) {
|
|
1569
|
+
wgpu.symbols.wgpuCommandEncoderCopyBufferToBuffer(
|
|
1570
|
+
encoder, cmd.s, BigInt(cmd.so), cmd.d, BigInt(cmd.do), BigInt(cmd.sz));
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
const cmdBuf = wgpu.symbols.wgpuCommandEncoderFinish(encoder, null);
|
|
1574
|
+
const ptrs = new BigUint64Array([BigInt(cmdBuf)]);
|
|
1575
|
+
wgpu.symbols.wgpuQueueSubmit(queueNative, BigInt(1), ptrs);
|
|
1576
|
+
wgpu.symbols.wgpuCommandBufferRelease(cmdBuf);
|
|
1577
|
+
wgpu.symbols.wgpuCommandEncoderRelease(encoder);
|
|
1578
|
+
return;
|
|
790
1579
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
let view = data;
|
|
795
|
-
if (dataOffset > 0 || size !== undefined) {
|
|
796
|
-
const byteOffset = data.byteOffset + dataOffset * (data.BYTES_PER_ELEMENT || 1);
|
|
797
|
-
const byteLength = size !== undefined
|
|
798
|
-
? size * (data.BYTES_PER_ELEMENT || 1)
|
|
799
|
-
: data.byteLength - dataOffset * (data.BYTES_PER_ELEMENT || 1);
|
|
800
|
-
view = new Uint8Array(data.buffer, byteOffset, byteLength);
|
|
1580
|
+
const ptrs = new BigUint64Array(buffers.length);
|
|
1581
|
+
for (let index = 0; index < buffers.length; index += 1) {
|
|
1582
|
+
ptrs[index] = BigInt(assertLiveResource(buffers[index], "GPUQueue.submit", "GPUCommandBuffer"));
|
|
801
1583
|
}
|
|
802
|
-
wgpu.symbols.
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
setPipeline(pipeline) {
|
|
816
|
-
wgpu.symbols.wgpuRenderPassEncoderSetPipeline(this._native, pipeline._native);
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
|
|
820
|
-
wgpu.symbols.wgpuRenderPassEncoderDraw(this._native, vertexCount, instanceCount, firstVertex, firstInstance);
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
end() {
|
|
824
|
-
wgpu.symbols.wgpuRenderPassEncoderEnd(this._native);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
class DoeGPUTexture {
|
|
829
|
-
constructor(native) { this._native = native; }
|
|
830
|
-
|
|
831
|
-
createView(_descriptor) {
|
|
832
|
-
const view = wgpu.symbols.wgpuTextureCreateView(this._native, null);
|
|
833
|
-
return new DoeGPUTextureView(view);
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
destroy() {
|
|
837
|
-
wgpu.symbols.wgpuTextureRelease(this._native);
|
|
838
|
-
this._native = null;
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
class DoeGPUTextureView {
|
|
843
|
-
constructor(native) { this._native = native; }
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
class DoeGPUSampler {
|
|
847
|
-
constructor(native) { this._native = native; }
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
class DoeGPURenderPipeline {
|
|
851
|
-
constructor(native) { this._native = native; }
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
class DoeGPUShaderModule {
|
|
855
|
-
constructor(native, code) {
|
|
856
|
-
this._native = native;
|
|
857
|
-
this._code = code;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
class DoeGPUComputePipeline {
|
|
862
|
-
constructor(native, device, explicitLayout, autoLayoutEntriesByGroup) {
|
|
863
|
-
this._native = native;
|
|
864
|
-
this._device = device;
|
|
865
|
-
this._explicitLayout = explicitLayout;
|
|
866
|
-
this._autoLayoutEntriesByGroup = autoLayoutEntriesByGroup;
|
|
867
|
-
this._cachedLayouts = new Map();
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
getBindGroupLayout(index) {
|
|
871
|
-
if (this._explicitLayout) return this._explicitLayout;
|
|
872
|
-
if (this._cachedLayouts.has(index)) return this._cachedLayouts.get(index);
|
|
873
|
-
|
|
874
|
-
let layout;
|
|
875
|
-
if (this._autoLayoutEntriesByGroup && process.platform === "darwin") {
|
|
876
|
-
const entries = this._autoLayoutEntriesByGroup.get(index) ?? [];
|
|
877
|
-
layout = this._device.createBindGroupLayout({ entries });
|
|
878
|
-
} else {
|
|
879
|
-
const native = process.platform === "darwin"
|
|
880
|
-
? wgpu.symbols.doeNativeComputePipelineGetBindGroupLayout(this._native, index)
|
|
881
|
-
: wgpu.symbols.wgpuComputePipelineGetBindGroupLayout(this._native, index);
|
|
882
|
-
layout = new DoeGPUBindGroupLayout(native);
|
|
1584
|
+
wgpu.symbols.wgpuQueueSubmit(queueNative, BigInt(buffers.length), ptrs);
|
|
1585
|
+
},
|
|
1586
|
+
queueWriteBuffer(_queue, native, bufferNative, bufferOffset, view) {
|
|
1587
|
+
wgpu.symbols.wgpuQueueWriteBuffer(native, bufferNative, BigInt(bufferOffset), view, BigInt(view.byteLength));
|
|
1588
|
+
},
|
|
1589
|
+
async queueOnSubmittedWorkDone(queue, native) {
|
|
1590
|
+
try {
|
|
1591
|
+
waitForSubmittedWorkDoneSync(queue._instance, native);
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
if (error?.code === "DOE_QUEUE_UNAVAILABLE") {
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
throw error;
|
|
883
1597
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
return
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const
|
|
915
|
-
return
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
createShaderModule(descriptor) {
|
|
919
|
-
const code = descriptor.code || descriptor.source;
|
|
920
|
-
if (!code) throw new Error("createShaderModule: descriptor.code is required");
|
|
1598
|
+
},
|
|
1599
|
+
textureCreateView(_texture, native) {
|
|
1600
|
+
return wgpu.symbols.wgpuTextureCreateView(native, null);
|
|
1601
|
+
},
|
|
1602
|
+
textureDestroy(native) {
|
|
1603
|
+
wgpu.symbols.wgpuTextureRelease(native);
|
|
1604
|
+
},
|
|
1605
|
+
shaderModuleDestroy(native) {
|
|
1606
|
+
wgpu.symbols.wgpuShaderModuleRelease(native);
|
|
1607
|
+
},
|
|
1608
|
+
computePipelineGetBindGroupLayout(pipeline, index, classes) {
|
|
1609
|
+
if (pipeline._autoLayoutEntriesByGroup && process.platform === "darwin") {
|
|
1610
|
+
const entries = pipeline._autoLayoutEntriesByGroup.get(index) ?? [];
|
|
1611
|
+
return pipeline._device.createBindGroupLayout({ entries });
|
|
1612
|
+
}
|
|
1613
|
+
const native = process.platform === "darwin"
|
|
1614
|
+
? wgpu.symbols.doeNativeComputePipelineGetBindGroupLayout(pipeline._native, index)
|
|
1615
|
+
: wgpu.symbols.wgpuComputePipelineGetBindGroupLayout(pipeline._native, index);
|
|
1616
|
+
return new classes.DoeGPUBindGroupLayout(native, pipeline._device);
|
|
1617
|
+
},
|
|
1618
|
+
deviceLimits,
|
|
1619
|
+
deviceFeatures,
|
|
1620
|
+
adapterLimits,
|
|
1621
|
+
adapterFeatures,
|
|
1622
|
+
preflightShaderSource,
|
|
1623
|
+
requireAutoLayoutEntriesFromNative,
|
|
1624
|
+
deviceGetQueue(native) {
|
|
1625
|
+
return wgpu.symbols.wgpuDeviceGetQueue(native);
|
|
1626
|
+
},
|
|
1627
|
+
deviceCreateBuffer(device, validated) {
|
|
1628
|
+
const descBytes = buildBufferDescriptor(validated);
|
|
1629
|
+
return wgpu.symbols.wgpuDeviceCreateBuffer(assertLiveResource(device, "GPUDevice.createBuffer", "GPUDevice"), descBytes);
|
|
1630
|
+
},
|
|
1631
|
+
deviceCreateShaderModule(device, code) {
|
|
921
1632
|
const { desc, _refs } = buildShaderModuleDescriptor(code);
|
|
922
|
-
|
|
1633
|
+
let mod;
|
|
1634
|
+
try {
|
|
1635
|
+
mod = wgpu.symbols.wgpuDeviceCreateShaderModule(assertLiveResource(device, "GPUDevice.createShaderModule", "GPUDevice"), desc);
|
|
1636
|
+
} catch (error) {
|
|
1637
|
+
throw enrichNativeCompilerError(error, "GPUDevice.createShaderModule", readLastErrorFields());
|
|
1638
|
+
}
|
|
923
1639
|
void _refs;
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
)
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const native = wgpu.symbols.wgpuDeviceCreateComputePipeline(this._native, desc);
|
|
1640
|
+
if (!mod) {
|
|
1641
|
+
throw compilerErrorFromMessage("GPUDevice.createShaderModule", nativeFailureMessage("createShaderModule failed"), readLastErrorFields());
|
|
1642
|
+
}
|
|
1643
|
+
return mod;
|
|
1644
|
+
},
|
|
1645
|
+
deviceCreateComputePipeline(device, shaderNative, entryPoint, layoutNative) {
|
|
1646
|
+
const { desc, _refs } = buildComputePipelineDescriptor(shaderNative, entryPoint, layoutNative);
|
|
1647
|
+
let native;
|
|
1648
|
+
try {
|
|
1649
|
+
native = wgpu.symbols.wgpuDeviceCreateComputePipeline(assertLiveResource(device, "GPUDevice.createComputePipeline", "GPUDevice"), desc);
|
|
1650
|
+
} catch (error) {
|
|
1651
|
+
throw enrichNativeCompilerError(error, "GPUDevice.createComputePipeline", readLastErrorFields());
|
|
1652
|
+
}
|
|
938
1653
|
void _refs;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
createBindGroupLayout(descriptor) {
|
|
947
|
-
const entries = (descriptor.entries || []).map((e) => ({
|
|
948
|
-
binding: e.binding,
|
|
949
|
-
visibility: e.visibility,
|
|
950
|
-
buffer: e.buffer ? {
|
|
951
|
-
type: e.buffer.type || "uniform",
|
|
952
|
-
hasDynamicOffset: e.buffer.hasDynamicOffset || false,
|
|
953
|
-
minBindingSize: e.buffer.minBindingSize || 0,
|
|
954
|
-
} : undefined,
|
|
955
|
-
}));
|
|
1654
|
+
if (!native) {
|
|
1655
|
+
throw compilerErrorFromMessage("GPUDevice.createComputePipeline", nativeFailureMessage("createComputePipeline failed"), readLastErrorFields());
|
|
1656
|
+
}
|
|
1657
|
+
return native;
|
|
1658
|
+
},
|
|
1659
|
+
deviceCreateBindGroupLayout(device, entries) {
|
|
956
1660
|
const { desc, _refs } = buildBindGroupLayoutDescriptor(entries);
|
|
957
|
-
const native = wgpu.symbols.wgpuDeviceCreateBindGroupLayout(
|
|
1661
|
+
const native = wgpu.symbols.wgpuDeviceCreateBindGroupLayout(assertLiveResource(device, "GPUDevice.createBindGroupLayout", "GPUDevice"), desc);
|
|
958
1662
|
void _refs;
|
|
959
|
-
return
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1663
|
+
return native;
|
|
1664
|
+
},
|
|
1665
|
+
deviceCreateBindGroup(device, layoutNative, entries) {
|
|
1666
|
+
const normalizedEntries = entries.map((entry) => ({
|
|
1667
|
+
binding: entry.binding,
|
|
1668
|
+
resource: entry.buffer
|
|
1669
|
+
? { buffer: entry.buffer, offset: entry.offset ?? 0, size: entry.size }
|
|
1670
|
+
: entry.sampler
|
|
1671
|
+
? { sampler: entry.sampler }
|
|
1672
|
+
: { textureView: entry.textureView },
|
|
1673
|
+
}));
|
|
1674
|
+
const { desc, _refs } = buildBindGroupDescriptor(layoutNative, normalizedEntries);
|
|
1675
|
+
const native = wgpu.symbols.wgpuDeviceCreateBindGroup(assertLiveResource(device, "GPUDevice.createBindGroup", "GPUDevice"), desc);
|
|
965
1676
|
void _refs;
|
|
966
|
-
return
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
createPipelineLayout(descriptor) {
|
|
970
|
-
const layouts = (descriptor.bindGroupLayouts || []).map((l) => l._native);
|
|
1677
|
+
return native;
|
|
1678
|
+
},
|
|
1679
|
+
deviceCreatePipelineLayout(device, layouts) {
|
|
971
1680
|
const { desc, _refs } = buildPipelineLayoutDescriptor(layouts);
|
|
972
|
-
const native = wgpu.symbols.wgpuDeviceCreatePipelineLayout(
|
|
1681
|
+
const native = wgpu.symbols.wgpuDeviceCreatePipelineLayout(assertLiveResource(device, "GPUDevice.createPipelineLayout", "GPUDevice"), desc);
|
|
973
1682
|
void _refs;
|
|
974
|
-
return
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1683
|
+
return native;
|
|
1684
|
+
},
|
|
1685
|
+
deviceCreateTexture(device, textureDescriptor, size, usage) {
|
|
1686
|
+
const descBytes = buildTextureDescriptor({
|
|
1687
|
+
...textureDescriptor,
|
|
1688
|
+
dimension: normalizeTextureDimension(textureDescriptor.dimension, "GPUDevice.createTexture"),
|
|
1689
|
+
usage,
|
|
1690
|
+
size,
|
|
1691
|
+
mipLevelCount: assertIntegerInRange(textureDescriptor.mipLevelCount ?? 1, "GPUDevice.createTexture", "descriptor.mipLevelCount", { min: 1, max: UINT32_MAX }),
|
|
1692
|
+
});
|
|
1693
|
+
return wgpu.symbols.wgpuDeviceCreateTexture(assertLiveResource(device, "GPUDevice.createTexture", "GPUDevice"), descBytes);
|
|
1694
|
+
},
|
|
1695
|
+
deviceCreateSampler(device, descriptor) {
|
|
984
1696
|
const descBytes = buildSamplerDescriptor(descriptor);
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1697
|
+
return wgpu.symbols.wgpuDeviceCreateSampler(assertLiveResource(device, "GPUDevice.createSampler", "GPUDevice"), descBytes);
|
|
1698
|
+
},
|
|
1699
|
+
deviceCreateRenderPipeline(device, descriptor) {
|
|
1700
|
+
const { desc, _refs } = buildRenderPipelineDescriptor({
|
|
1701
|
+
layout: descriptor.layout,
|
|
1702
|
+
vertexModule: descriptor.vertexModule,
|
|
1703
|
+
vertexEntryPoint: descriptor.vertexEntryPoint,
|
|
1704
|
+
vertexBuffers: descriptor.vertexBuffers ?? [],
|
|
1705
|
+
fragmentModule: descriptor.fragmentModule,
|
|
1706
|
+
fragmentEntryPoint: descriptor.fragmentEntryPoint,
|
|
1707
|
+
colorFormat: descriptor.colorFormat,
|
|
1708
|
+
primitive: descriptor.primitive ?? null,
|
|
1709
|
+
depthStencil: descriptor.depthStencil ?? null,
|
|
1710
|
+
multisample: descriptor.multisample ?? null,
|
|
1711
|
+
});
|
|
1712
|
+
const native = wgpu.symbols.wgpuDeviceCreateRenderPipeline(
|
|
1713
|
+
assertLiveResource(device, "GPUDevice.createRenderPipeline", "GPUDevice"),
|
|
1714
|
+
desc,
|
|
1715
|
+
);
|
|
1716
|
+
void _refs;
|
|
1717
|
+
if (!native) {
|
|
1718
|
+
throw compilerErrorFromMessage("GPUDevice.createRenderPipeline", nativeFailureMessage("createRenderPipeline failed"));
|
|
1719
|
+
}
|
|
1720
|
+
return native;
|
|
1721
|
+
},
|
|
1722
|
+
deviceCreateQuerySet(device, descriptor) {
|
|
1723
|
+
const QUERY_TYPE_TIMESTAMP = 2;
|
|
1724
|
+
const fn = wgpu.symbols.doeNativeDeviceCreateQuerySet;
|
|
1725
|
+
if (typeof fn !== "function") {
|
|
1726
|
+
throw new Error("[fawn-webgpu] doeNativeDeviceCreateQuerySet not available");
|
|
1727
|
+
}
|
|
1728
|
+
const native = fn(
|
|
1729
|
+
assertLiveResource(device, "GPUDevice.createQuerySet", "GPUDevice"),
|
|
1730
|
+
QUERY_TYPE_TIMESTAMP,
|
|
1731
|
+
descriptor.count,
|
|
1732
|
+
);
|
|
1733
|
+
if (!native) throw new Error("[fawn-webgpu] createQuerySet failed");
|
|
1734
|
+
return native;
|
|
1735
|
+
},
|
|
1736
|
+
querySetDestroy(native) {
|
|
1737
|
+
if (typeof wgpu.symbols.doeNativeQuerySetDestroy === "function") {
|
|
1738
|
+
wgpu.symbols.doeNativeQuerySetDestroy(native);
|
|
1739
|
+
}
|
|
1740
|
+
},
|
|
1741
|
+
deviceCreateCommandEncoder(device) {
|
|
1742
|
+
return new DoeGPUCommandEncoder(null, device);
|
|
1743
|
+
},
|
|
1744
|
+
deviceDestroy(native) {
|
|
1745
|
+
wgpu.symbols.wgpuDeviceRelease(native);
|
|
1746
|
+
},
|
|
1747
|
+
adapterRequestDevice(adapter, _descriptor, classes) {
|
|
1748
|
+
const native = requestDeviceSync(adapter._instance, assertLiveResource(adapter, "GPUAdapter.requestDevice", "GPUAdapter"));
|
|
1749
|
+
const device = {
|
|
1750
|
+
_destroyed: false,
|
|
1751
|
+
_resourceLabel: "GPUDevice",
|
|
1752
|
+
_resourceOwner: null,
|
|
1753
|
+
createBuffer: classes.DoeGPUDevice.prototype.createBuffer,
|
|
1754
|
+
createShaderModule: classes.DoeGPUDevice.prototype.createShaderModule,
|
|
1755
|
+
createComputePipeline: classes.DoeGPUDevice.prototype.createComputePipeline,
|
|
1756
|
+
createComputePipelineAsync: classes.DoeGPUDevice.prototype.createComputePipelineAsync,
|
|
1757
|
+
createBindGroupLayout: classes.DoeGPUDevice.prototype.createBindGroupLayout,
|
|
1758
|
+
createBindGroup: classes.DoeGPUDevice.prototype.createBindGroup,
|
|
1759
|
+
createPipelineLayout: classes.DoeGPUDevice.prototype.createPipelineLayout,
|
|
1760
|
+
createTexture: classes.DoeGPUDevice.prototype.createTexture,
|
|
1761
|
+
createSampler: classes.DoeGPUDevice.prototype.createSampler,
|
|
1762
|
+
createRenderPipeline: classes.DoeGPUDevice.prototype.createRenderPipeline,
|
|
1763
|
+
createQuerySet: classes.DoeGPUDevice.prototype.createQuerySet,
|
|
1764
|
+
createCommandEncoder: classes.DoeGPUDevice.prototype.createCommandEncoder,
|
|
1765
|
+
destroy: classes.DoeGPUDevice.prototype.destroy,
|
|
1766
|
+
};
|
|
1767
|
+
device._native = native;
|
|
1768
|
+
device._instance = adapter._instance;
|
|
1769
|
+
device.limits = deviceLimits(native);
|
|
1770
|
+
device.features = deviceFeatures(native);
|
|
1771
|
+
const queue = {
|
|
1772
|
+
_destroyed: false,
|
|
1773
|
+
_resourceLabel: "GPUQueue",
|
|
1774
|
+
_resourceOwner: device,
|
|
1775
|
+
hasPendingSubmissions: classes.DoeGPUQueue.prototype.hasPendingSubmissions,
|
|
1776
|
+
markSubmittedWorkDone: classes.DoeGPUQueue.prototype.markSubmittedWorkDone,
|
|
1777
|
+
submit: classes.DoeGPUQueue.prototype.submit,
|
|
1778
|
+
writeBuffer: classes.DoeGPUQueue.prototype.writeBuffer,
|
|
1779
|
+
onSubmittedWorkDone: classes.DoeGPUQueue.prototype.onSubmittedWorkDone,
|
|
1780
|
+
};
|
|
1781
|
+
queue._native = this.deviceGetQueue(native);
|
|
1782
|
+
queue._instance = adapter._instance;
|
|
1783
|
+
queue._device = device;
|
|
1784
|
+
this.initQueueState(queue);
|
|
1785
|
+
device.queue = queue;
|
|
1786
|
+
return device;
|
|
1787
|
+
},
|
|
1788
|
+
adapterDestroy(native) {
|
|
1789
|
+
wgpu.symbols.wgpuAdapterRelease(native);
|
|
1790
|
+
},
|
|
1791
|
+
gpuRequestAdapter(gpu, _options, classes) {
|
|
1792
|
+
const adapter = requestAdapterSync(gpu._instance);
|
|
1793
|
+
return new classes.DoeGPUAdapter(adapter, gpu._instance);
|
|
1794
|
+
},
|
|
1795
|
+
};
|
|
1029
1796
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1797
|
+
const {
|
|
1798
|
+
DoeGPUBuffer,
|
|
1799
|
+
DoeGPUQueue,
|
|
1800
|
+
DoeGPUTexture,
|
|
1801
|
+
DoeGPUTextureView,
|
|
1802
|
+
DoeGPUSampler,
|
|
1803
|
+
DoeGPURenderPipeline,
|
|
1804
|
+
DoeGPUShaderModule,
|
|
1805
|
+
DoeGPUComputePipeline,
|
|
1806
|
+
DoeGPUBindGroupLayout,
|
|
1807
|
+
DoeGPUBindGroup,
|
|
1808
|
+
DoeGPUPipelineLayout,
|
|
1809
|
+
DoeGPUDevice,
|
|
1810
|
+
DoeGPUAdapter,
|
|
1811
|
+
DoeGPU,
|
|
1812
|
+
} = createFullSurfaceClasses({
|
|
1813
|
+
globals,
|
|
1814
|
+
backend: fullSurfaceBackend,
|
|
1815
|
+
});
|
|
1035
1816
|
|
|
1036
1817
|
// ---------------------------------------------------------------------------
|
|
1037
1818
|
// Library initialization
|
|
@@ -1061,57 +1842,21 @@ export function create(createArgs = null) {
|
|
|
1061
1842
|
}
|
|
1062
1843
|
|
|
1063
1844
|
export function setupGlobals(target = globalThis, createArgs = null) {
|
|
1064
|
-
for (const [name, value] of Object.entries(globals)) {
|
|
1065
|
-
if (target[name] === undefined) {
|
|
1066
|
-
Object.defineProperty(target, name, {
|
|
1067
|
-
value,
|
|
1068
|
-
writable: true,
|
|
1069
|
-
configurable: true,
|
|
1070
|
-
enumerable: false,
|
|
1071
|
-
});
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
1845
|
const gpu = create(createArgs);
|
|
1075
|
-
|
|
1076
|
-
Object.defineProperty(target, "navigator", {
|
|
1077
|
-
value: { gpu },
|
|
1078
|
-
writable: true,
|
|
1079
|
-
configurable: true,
|
|
1080
|
-
enumerable: false,
|
|
1081
|
-
});
|
|
1082
|
-
} else if (!target.navigator.gpu) {
|
|
1083
|
-
Object.defineProperty(target.navigator, "gpu", {
|
|
1084
|
-
value: gpu,
|
|
1085
|
-
writable: true,
|
|
1086
|
-
configurable: true,
|
|
1087
|
-
enumerable: false,
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
return gpu;
|
|
1846
|
+
return setupGlobalsOnTarget(target, gpu, globals);
|
|
1091
1847
|
}
|
|
1092
1848
|
|
|
1093
1849
|
export async function requestAdapter(adapterOptions = undefined, createArgs = null) {
|
|
1094
|
-
|
|
1095
|
-
return gpu.requestAdapter(adapterOptions);
|
|
1850
|
+
return requestAdapterFromCreate(create, adapterOptions, createArgs);
|
|
1096
1851
|
}
|
|
1097
1852
|
|
|
1098
1853
|
export async function requestDevice(options = {}) {
|
|
1099
|
-
|
|
1100
|
-
const adapter = await requestAdapter(options?.adapterOptions, createArgs);
|
|
1101
|
-
return adapter.requestDevice(options?.deviceDescriptor);
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
function libraryFlavor(libraryPath) {
|
|
1105
|
-
if (!libraryPath) return "missing";
|
|
1106
|
-
if (/libwebgpu_doe\.(so|dylib|dll)$/.test(libraryPath)) return "doe-dropin";
|
|
1107
|
-
if (/lib(webgpu|webgpu_dawn|wgpu_native)\.(so|dylib|dll)/.test(libraryPath)) return "delegate";
|
|
1108
|
-
return "unknown";
|
|
1854
|
+
return requestDeviceFromRequestAdapter(requestAdapter, options);
|
|
1109
1855
|
}
|
|
1110
1856
|
|
|
1111
1857
|
export function providerInfo() {
|
|
1112
1858
|
const flavor = DOE_LIBRARY_FLAVOR;
|
|
1113
|
-
return {
|
|
1114
|
-
module: "@simulatte/webgpu",
|
|
1859
|
+
return buildProviderInfo({
|
|
1115
1860
|
loaded: !!DOE_LIB_PATH,
|
|
1116
1861
|
loadError: !DOE_LIB_PATH ? "libwebgpu_doe not found" : "",
|
|
1117
1862
|
defaultCreateArgs: [],
|
|
@@ -1122,10 +1867,17 @@ export function providerInfo() {
|
|
|
1122
1867
|
buildMetadataPath: DOE_BUILD_METADATA.path,
|
|
1123
1868
|
leanVerifiedBuild: DOE_BUILD_METADATA.leanVerifiedBuild,
|
|
1124
1869
|
proofArtifactSha256: DOE_BUILD_METADATA.proofArtifactSha256,
|
|
1125
|
-
};
|
|
1870
|
+
});
|
|
1126
1871
|
}
|
|
1127
1872
|
|
|
1128
1873
|
export { createDoeRuntime, runDawnVsDoeCompare };
|
|
1874
|
+
export { preflightShaderSource };
|
|
1875
|
+
export { fastPathStats };
|
|
1876
|
+
|
|
1877
|
+
export function setNativeTimeoutMs(timeoutMs) {
|
|
1878
|
+
validatePositiveInteger(timeoutMs, 'native timeout');
|
|
1879
|
+
processEventsTimeoutNs = timeoutMs * 1_000_000;
|
|
1880
|
+
}
|
|
1129
1881
|
|
|
1130
1882
|
export default {
|
|
1131
1883
|
create,
|
|
@@ -1134,6 +1886,9 @@ export default {
|
|
|
1134
1886
|
requestAdapter,
|
|
1135
1887
|
requestDevice,
|
|
1136
1888
|
providerInfo,
|
|
1889
|
+
preflightShaderSource,
|
|
1890
|
+
setNativeTimeoutMs,
|
|
1137
1891
|
createDoeRuntime,
|
|
1138
1892
|
runDawnVsDoeCompare,
|
|
1893
|
+
fastPathStats,
|
|
1139
1894
|
};
|