@simulatte/webgpu-doe 0.1.0 → 0.1.1
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/README.md +129 -60
- package/native/doe_napi.c +631 -78
- package/package.json +12 -7
- package/prebuilds/darwin-arm64/doe_napi.node +0 -0
- package/prebuilds/darwin-arm64/libdoe_webgpu.dylib +0 -0
- package/src/index.js +143 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simulatte/webgpu-doe",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Doe WebGPU runtime for Node.js — native Zig GPU backends (Metal, Vulkan) via N-API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -12,13 +12,18 @@
|
|
|
12
12
|
"src/index.js",
|
|
13
13
|
"native/",
|
|
14
14
|
"binding.gyp",
|
|
15
|
+
"prebuilds/",
|
|
15
16
|
"README.md"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
|
-
"
|
|
19
|
-
"build": "node-gyp rebuild"
|
|
19
|
+
"build:addon": "node-gyp rebuild"
|
|
20
20
|
},
|
|
21
|
-
"
|
|
21
|
+
"os": [
|
|
22
|
+
"darwin"
|
|
23
|
+
],
|
|
24
|
+
"cpu": [
|
|
25
|
+
"arm64"
|
|
26
|
+
],
|
|
22
27
|
"keywords": [
|
|
23
28
|
"webgpu",
|
|
24
29
|
"doe",
|
|
@@ -26,11 +31,11 @@
|
|
|
26
31
|
"compute",
|
|
27
32
|
"headless",
|
|
28
33
|
"node",
|
|
29
|
-
"bun",
|
|
30
34
|
"native",
|
|
31
35
|
"napi",
|
|
32
36
|
"metal",
|
|
33
|
-
"vulkan"
|
|
37
|
+
"vulkan",
|
|
38
|
+
"zig"
|
|
34
39
|
],
|
|
35
40
|
"repository": {
|
|
36
41
|
"type": "git",
|
|
Binary file
|
|
Binary file
|
package/src/index.js
CHANGED
|
@@ -11,13 +11,18 @@ const DOE_LIB_PATH = resolveDoeLibraryPath();
|
|
|
11
11
|
let libraryLoaded = false;
|
|
12
12
|
|
|
13
13
|
function loadAddon() {
|
|
14
|
+
const prebuildPath = resolve(__dirname, '..', 'prebuilds', `${process.platform}-${process.arch}`, 'doe_napi.node');
|
|
14
15
|
try {
|
|
15
|
-
return require(
|
|
16
|
+
return require(prebuildPath);
|
|
16
17
|
} catch {
|
|
17
18
|
try {
|
|
18
|
-
return require('../build/
|
|
19
|
+
return require('../build/Release/doe_napi.node');
|
|
19
20
|
} catch {
|
|
20
|
-
|
|
21
|
+
try {
|
|
22
|
+
return require('../build/Debug/doe_napi.node');
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
}
|
|
@@ -88,14 +93,16 @@ export const globals = {
|
|
|
88
93
|
};
|
|
89
94
|
|
|
90
95
|
class DoeGPUBuffer {
|
|
91
|
-
constructor(native, instance, size, usage) {
|
|
96
|
+
constructor(native, instance, size, usage, queue) {
|
|
92
97
|
this._native = native;
|
|
93
98
|
this._instance = instance;
|
|
99
|
+
this._queue = queue;
|
|
94
100
|
this.size = size;
|
|
95
101
|
this.usage = usage;
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
async mapAsync(mode, offset = 0, size = this.size) {
|
|
105
|
+
if (this._queue) addon.queueFlush(this._queue);
|
|
99
106
|
addon.bufferMapSync(this._instance, this._native, mode, offset, size);
|
|
100
107
|
}
|
|
101
108
|
|
|
@@ -128,6 +135,10 @@ class DoeGPUComputePassEncoder {
|
|
|
128
135
|
addon.computePassDispatchWorkgroups(this._native, x, y, z);
|
|
129
136
|
}
|
|
130
137
|
|
|
138
|
+
dispatchWorkgroupsIndirect(indirectBuffer, indirectOffset = 0) {
|
|
139
|
+
addon.computePassDispatchWorkgroupsIndirect(this._native, indirectBuffer._native, indirectOffset);
|
|
140
|
+
}
|
|
141
|
+
|
|
131
142
|
end() {
|
|
132
143
|
addon.computePassEnd(this._native);
|
|
133
144
|
}
|
|
@@ -141,6 +152,15 @@ class DoeGPUCommandEncoder {
|
|
|
141
152
|
return new DoeGPUComputePassEncoder(pass);
|
|
142
153
|
}
|
|
143
154
|
|
|
155
|
+
beginRenderPass(descriptor) {
|
|
156
|
+
const colorAttachments = (descriptor.colorAttachments || []).map((a) => ({
|
|
157
|
+
view: a.view._native,
|
|
158
|
+
clearValue: a.clearValue || { r: 0, g: 0, b: 0, a: 1 },
|
|
159
|
+
}));
|
|
160
|
+
const pass = addon.beginRenderPass(this._native, colorAttachments);
|
|
161
|
+
return new DoeGPURenderPassEncoder(pass);
|
|
162
|
+
}
|
|
163
|
+
|
|
144
164
|
copyBufferToBuffer(src, srcOffset, dst, dstOffset, size) {
|
|
145
165
|
addon.commandEncoderCopyBufferToBuffer(
|
|
146
166
|
this._native, src._native, srcOffset, dst._native, dstOffset, size);
|
|
@@ -171,6 +191,52 @@ class DoeGPUQueue {
|
|
|
171
191
|
}
|
|
172
192
|
addon.queueWriteBuffer(this._native, buffer._native, bufferOffset, view);
|
|
173
193
|
}
|
|
194
|
+
|
|
195
|
+
async onSubmittedWorkDone() {
|
|
196
|
+
addon.queueFlush(this._native);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
class DoeGPURenderPassEncoder {
|
|
201
|
+
constructor(native) { this._native = native; }
|
|
202
|
+
|
|
203
|
+
setPipeline(pipeline) {
|
|
204
|
+
addon.renderPassSetPipeline(this._native, pipeline._native);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
|
|
208
|
+
addon.renderPassDraw(this._native, vertexCount, instanceCount, firstVertex, firstInstance);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
end() {
|
|
212
|
+
addon.renderPassEnd(this._native);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
class DoeGPUTexture {
|
|
217
|
+
constructor(native) { this._native = native; }
|
|
218
|
+
|
|
219
|
+
createView(descriptor) {
|
|
220
|
+
const view = addon.textureCreateView(this._native);
|
|
221
|
+
return new DoeGPUTextureView(view);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
destroy() {
|
|
225
|
+
addon.textureRelease(this._native);
|
|
226
|
+
this._native = null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
class DoeGPUTextureView {
|
|
231
|
+
constructor(native) { this._native = native; }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class DoeGPUSampler {
|
|
235
|
+
constructor(native) { this._native = native; }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
class DoeGPURenderPipeline {
|
|
239
|
+
constructor(native) { this._native = native; }
|
|
174
240
|
}
|
|
175
241
|
|
|
176
242
|
class DoeGPUShaderModule {
|
|
@@ -179,6 +245,11 @@ class DoeGPUShaderModule {
|
|
|
179
245
|
|
|
180
246
|
class DoeGPUComputePipeline {
|
|
181
247
|
constructor(native) { this._native = native; }
|
|
248
|
+
|
|
249
|
+
getBindGroupLayout(index) {
|
|
250
|
+
const layout = addon.computePipelineGetBindGroupLayout(this._native, index);
|
|
251
|
+
return new DoeGPUBindGroupLayout(layout);
|
|
252
|
+
}
|
|
182
253
|
}
|
|
183
254
|
|
|
184
255
|
class DoeGPUBindGroupLayout {
|
|
@@ -193,17 +264,56 @@ class DoeGPUPipelineLayout {
|
|
|
193
264
|
constructor(native) { this._native = native; }
|
|
194
265
|
}
|
|
195
266
|
|
|
267
|
+
// Metal defaults for Apple Silicon — matches doe_device_caps.zig METAL_LIMITS.
|
|
268
|
+
const DOE_LIMITS = Object.freeze({
|
|
269
|
+
maxTextureDimension1D: 16384,
|
|
270
|
+
maxTextureDimension2D: 16384,
|
|
271
|
+
maxTextureDimension3D: 2048,
|
|
272
|
+
maxTextureArrayLayers: 2048,
|
|
273
|
+
maxBindGroups: 4,
|
|
274
|
+
maxBindGroupsPlusVertexBuffers: 24,
|
|
275
|
+
maxBindingsPerBindGroup: 1000,
|
|
276
|
+
maxDynamicUniformBuffersPerPipelineLayout: 8,
|
|
277
|
+
maxDynamicStorageBuffersPerPipelineLayout: 4,
|
|
278
|
+
maxSampledTexturesPerShaderStage: 16,
|
|
279
|
+
maxSamplersPerShaderStage: 16,
|
|
280
|
+
maxStorageBuffersPerShaderStage: 8,
|
|
281
|
+
maxStorageTexturesPerShaderStage: 4,
|
|
282
|
+
maxUniformBuffersPerShaderStage: 12,
|
|
283
|
+
maxUniformBufferBindingSize: 65536,
|
|
284
|
+
maxStorageBufferBindingSize: 134217728,
|
|
285
|
+
minUniformBufferOffsetAlignment: 256,
|
|
286
|
+
minStorageBufferOffsetAlignment: 32,
|
|
287
|
+
maxVertexBuffers: 8,
|
|
288
|
+
maxBufferSize: 268435456,
|
|
289
|
+
maxVertexAttributes: 16,
|
|
290
|
+
maxVertexBufferArrayStride: 2048,
|
|
291
|
+
maxInterStageShaderVariables: 16,
|
|
292
|
+
maxColorAttachments: 8,
|
|
293
|
+
maxColorAttachmentBytesPerSample: 32,
|
|
294
|
+
maxComputeWorkgroupStorageSize: 32768,
|
|
295
|
+
maxComputeInvocationsPerWorkgroup: 1024,
|
|
296
|
+
maxComputeWorkgroupSizeX: 1024,
|
|
297
|
+
maxComputeWorkgroupSizeY: 1024,
|
|
298
|
+
maxComputeWorkgroupSizeZ: 64,
|
|
299
|
+
maxComputeWorkgroupsPerDimension: 65535,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const DOE_FEATURES = Object.freeze(new Set(['shader-f16']));
|
|
303
|
+
|
|
196
304
|
class DoeGPUDevice {
|
|
197
305
|
constructor(native, instance) {
|
|
198
306
|
this._native = native;
|
|
199
307
|
this._instance = instance;
|
|
200
308
|
const q = addon.deviceGetQueue(native);
|
|
201
309
|
this.queue = new DoeGPUQueue(q);
|
|
310
|
+
this.limits = DOE_LIMITS;
|
|
311
|
+
this.features = DOE_FEATURES;
|
|
202
312
|
}
|
|
203
313
|
|
|
204
314
|
createBuffer(descriptor) {
|
|
205
315
|
const buf = addon.createBuffer(this._native, descriptor);
|
|
206
|
-
return new DoeGPUBuffer(buf, this._instance, descriptor.size, descriptor.usage);
|
|
316
|
+
return new DoeGPUBuffer(buf, this._instance, descriptor.size, descriptor.usage, this.queue._native);
|
|
207
317
|
}
|
|
208
318
|
|
|
209
319
|
createShaderModule(descriptor) {
|
|
@@ -223,6 +333,10 @@ class DoeGPUDevice {
|
|
|
223
333
|
return new DoeGPUComputePipeline(native);
|
|
224
334
|
}
|
|
225
335
|
|
|
336
|
+
async createComputePipelineAsync(descriptor) {
|
|
337
|
+
return this.createComputePipeline(descriptor);
|
|
338
|
+
}
|
|
339
|
+
|
|
226
340
|
createBindGroupLayout(descriptor) {
|
|
227
341
|
const entries = (descriptor.entries || []).map((e) => ({
|
|
228
342
|
binding: e.binding,
|
|
@@ -259,6 +373,28 @@ class DoeGPUDevice {
|
|
|
259
373
|
return new DoeGPUPipelineLayout(native);
|
|
260
374
|
}
|
|
261
375
|
|
|
376
|
+
createTexture(descriptor) {
|
|
377
|
+
const native = addon.createTexture(this._native, {
|
|
378
|
+
format: descriptor.format || 'rgba8unorm',
|
|
379
|
+
width: descriptor.size?.[0] ?? descriptor.size?.width ?? descriptor.size ?? 1,
|
|
380
|
+
height: descriptor.size?.[1] ?? descriptor.size?.height ?? 1,
|
|
381
|
+
depthOrArrayLayers: descriptor.size?.[2] ?? descriptor.size?.depthOrArrayLayers ?? 1,
|
|
382
|
+
usage: descriptor.usage || 0,
|
|
383
|
+
mipLevelCount: descriptor.mipLevelCount || 1,
|
|
384
|
+
});
|
|
385
|
+
return new DoeGPUTexture(native);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
createSampler(descriptor = {}) {
|
|
389
|
+
const native = addon.createSampler(this._native, descriptor);
|
|
390
|
+
return new DoeGPUSampler(native);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
createRenderPipeline(descriptor) {
|
|
394
|
+
const native = addon.createRenderPipeline(this._native);
|
|
395
|
+
return new DoeGPURenderPipeline(native);
|
|
396
|
+
}
|
|
397
|
+
|
|
262
398
|
createCommandEncoder(descriptor) {
|
|
263
399
|
const native = addon.createCommandEncoder(this._native);
|
|
264
400
|
return new DoeGPUCommandEncoder(native);
|
|
@@ -274,6 +410,8 @@ class DoeGPUAdapter {
|
|
|
274
410
|
constructor(native, instance) {
|
|
275
411
|
this._native = native;
|
|
276
412
|
this._instance = instance;
|
|
413
|
+
this.features = DOE_FEATURES;
|
|
414
|
+
this.limits = DOE_LIMITS;
|
|
277
415
|
}
|
|
278
416
|
|
|
279
417
|
async requestDevice(descriptor) {
|