@simulatte/webgpu-doe 0.1.2 → 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 +19 -0
- package/LICENSE +191 -0
- package/README.md +121 -126
- package/assets/fawn-icon-main.svg +222 -0
- package/examples/with-webgpu-compute.js +25 -0
- package/package.json +31 -26
- package/src/index.d.ts +125 -0
- package/src/index.js +644 -408
- package/binding.gyp +0 -20
- package/native/doe_napi.c +0 -1677
- package/prebuilds/darwin-arm64/doe_napi.node +0 -0
- package/prebuilds/darwin-arm64/libdoe_webgpu.dylib +0 -0
package/native/doe_napi.c
DELETED
|
@@ -1,1677 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* doe_napi.c — N-API binding for libdoe_webgpu (Doe WebGPU runtime).
|
|
3
|
-
*
|
|
4
|
-
* Loads the Doe shared library at runtime via dlopen and exposes the core
|
|
5
|
-
* WebGPU compute surface to JavaScript through Node.js N-API.
|
|
6
|
-
*
|
|
7
|
-
* All WGPUInstance/Adapter/Device/Buffer/etc. handles are wrapped as
|
|
8
|
-
* napi_external values. Struct descriptors are marshaled from JS objects.
|
|
9
|
-
* Async operations (requestAdapter, requestDevice, bufferMapAsync) use
|
|
10
|
-
* synchronous WaitAny blocking — acceptable for headless compute.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
#include <node_api.h>
|
|
14
|
-
#include <stdlib.h>
|
|
15
|
-
#include <string.h>
|
|
16
|
-
#include <stdint.h>
|
|
17
|
-
|
|
18
|
-
#ifdef _WIN32
|
|
19
|
-
#include <windows.h>
|
|
20
|
-
#define LIB_OPEN(p) LoadLibraryA(p)
|
|
21
|
-
#define LIB_SYM(h, n) ((void*)GetProcAddress((HMODULE)(h), n))
|
|
22
|
-
#define LIB_CLOSE(h) FreeLibrary((HMODULE)(h))
|
|
23
|
-
#else
|
|
24
|
-
#include <dlfcn.h>
|
|
25
|
-
#define LIB_OPEN(p) dlopen(p, RTLD_NOW | RTLD_LOCAL)
|
|
26
|
-
#define LIB_SYM(h, n) dlsym(h, n)
|
|
27
|
-
#define LIB_CLOSE(h) dlclose(h)
|
|
28
|
-
#endif
|
|
29
|
-
|
|
30
|
-
/* ================================================================
|
|
31
|
-
* WebGPU C ABI type definitions (matching wgpu_types.zig)
|
|
32
|
-
* ================================================================ */
|
|
33
|
-
|
|
34
|
-
typedef void* WGPUInstance;
|
|
35
|
-
typedef void* WGPUAdapter;
|
|
36
|
-
typedef void* WGPUDevice;
|
|
37
|
-
typedef void* WGPUQueue;
|
|
38
|
-
typedef void* WGPUBuffer;
|
|
39
|
-
typedef void* WGPUShaderModule;
|
|
40
|
-
typedef void* WGPUComputePipeline;
|
|
41
|
-
typedef void* WGPURenderPipeline;
|
|
42
|
-
typedef void* WGPUBindGroupLayout;
|
|
43
|
-
typedef void* WGPUBindGroup;
|
|
44
|
-
typedef void* WGPUPipelineLayout;
|
|
45
|
-
typedef void* WGPUCommandEncoder;
|
|
46
|
-
typedef void* WGPUCommandBuffer;
|
|
47
|
-
typedef void* WGPUComputePassEncoder;
|
|
48
|
-
typedef void* WGPUQuerySet;
|
|
49
|
-
typedef void* WGPUTexture;
|
|
50
|
-
typedef void* WGPUTextureView;
|
|
51
|
-
typedef void* WGPUSampler;
|
|
52
|
-
typedef void* WGPURenderPassEncoder;
|
|
53
|
-
typedef uint64_t WGPUFlags;
|
|
54
|
-
typedef uint32_t WGPUBool;
|
|
55
|
-
|
|
56
|
-
#define WGPU_STRLEN SIZE_MAX
|
|
57
|
-
#define WGPU_WHOLE_SIZE UINT64_MAX
|
|
58
|
-
#define WGPU_STYPE_SHADER_SOURCE_WGSL 0x00000002
|
|
59
|
-
#define WGPU_WAIT_STATUS_SUCCESS 1
|
|
60
|
-
#define WGPU_MAP_ASYNC_STATUS_SUCCESS 1
|
|
61
|
-
#define WGPU_REQUEST_STATUS_SUCCESS 1
|
|
62
|
-
|
|
63
|
-
typedef struct { uint64_t id; } WGPUFuture;
|
|
64
|
-
typedef struct { const char* data; size_t length; } WGPUStringView;
|
|
65
|
-
typedef struct { WGPUFuture future; WGPUBool completed; } WGPUFutureWaitInfo;
|
|
66
|
-
|
|
67
|
-
typedef struct { void* next; uint32_t sType; } WGPUChainedStruct;
|
|
68
|
-
|
|
69
|
-
typedef struct {
|
|
70
|
-
void* nextInChain;
|
|
71
|
-
WGPUStringView label;
|
|
72
|
-
uint64_t usage;
|
|
73
|
-
uint64_t size;
|
|
74
|
-
WGPUBool mappedAtCreation;
|
|
75
|
-
} WGPUBufferDescriptor;
|
|
76
|
-
|
|
77
|
-
typedef struct {
|
|
78
|
-
void* nextInChain;
|
|
79
|
-
WGPUStringView label;
|
|
80
|
-
} WGPUCommandEncoderDescriptor;
|
|
81
|
-
|
|
82
|
-
typedef struct {
|
|
83
|
-
void* nextInChain;
|
|
84
|
-
WGPUStringView label;
|
|
85
|
-
} WGPUCommandBufferDescriptor;
|
|
86
|
-
|
|
87
|
-
typedef struct {
|
|
88
|
-
WGPUChainedStruct chain;
|
|
89
|
-
WGPUStringView code;
|
|
90
|
-
} WGPUShaderSourceWGSL;
|
|
91
|
-
|
|
92
|
-
typedef struct {
|
|
93
|
-
void* nextInChain;
|
|
94
|
-
WGPUStringView label;
|
|
95
|
-
} WGPUShaderModuleDescriptor;
|
|
96
|
-
|
|
97
|
-
typedef struct {
|
|
98
|
-
void* nextInChain;
|
|
99
|
-
WGPUShaderModule module;
|
|
100
|
-
WGPUStringView entryPoint;
|
|
101
|
-
size_t constantCount;
|
|
102
|
-
void* constants;
|
|
103
|
-
} WGPUComputeState;
|
|
104
|
-
|
|
105
|
-
typedef struct {
|
|
106
|
-
void* nextInChain;
|
|
107
|
-
WGPUStringView label;
|
|
108
|
-
void* layout;
|
|
109
|
-
WGPUComputeState compute;
|
|
110
|
-
} WGPUComputePipelineDescriptor;
|
|
111
|
-
|
|
112
|
-
typedef struct {
|
|
113
|
-
void* nextInChain;
|
|
114
|
-
uint32_t type;
|
|
115
|
-
WGPUBool hasDynamicOffset;
|
|
116
|
-
uint64_t minBindingSize;
|
|
117
|
-
} WGPUBufferBindingLayout;
|
|
118
|
-
|
|
119
|
-
typedef struct {
|
|
120
|
-
void* nextInChain;
|
|
121
|
-
uint32_t type;
|
|
122
|
-
} WGPUSamplerBindingLayout;
|
|
123
|
-
|
|
124
|
-
typedef struct {
|
|
125
|
-
void* nextInChain;
|
|
126
|
-
uint32_t sampleType;
|
|
127
|
-
uint32_t viewDimension;
|
|
128
|
-
WGPUBool multisampled;
|
|
129
|
-
} WGPUTextureBindingLayout;
|
|
130
|
-
|
|
131
|
-
typedef struct {
|
|
132
|
-
void* nextInChain;
|
|
133
|
-
uint32_t access;
|
|
134
|
-
uint32_t format;
|
|
135
|
-
uint32_t viewDimension;
|
|
136
|
-
} WGPUStorageTextureBindingLayout;
|
|
137
|
-
|
|
138
|
-
typedef struct {
|
|
139
|
-
void* nextInChain;
|
|
140
|
-
uint32_t binding;
|
|
141
|
-
uint64_t visibility;
|
|
142
|
-
uint32_t bindingArraySize;
|
|
143
|
-
WGPUBufferBindingLayout buffer;
|
|
144
|
-
WGPUSamplerBindingLayout sampler;
|
|
145
|
-
WGPUTextureBindingLayout texture;
|
|
146
|
-
WGPUStorageTextureBindingLayout storageTexture;
|
|
147
|
-
} WGPUBindGroupLayoutEntry;
|
|
148
|
-
|
|
149
|
-
typedef struct {
|
|
150
|
-
void* nextInChain;
|
|
151
|
-
WGPUStringView label;
|
|
152
|
-
size_t entryCount;
|
|
153
|
-
const WGPUBindGroupLayoutEntry* entries;
|
|
154
|
-
} WGPUBindGroupLayoutDescriptor;
|
|
155
|
-
|
|
156
|
-
typedef struct {
|
|
157
|
-
void* nextInChain;
|
|
158
|
-
uint32_t binding;
|
|
159
|
-
WGPUBuffer buffer;
|
|
160
|
-
uint64_t offset;
|
|
161
|
-
uint64_t size;
|
|
162
|
-
WGPUSampler sampler;
|
|
163
|
-
WGPUTextureView textureView;
|
|
164
|
-
} WGPUBindGroupEntry;
|
|
165
|
-
|
|
166
|
-
typedef struct {
|
|
167
|
-
void* nextInChain;
|
|
168
|
-
WGPUStringView label;
|
|
169
|
-
WGPUBindGroupLayout layout;
|
|
170
|
-
size_t entryCount;
|
|
171
|
-
const WGPUBindGroupEntry* entries;
|
|
172
|
-
} WGPUBindGroupDescriptor;
|
|
173
|
-
|
|
174
|
-
typedef struct {
|
|
175
|
-
void* nextInChain;
|
|
176
|
-
WGPUStringView label;
|
|
177
|
-
size_t bindGroupLayoutCount;
|
|
178
|
-
const WGPUBindGroupLayout* bindGroupLayouts;
|
|
179
|
-
uint32_t immediateSize;
|
|
180
|
-
} WGPUPipelineLayoutDescriptor;
|
|
181
|
-
|
|
182
|
-
typedef struct {
|
|
183
|
-
void* nextInChain;
|
|
184
|
-
WGPUStringView label;
|
|
185
|
-
void* timestampWrites;
|
|
186
|
-
} WGPUComputePassDescriptor;
|
|
187
|
-
|
|
188
|
-
typedef struct {
|
|
189
|
-
uint32_t width;
|
|
190
|
-
uint32_t height;
|
|
191
|
-
uint32_t depthOrArrayLayers;
|
|
192
|
-
} WGPUExtent3D;
|
|
193
|
-
|
|
194
|
-
typedef struct {
|
|
195
|
-
void* nextInChain;
|
|
196
|
-
WGPUStringView label;
|
|
197
|
-
uint64_t usage;
|
|
198
|
-
uint32_t dimension;
|
|
199
|
-
WGPUExtent3D size;
|
|
200
|
-
uint32_t format;
|
|
201
|
-
uint32_t mipLevelCount;
|
|
202
|
-
uint32_t sampleCount;
|
|
203
|
-
size_t viewFormatCount;
|
|
204
|
-
const uint32_t* viewFormats;
|
|
205
|
-
} WGPUTextureDescriptor;
|
|
206
|
-
|
|
207
|
-
typedef struct {
|
|
208
|
-
void* nextInChain;
|
|
209
|
-
WGPUStringView label;
|
|
210
|
-
uint32_t format;
|
|
211
|
-
uint32_t dimension;
|
|
212
|
-
uint32_t baseMipLevel;
|
|
213
|
-
uint32_t mipLevelCount;
|
|
214
|
-
uint32_t baseArrayLayer;
|
|
215
|
-
uint32_t arrayLayerCount;
|
|
216
|
-
uint32_t aspect;
|
|
217
|
-
uint64_t usage;
|
|
218
|
-
} WGPUTextureViewDescriptor;
|
|
219
|
-
|
|
220
|
-
typedef struct {
|
|
221
|
-
void* nextInChain;
|
|
222
|
-
WGPUStringView label;
|
|
223
|
-
uint32_t addressModeU;
|
|
224
|
-
uint32_t addressModeV;
|
|
225
|
-
uint32_t addressModeW;
|
|
226
|
-
uint32_t magFilter;
|
|
227
|
-
uint32_t minFilter;
|
|
228
|
-
uint32_t mipmapFilter;
|
|
229
|
-
float lodMinClamp;
|
|
230
|
-
float lodMaxClamp;
|
|
231
|
-
uint32_t compare;
|
|
232
|
-
uint16_t maxAnisotropy;
|
|
233
|
-
} WGPUSamplerDescriptor;
|
|
234
|
-
|
|
235
|
-
typedef struct { double r; double g; double b; double a; } WGPUColor;
|
|
236
|
-
|
|
237
|
-
typedef struct {
|
|
238
|
-
void* nextInChain;
|
|
239
|
-
WGPUTextureView view;
|
|
240
|
-
uint32_t depthSlice;
|
|
241
|
-
WGPUTextureView resolveTarget;
|
|
242
|
-
uint32_t loadOp;
|
|
243
|
-
uint32_t storeOp;
|
|
244
|
-
WGPUColor clearValue;
|
|
245
|
-
} WGPURenderPassColorAttachment;
|
|
246
|
-
|
|
247
|
-
typedef struct {
|
|
248
|
-
void* nextInChain;
|
|
249
|
-
WGPUStringView label;
|
|
250
|
-
size_t colorAttachmentCount;
|
|
251
|
-
const WGPURenderPassColorAttachment* colorAttachments;
|
|
252
|
-
void* depthStencilAttachment;
|
|
253
|
-
WGPUQuerySet occlusionQuerySet;
|
|
254
|
-
void* timestampWrites;
|
|
255
|
-
} WGPURenderPassDescriptor;
|
|
256
|
-
|
|
257
|
-
typedef struct {
|
|
258
|
-
void* nextInChain;
|
|
259
|
-
uint32_t maxTextureDimension1D;
|
|
260
|
-
uint32_t maxTextureDimension2D;
|
|
261
|
-
uint32_t maxTextureDimension3D;
|
|
262
|
-
uint32_t maxTextureArrayLayers;
|
|
263
|
-
uint32_t maxBindGroups;
|
|
264
|
-
uint32_t maxBindGroupsPlusVertexBuffers;
|
|
265
|
-
uint32_t maxBindingsPerBindGroup;
|
|
266
|
-
uint32_t maxDynamicUniformBuffersPerPipelineLayout;
|
|
267
|
-
uint32_t maxDynamicStorageBuffersPerPipelineLayout;
|
|
268
|
-
uint32_t maxSampledTexturesPerShaderStage;
|
|
269
|
-
uint32_t maxSamplersPerShaderStage;
|
|
270
|
-
uint32_t maxStorageBuffersPerShaderStage;
|
|
271
|
-
uint32_t maxStorageTexturesPerShaderStage;
|
|
272
|
-
uint32_t maxUniformBuffersPerShaderStage;
|
|
273
|
-
uint64_t maxUniformBufferBindingSize;
|
|
274
|
-
uint64_t maxStorageBufferBindingSize;
|
|
275
|
-
uint32_t minUniformBufferOffsetAlignment;
|
|
276
|
-
uint32_t minStorageBufferOffsetAlignment;
|
|
277
|
-
uint32_t maxVertexBuffers;
|
|
278
|
-
uint64_t maxBufferSize;
|
|
279
|
-
uint32_t maxVertexAttributes;
|
|
280
|
-
uint32_t maxVertexBufferArrayStride;
|
|
281
|
-
uint32_t maxInterStageShaderVariables;
|
|
282
|
-
uint32_t maxColorAttachments;
|
|
283
|
-
uint32_t maxColorAttachmentBytesPerSample;
|
|
284
|
-
uint32_t maxComputeWorkgroupStorageSize;
|
|
285
|
-
uint32_t maxComputeInvocationsPerWorkgroup;
|
|
286
|
-
uint32_t maxComputeWorkgroupSizeX;
|
|
287
|
-
uint32_t maxComputeWorkgroupSizeY;
|
|
288
|
-
uint32_t maxComputeWorkgroupSizeZ;
|
|
289
|
-
uint32_t maxComputeWorkgroupsPerDimension;
|
|
290
|
-
uint32_t maxImmediateSize;
|
|
291
|
-
} WGPULimits;
|
|
292
|
-
|
|
293
|
-
#define WGPU_FEATURE_SHADER_F16 0x0000000B
|
|
294
|
-
|
|
295
|
-
/* Callback types */
|
|
296
|
-
typedef void (*WGPURequestAdapterCallback)(
|
|
297
|
-
uint32_t status, WGPUAdapter adapter, WGPUStringView message,
|
|
298
|
-
void* userdata1, void* userdata2);
|
|
299
|
-
|
|
300
|
-
typedef void (*WGPURequestDeviceCallback)(
|
|
301
|
-
uint32_t status, WGPUDevice device, WGPUStringView message,
|
|
302
|
-
void* userdata1, void* userdata2);
|
|
303
|
-
|
|
304
|
-
typedef void (*WGPUBufferMapCallback)(
|
|
305
|
-
uint32_t status, WGPUStringView message,
|
|
306
|
-
void* userdata1, void* userdata2);
|
|
307
|
-
|
|
308
|
-
/* ================================================================
|
|
309
|
-
* Function pointer types and global storage
|
|
310
|
-
* ================================================================ */
|
|
311
|
-
|
|
312
|
-
#define DECL_PFN(ret, name, params) typedef ret (*PFN_##name) params; static PFN_##name pfn_##name = NULL
|
|
313
|
-
|
|
314
|
-
DECL_PFN(WGPUInstance, wgpuCreateInstance, (const void*));
|
|
315
|
-
DECL_PFN(void, wgpuInstanceRelease, (WGPUInstance));
|
|
316
|
-
DECL_PFN(uint32_t, wgpuInstanceWaitAny, (WGPUInstance, size_t, WGPUFutureWaitInfo*, uint64_t));
|
|
317
|
-
DECL_PFN(void, wgpuInstanceProcessEvents, (WGPUInstance));
|
|
318
|
-
DECL_PFN(void, wgpuAdapterRelease, (WGPUAdapter));
|
|
319
|
-
DECL_PFN(WGPUBool, wgpuAdapterHasFeature, (WGPUAdapter, uint32_t));
|
|
320
|
-
DECL_PFN(void, wgpuDeviceRelease, (WGPUDevice));
|
|
321
|
-
DECL_PFN(WGPUBool, wgpuDeviceHasFeature, (WGPUDevice, uint32_t));
|
|
322
|
-
DECL_PFN(WGPUQueue, wgpuDeviceGetQueue, (WGPUDevice));
|
|
323
|
-
DECL_PFN(WGPUBuffer, wgpuDeviceCreateBuffer, (WGPUDevice, const WGPUBufferDescriptor*));
|
|
324
|
-
DECL_PFN(WGPUShaderModule, wgpuDeviceCreateShaderModule, (WGPUDevice, const WGPUShaderModuleDescriptor*));
|
|
325
|
-
DECL_PFN(void, wgpuShaderModuleRelease, (WGPUShaderModule));
|
|
326
|
-
DECL_PFN(WGPUComputePipeline, wgpuDeviceCreateComputePipeline, (WGPUDevice, const WGPUComputePipelineDescriptor*));
|
|
327
|
-
DECL_PFN(void, wgpuComputePipelineRelease, (WGPUComputePipeline));
|
|
328
|
-
DECL_PFN(WGPUBindGroupLayout, wgpuComputePipelineGetBindGroupLayout, (WGPUComputePipeline, uint32_t));
|
|
329
|
-
DECL_PFN(WGPUBindGroupLayout, wgpuDeviceCreateBindGroupLayout, (WGPUDevice, const WGPUBindGroupLayoutDescriptor*));
|
|
330
|
-
DECL_PFN(void, wgpuBindGroupLayoutRelease, (WGPUBindGroupLayout));
|
|
331
|
-
DECL_PFN(WGPUBindGroup, wgpuDeviceCreateBindGroup, (WGPUDevice, const WGPUBindGroupDescriptor*));
|
|
332
|
-
DECL_PFN(void, wgpuBindGroupRelease, (WGPUBindGroup));
|
|
333
|
-
DECL_PFN(WGPUPipelineLayout, wgpuDeviceCreatePipelineLayout, (WGPUDevice, const WGPUPipelineLayoutDescriptor*));
|
|
334
|
-
DECL_PFN(void, wgpuPipelineLayoutRelease, (WGPUPipelineLayout));
|
|
335
|
-
DECL_PFN(WGPUCommandEncoder, wgpuDeviceCreateCommandEncoder, (WGPUDevice, const WGPUCommandEncoderDescriptor*));
|
|
336
|
-
DECL_PFN(void, wgpuCommandEncoderRelease, (WGPUCommandEncoder));
|
|
337
|
-
DECL_PFN(WGPUComputePassEncoder, wgpuCommandEncoderBeginComputePass, (WGPUCommandEncoder, const WGPUComputePassDescriptor*));
|
|
338
|
-
DECL_PFN(void, wgpuCommandEncoderCopyBufferToBuffer, (WGPUCommandEncoder, WGPUBuffer, uint64_t, WGPUBuffer, uint64_t, uint64_t));
|
|
339
|
-
DECL_PFN(WGPUCommandBuffer, wgpuCommandEncoderFinish, (WGPUCommandEncoder, const WGPUCommandBufferDescriptor*));
|
|
340
|
-
DECL_PFN(void, wgpuComputePassEncoderSetPipeline, (WGPUComputePassEncoder, WGPUComputePipeline));
|
|
341
|
-
DECL_PFN(void, wgpuComputePassEncoderSetBindGroup, (WGPUComputePassEncoder, uint32_t, WGPUBindGroup, size_t, const uint32_t*));
|
|
342
|
-
DECL_PFN(void, wgpuComputePassEncoderDispatchWorkgroups, (WGPUComputePassEncoder, uint32_t, uint32_t, uint32_t));
|
|
343
|
-
DECL_PFN(void, wgpuComputePassEncoderDispatchWorkgroupsIndirect, (WGPUComputePassEncoder, WGPUBuffer, uint64_t));
|
|
344
|
-
DECL_PFN(void, wgpuComputePassEncoderEnd, (WGPUComputePassEncoder));
|
|
345
|
-
DECL_PFN(void, wgpuComputePassEncoderRelease, (WGPUComputePassEncoder));
|
|
346
|
-
DECL_PFN(void, wgpuQueueSubmit, (WGPUQueue, size_t, const WGPUCommandBuffer*));
|
|
347
|
-
DECL_PFN(void, wgpuQueueWriteBuffer, (WGPUQueue, WGPUBuffer, uint64_t, const void*, size_t));
|
|
348
|
-
DECL_PFN(void, wgpuQueueRelease, (WGPUQueue));
|
|
349
|
-
DECL_PFN(void, doeNativeQueueFlush, (WGPUQueue));
|
|
350
|
-
DECL_PFN(void, wgpuBufferRelease, (WGPUBuffer));
|
|
351
|
-
DECL_PFN(void, wgpuBufferUnmap, (WGPUBuffer));
|
|
352
|
-
DECL_PFN(const void*, wgpuBufferGetConstMappedRange, (WGPUBuffer, size_t, size_t));
|
|
353
|
-
DECL_PFN(void*, wgpuBufferGetMappedRange, (WGPUBuffer, size_t, size_t));
|
|
354
|
-
DECL_PFN(void, wgpuCommandBufferRelease, (WGPUCommandBuffer));
|
|
355
|
-
DECL_PFN(WGPUTexture, wgpuDeviceCreateTexture, (WGPUDevice, const WGPUTextureDescriptor*));
|
|
356
|
-
DECL_PFN(WGPUTextureView, wgpuTextureCreateView, (WGPUTexture, const WGPUTextureViewDescriptor*));
|
|
357
|
-
DECL_PFN(void, wgpuTextureRelease, (WGPUTexture));
|
|
358
|
-
DECL_PFN(void, wgpuTextureViewRelease, (WGPUTextureView));
|
|
359
|
-
DECL_PFN(WGPUSampler, wgpuDeviceCreateSampler, (WGPUDevice, const WGPUSamplerDescriptor*));
|
|
360
|
-
DECL_PFN(void, wgpuSamplerRelease, (WGPUSampler));
|
|
361
|
-
DECL_PFN(WGPURenderPipeline, wgpuDeviceCreateRenderPipeline, (WGPUDevice, const void*));
|
|
362
|
-
DECL_PFN(void, wgpuRenderPipelineRelease, (WGPURenderPipeline));
|
|
363
|
-
DECL_PFN(WGPURenderPassEncoder, wgpuCommandEncoderBeginRenderPass, (WGPUCommandEncoder, const WGPURenderPassDescriptor*));
|
|
364
|
-
DECL_PFN(void, wgpuRenderPassEncoderSetPipeline, (WGPURenderPassEncoder, WGPURenderPipeline));
|
|
365
|
-
DECL_PFN(void, wgpuRenderPassEncoderDraw, (WGPURenderPassEncoder, uint32_t, uint32_t, uint32_t, uint32_t));
|
|
366
|
-
DECL_PFN(void, wgpuRenderPassEncoderEnd, (WGPURenderPassEncoder));
|
|
367
|
-
DECL_PFN(void, wgpuRenderPassEncoderRelease, (WGPURenderPassEncoder));
|
|
368
|
-
DECL_PFN(uint32_t, wgpuDeviceGetLimits, (WGPUDevice, void*));
|
|
369
|
-
|
|
370
|
-
/* Flat helpers for FFI-friendly adapter/device request */
|
|
371
|
-
DECL_PFN(WGPUFuture, doeRequestAdapterFlat, (WGPUInstance, const void*, uint32_t, WGPURequestAdapterCallback, void*, void*));
|
|
372
|
-
DECL_PFN(WGPUFuture, doeRequestDeviceFlat, (WGPUAdapter, const void*, uint32_t, WGPURequestDeviceCallback, void*, void*));
|
|
373
|
-
typedef struct {
|
|
374
|
-
void* nextInChain;
|
|
375
|
-
uint32_t mode;
|
|
376
|
-
WGPUBufferMapCallback callback;
|
|
377
|
-
void* userdata1;
|
|
378
|
-
void* userdata2;
|
|
379
|
-
} WGPUBufferMapCallbackInfo;
|
|
380
|
-
|
|
381
|
-
typedef WGPUFuture (*PFN_wgpuBufferMapAsync2)(WGPUBuffer, uint64_t, size_t, size_t, WGPUBufferMapCallbackInfo);
|
|
382
|
-
static PFN_wgpuBufferMapAsync2 pfn_wgpuBufferMapAsync2 = NULL;
|
|
383
|
-
|
|
384
|
-
static void* g_lib = NULL;
|
|
385
|
-
|
|
386
|
-
/* ================================================================
|
|
387
|
-
* N-API utility helpers
|
|
388
|
-
* ================================================================ */
|
|
389
|
-
|
|
390
|
-
#define NAPI_THROW(env, msg) do { napi_throw_error(env, NULL, msg); return NULL; } while(0)
|
|
391
|
-
#define MAX_NAPI_ARGS 8
|
|
392
|
-
#define NAPI_ASSERT_ARGC(env, info, n) \
|
|
393
|
-
size_t _argc = (n); napi_value _args[MAX_NAPI_ARGS]; \
|
|
394
|
-
if ((n) > MAX_NAPI_ARGS) NAPI_THROW(env, "too many args"); \
|
|
395
|
-
if (napi_get_cb_info(env, info, &_argc, _args, NULL, NULL) != napi_ok) NAPI_THROW(env, "napi_get_cb_info failed")
|
|
396
|
-
#define CHECK_LIB_LOADED(env) do { if (!g_lib) NAPI_THROW(env, "Library not loaded"); } while(0)
|
|
397
|
-
|
|
398
|
-
static void* unwrap_ptr(napi_env env, napi_value val) {
|
|
399
|
-
void* ptr = NULL;
|
|
400
|
-
napi_get_value_external(env, val, &ptr);
|
|
401
|
-
return ptr;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* Release callback for GC'd externals. Logs but cannot release because we
|
|
405
|
-
* don't know the handle type. Prevents silent leaks in long-lived processes. */
|
|
406
|
-
static void handle_Release_hint(napi_env env, void* data, void* hint) {
|
|
407
|
-
(void)env; (void)hint;
|
|
408
|
-
/* If data is non-null, the JS side forgot to call release().
|
|
409
|
-
* We cannot safely call the typed release here without knowing the type,
|
|
410
|
-
* so this is intentionally a no-op — but the destructor being non-NULL
|
|
411
|
-
* means napi will not leak the ref-tracking entry. */
|
|
412
|
-
(void)data;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
static napi_value wrap_ptr(napi_env env, void* ptr) {
|
|
416
|
-
napi_value result;
|
|
417
|
-
if (napi_create_external(env, ptr, handle_Release_hint, NULL, &result) != napi_ok) return NULL;
|
|
418
|
-
return result;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
static uint32_t get_uint32_prop(napi_env env, napi_value obj, const char* key) {
|
|
422
|
-
napi_value val;
|
|
423
|
-
napi_get_named_property(env, obj, key, &val);
|
|
424
|
-
uint32_t out = 0;
|
|
425
|
-
napi_get_value_uint32(env, val, &out);
|
|
426
|
-
return out;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
static int64_t get_int64_prop(napi_env env, napi_value obj, const char* key) {
|
|
430
|
-
napi_value val;
|
|
431
|
-
napi_get_named_property(env, obj, key, &val);
|
|
432
|
-
int64_t out = 0;
|
|
433
|
-
napi_get_value_int64(env, val, &out);
|
|
434
|
-
return out;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
static bool get_bool_prop(napi_env env, napi_value obj, const char* key) {
|
|
438
|
-
napi_value val;
|
|
439
|
-
napi_get_named_property(env, obj, key, &val);
|
|
440
|
-
napi_valuetype vt;
|
|
441
|
-
napi_typeof(env, val, &vt);
|
|
442
|
-
if (vt != napi_boolean) return false;
|
|
443
|
-
bool out = false;
|
|
444
|
-
napi_get_value_bool(env, val, &out);
|
|
445
|
-
return out;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
static bool has_prop(napi_env env, napi_value obj, const char* key) {
|
|
449
|
-
bool result = false;
|
|
450
|
-
napi_has_named_property(env, obj, key, &result);
|
|
451
|
-
return result;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
static napi_value get_prop(napi_env env, napi_value obj, const char* key) {
|
|
455
|
-
napi_value val;
|
|
456
|
-
napi_get_named_property(env, obj, key, &val);
|
|
457
|
-
return val;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
static napi_valuetype prop_type(napi_env env, napi_value obj, const char* key) {
|
|
461
|
-
napi_value val;
|
|
462
|
-
napi_get_named_property(env, obj, key, &val);
|
|
463
|
-
napi_valuetype vt;
|
|
464
|
-
napi_typeof(env, val, &vt);
|
|
465
|
-
return vt;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/* ================================================================
|
|
469
|
-
* Library loading
|
|
470
|
-
* ================================================================ */
|
|
471
|
-
|
|
472
|
-
#define LOAD_SYM(name) pfn_##name = (PFN_##name)LIB_SYM(g_lib, #name)
|
|
473
|
-
|
|
474
|
-
static napi_value doe_load_library(napi_env env, napi_callback_info info) {
|
|
475
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
476
|
-
size_t path_len = 0;
|
|
477
|
-
napi_get_value_string_utf8(env, _args[0], NULL, 0, &path_len);
|
|
478
|
-
char* path = (char*)malloc(path_len + 1);
|
|
479
|
-
napi_get_value_string_utf8(env, _args[0], path, path_len + 1, &path_len);
|
|
480
|
-
|
|
481
|
-
if (g_lib) { LIB_CLOSE(g_lib); g_lib = NULL; }
|
|
482
|
-
g_lib = LIB_OPEN(path);
|
|
483
|
-
free(path);
|
|
484
|
-
if (!g_lib) NAPI_THROW(env, "Failed to load libdoe_webgpu");
|
|
485
|
-
|
|
486
|
-
/* Load native Metal backend symbols (doeNative*) — bypasses Dawn routing. */
|
|
487
|
-
#define LOAD_NATIVE(pfn_name, native_name) pfn_##pfn_name = (PFN_##pfn_name)LIB_SYM(g_lib, #native_name)
|
|
488
|
-
LOAD_NATIVE(wgpuCreateInstance, doeNativeCreateInstance);
|
|
489
|
-
LOAD_NATIVE(wgpuInstanceRelease, doeNativeInstanceRelease);
|
|
490
|
-
LOAD_NATIVE(wgpuInstanceWaitAny, doeNativeInstanceWaitAny);
|
|
491
|
-
LOAD_NATIVE(wgpuInstanceProcessEvents, doeNativeInstanceProcessEvents);
|
|
492
|
-
LOAD_NATIVE(wgpuAdapterRelease, doeNativeAdapterRelease);
|
|
493
|
-
LOAD_NATIVE(wgpuAdapterHasFeature, doeNativeAdapterHasFeature);
|
|
494
|
-
LOAD_NATIVE(wgpuDeviceRelease, doeNativeDeviceRelease);
|
|
495
|
-
LOAD_NATIVE(wgpuDeviceHasFeature, doeNativeDeviceHasFeature);
|
|
496
|
-
LOAD_NATIVE(wgpuDeviceGetQueue, doeNativeDeviceGetQueue);
|
|
497
|
-
LOAD_NATIVE(wgpuDeviceCreateBuffer, doeNativeDeviceCreateBuffer);
|
|
498
|
-
LOAD_NATIVE(wgpuDeviceCreateShaderModule, doeNativeDeviceCreateShaderModule);
|
|
499
|
-
LOAD_NATIVE(wgpuShaderModuleRelease, doeNativeShaderModuleRelease);
|
|
500
|
-
LOAD_NATIVE(wgpuDeviceCreateComputePipeline, doeNativeDeviceCreateComputePipeline);
|
|
501
|
-
LOAD_NATIVE(wgpuComputePipelineRelease, doeNativeComputePipelineRelease);
|
|
502
|
-
LOAD_NATIVE(wgpuComputePipelineGetBindGroupLayout, doeNativeComputePipelineGetBindGroupLayout);
|
|
503
|
-
LOAD_NATIVE(wgpuDeviceCreateBindGroupLayout, doeNativeDeviceCreateBindGroupLayout);
|
|
504
|
-
LOAD_NATIVE(wgpuBindGroupLayoutRelease, doeNativeBindGroupLayoutRelease);
|
|
505
|
-
LOAD_NATIVE(wgpuDeviceCreateBindGroup, doeNativeDeviceCreateBindGroup);
|
|
506
|
-
LOAD_NATIVE(wgpuBindGroupRelease, doeNativeBindGroupRelease);
|
|
507
|
-
LOAD_NATIVE(wgpuDeviceCreatePipelineLayout, doeNativeDeviceCreatePipelineLayout);
|
|
508
|
-
LOAD_NATIVE(wgpuPipelineLayoutRelease, doeNativePipelineLayoutRelease);
|
|
509
|
-
LOAD_NATIVE(wgpuDeviceCreateCommandEncoder, doeNativeDeviceCreateCommandEncoder);
|
|
510
|
-
LOAD_NATIVE(wgpuCommandEncoderRelease, doeNativeCommandEncoderRelease);
|
|
511
|
-
LOAD_NATIVE(wgpuCommandEncoderBeginComputePass, doeNativeCommandEncoderBeginComputePass);
|
|
512
|
-
LOAD_NATIVE(wgpuCommandEncoderCopyBufferToBuffer, doeNativeCopyBufferToBuffer);
|
|
513
|
-
LOAD_NATIVE(wgpuCommandEncoderFinish, doeNativeCommandEncoderFinish);
|
|
514
|
-
LOAD_NATIVE(wgpuComputePassEncoderSetPipeline, doeNativeComputePassSetPipeline);
|
|
515
|
-
LOAD_NATIVE(wgpuComputePassEncoderSetBindGroup, doeNativeComputePassSetBindGroup);
|
|
516
|
-
LOAD_NATIVE(wgpuComputePassEncoderDispatchWorkgroups, doeNativeComputePassDispatch);
|
|
517
|
-
LOAD_NATIVE(wgpuComputePassEncoderDispatchWorkgroupsIndirect, doeNativeComputePassDispatchIndirect);
|
|
518
|
-
LOAD_NATIVE(wgpuComputePassEncoderEnd, doeNativeComputePassEnd);
|
|
519
|
-
LOAD_NATIVE(wgpuComputePassEncoderRelease, doeNativeComputePassRelease);
|
|
520
|
-
LOAD_NATIVE(wgpuQueueSubmit, doeNativeQueueSubmit);
|
|
521
|
-
LOAD_NATIVE(wgpuQueueWriteBuffer, doeNativeQueueWriteBuffer);
|
|
522
|
-
LOAD_NATIVE(wgpuQueueRelease, doeNativeQueueRelease);
|
|
523
|
-
LOAD_NATIVE(doeNativeQueueFlush, doeNativeQueueFlush);
|
|
524
|
-
LOAD_NATIVE(wgpuBufferRelease, doeNativeBufferRelease);
|
|
525
|
-
LOAD_NATIVE(wgpuBufferUnmap, doeNativeBufferUnmap);
|
|
526
|
-
LOAD_NATIVE(wgpuBufferGetConstMappedRange, doeNativeBufferGetConstMappedRange);
|
|
527
|
-
LOAD_NATIVE(wgpuBufferGetMappedRange, doeNativeBufferGetMappedRange);
|
|
528
|
-
LOAD_NATIVE(wgpuCommandBufferRelease, doeNativeCommandBufferRelease);
|
|
529
|
-
LOAD_NATIVE(wgpuDeviceCreateTexture, doeNativeDeviceCreateTexture);
|
|
530
|
-
LOAD_NATIVE(wgpuTextureCreateView, doeNativeTextureCreateView);
|
|
531
|
-
LOAD_NATIVE(wgpuTextureRelease, doeNativeTextureRelease);
|
|
532
|
-
LOAD_NATIVE(wgpuTextureViewRelease, doeNativeTextureViewRelease);
|
|
533
|
-
LOAD_NATIVE(wgpuDeviceCreateSampler, doeNativeDeviceCreateSampler);
|
|
534
|
-
LOAD_NATIVE(wgpuSamplerRelease, doeNativeSamplerRelease);
|
|
535
|
-
LOAD_NATIVE(wgpuDeviceCreateRenderPipeline, doeNativeDeviceCreateRenderPipeline);
|
|
536
|
-
LOAD_NATIVE(wgpuRenderPipelineRelease, doeNativeRenderPipelineRelease);
|
|
537
|
-
LOAD_NATIVE(wgpuCommandEncoderBeginRenderPass, doeNativeCommandEncoderBeginRenderPass);
|
|
538
|
-
LOAD_NATIVE(wgpuRenderPassEncoderSetPipeline, doeNativeRenderPassSetPipeline);
|
|
539
|
-
LOAD_NATIVE(wgpuRenderPassEncoderDraw, doeNativeRenderPassDraw);
|
|
540
|
-
LOAD_NATIVE(wgpuRenderPassEncoderEnd, doeNativeRenderPassEnd);
|
|
541
|
-
LOAD_NATIVE(wgpuRenderPassEncoderRelease, doeNativeRenderPassRelease);
|
|
542
|
-
LOAD_NATIVE(wgpuDeviceGetLimits, doeNativeDeviceGetLimits);
|
|
543
|
-
LOAD_NATIVE(doeRequestAdapterFlat, doeNativeRequestAdapterFlat);
|
|
544
|
-
LOAD_NATIVE(doeRequestDeviceFlat, doeNativeRequestDeviceFlat);
|
|
545
|
-
pfn_wgpuBufferMapAsync2 = (PFN_wgpuBufferMapAsync2)LIB_SYM(g_lib, "doeNativeBufferMapAsync");
|
|
546
|
-
#undef LOAD_NATIVE
|
|
547
|
-
|
|
548
|
-
/* Validate all critical function pointers were resolved. */
|
|
549
|
-
if (!pfn_wgpuCreateInstance || !pfn_wgpuInstanceRelease || !pfn_wgpuInstanceWaitAny ||
|
|
550
|
-
!pfn_doeRequestAdapterFlat || !pfn_doeRequestDeviceFlat ||
|
|
551
|
-
!pfn_wgpuDeviceGetQueue || !pfn_wgpuDeviceCreateBuffer ||
|
|
552
|
-
!pfn_wgpuDeviceCreateShaderModule || !pfn_wgpuDeviceCreateComputePipeline ||
|
|
553
|
-
!pfn_wgpuDeviceCreateCommandEncoder || !pfn_wgpuCommandEncoderBeginComputePass ||
|
|
554
|
-
!pfn_wgpuCommandEncoderFinish || !pfn_wgpuQueueSubmit ||
|
|
555
|
-
!pfn_wgpuBufferMapAsync2) {
|
|
556
|
-
LIB_CLOSE(g_lib);
|
|
557
|
-
g_lib = NULL;
|
|
558
|
-
NAPI_THROW(env, "Failed to resolve required symbols from libdoe_webgpu");
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
napi_value result;
|
|
562
|
-
napi_get_boolean(env, true, &result);
|
|
563
|
-
return result;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/* ================================================================
|
|
567
|
-
* Instance
|
|
568
|
-
* ================================================================ */
|
|
569
|
-
|
|
570
|
-
static napi_value doe_create_instance(napi_env env, napi_callback_info info) {
|
|
571
|
-
(void)info;
|
|
572
|
-
CHECK_LIB_LOADED(env);
|
|
573
|
-
/* Doe ignores the descriptor — pass NULL for clarity. */
|
|
574
|
-
WGPUInstance inst = pfn_wgpuCreateInstance(NULL);
|
|
575
|
-
if (!inst) NAPI_THROW(env, "wgpuCreateInstance returned NULL");
|
|
576
|
-
return wrap_ptr(env, inst);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
static napi_value doe_instance_release(napi_env env, napi_callback_info info) {
|
|
580
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
581
|
-
void* inst = unwrap_ptr(env, _args[0]);
|
|
582
|
-
if (inst) pfn_wgpuInstanceRelease(inst);
|
|
583
|
-
return NULL;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/* ================================================================
|
|
587
|
-
* Adapter (synchronous requestAdapter via WaitAny)
|
|
588
|
-
* ================================================================ */
|
|
589
|
-
|
|
590
|
-
typedef struct {
|
|
591
|
-
uint32_t status;
|
|
592
|
-
WGPUAdapter adapter;
|
|
593
|
-
} AdapterRequestResult;
|
|
594
|
-
|
|
595
|
-
static void adapter_callback(uint32_t status, WGPUAdapter adapter,
|
|
596
|
-
WGPUStringView message, void* userdata1, void* userdata2) {
|
|
597
|
-
(void)message; (void)userdata2;
|
|
598
|
-
AdapterRequestResult* r = (AdapterRequestResult*)userdata1;
|
|
599
|
-
r->status = status;
|
|
600
|
-
r->adapter = adapter;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
static napi_value doe_request_adapter(napi_env env, napi_callback_info info) {
|
|
604
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
605
|
-
CHECK_LIB_LOADED(env);
|
|
606
|
-
WGPUInstance inst = unwrap_ptr(env, _args[0]);
|
|
607
|
-
if (!inst) NAPI_THROW(env, "Invalid instance");
|
|
608
|
-
|
|
609
|
-
AdapterRequestResult result = {0, NULL};
|
|
610
|
-
WGPUFuture future = pfn_doeRequestAdapterFlat(
|
|
611
|
-
inst, NULL, 1 /* WaitAnyOnly */, adapter_callback, &result, NULL);
|
|
612
|
-
|
|
613
|
-
WGPUFutureWaitInfo wait_info = { .future = future, .completed = 0 };
|
|
614
|
-
uint32_t wait_status = pfn_wgpuInstanceWaitAny(
|
|
615
|
-
inst, 1, &wait_info, (uint64_t)5000000000ULL);
|
|
616
|
-
|
|
617
|
-
if (wait_status != WGPU_WAIT_STATUS_SUCCESS ||
|
|
618
|
-
result.status != WGPU_REQUEST_STATUS_SUCCESS || !result.adapter)
|
|
619
|
-
NAPI_THROW(env, "requestAdapter failed");
|
|
620
|
-
|
|
621
|
-
return wrap_ptr(env, result.adapter);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
static napi_value doe_adapter_release(napi_env env, napi_callback_info info) {
|
|
625
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
626
|
-
void* adapter = unwrap_ptr(env, _args[0]);
|
|
627
|
-
if (adapter) pfn_wgpuAdapterRelease(adapter);
|
|
628
|
-
return NULL;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/* ================================================================
|
|
632
|
-
* Device (synchronous requestDevice via WaitAny)
|
|
633
|
-
* ================================================================ */
|
|
634
|
-
|
|
635
|
-
typedef struct {
|
|
636
|
-
uint32_t status;
|
|
637
|
-
WGPUDevice device;
|
|
638
|
-
} DeviceRequestResult;
|
|
639
|
-
|
|
640
|
-
static void device_callback(uint32_t status, WGPUDevice device,
|
|
641
|
-
WGPUStringView message, void* userdata1, void* userdata2) {
|
|
642
|
-
(void)message; (void)userdata2;
|
|
643
|
-
DeviceRequestResult* r = (DeviceRequestResult*)userdata1;
|
|
644
|
-
r->status = status;
|
|
645
|
-
r->device = device;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
static napi_value doe_request_device(napi_env env, napi_callback_info info) {
|
|
649
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
650
|
-
CHECK_LIB_LOADED(env);
|
|
651
|
-
WGPUInstance inst = unwrap_ptr(env, _args[0]);
|
|
652
|
-
WGPUAdapter adapter = unwrap_ptr(env, _args[1]);
|
|
653
|
-
if (!inst || !adapter) NAPI_THROW(env, "Invalid instance or adapter");
|
|
654
|
-
|
|
655
|
-
DeviceRequestResult result = {0, NULL};
|
|
656
|
-
WGPUFuture future = pfn_doeRequestDeviceFlat(
|
|
657
|
-
adapter, NULL, 1 /* WaitAnyOnly */, device_callback, &result, NULL);
|
|
658
|
-
|
|
659
|
-
WGPUFutureWaitInfo wait_info = { .future = future, .completed = 0 };
|
|
660
|
-
uint32_t wait_status = pfn_wgpuInstanceWaitAny(
|
|
661
|
-
inst, 1, &wait_info, (uint64_t)5000000000ULL);
|
|
662
|
-
|
|
663
|
-
if (wait_status != WGPU_WAIT_STATUS_SUCCESS ||
|
|
664
|
-
result.status != WGPU_REQUEST_STATUS_SUCCESS || !result.device)
|
|
665
|
-
NAPI_THROW(env, "requestDevice failed");
|
|
666
|
-
|
|
667
|
-
return wrap_ptr(env, result.device);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
static napi_value doe_device_release(napi_env env, napi_callback_info info) {
|
|
671
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
672
|
-
void* device = unwrap_ptr(env, _args[0]);
|
|
673
|
-
if (device) pfn_wgpuDeviceRelease(device);
|
|
674
|
-
return NULL;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
static napi_value doe_device_get_queue(napi_env env, napi_callback_info info) {
|
|
678
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
679
|
-
CHECK_LIB_LOADED(env);
|
|
680
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
681
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
682
|
-
WGPUQueue queue = pfn_wgpuDeviceGetQueue(device);
|
|
683
|
-
return wrap_ptr(env, queue);
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/* ================================================================
|
|
687
|
-
* Buffer
|
|
688
|
-
* ================================================================ */
|
|
689
|
-
|
|
690
|
-
static napi_value doe_create_buffer(napi_env env, napi_callback_info info) {
|
|
691
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
692
|
-
CHECK_LIB_LOADED(env);
|
|
693
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
694
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
695
|
-
|
|
696
|
-
WGPUBufferDescriptor desc;
|
|
697
|
-
memset(&desc, 0, sizeof(desc));
|
|
698
|
-
desc.usage = (uint64_t)get_int64_prop(env, _args[1], "usage");
|
|
699
|
-
desc.size = (uint64_t)get_int64_prop(env, _args[1], "size");
|
|
700
|
-
desc.mappedAtCreation = get_bool_prop(env, _args[1], "mappedAtCreation") ? 1 : 0;
|
|
701
|
-
|
|
702
|
-
WGPUBuffer buf = pfn_wgpuDeviceCreateBuffer(device, &desc);
|
|
703
|
-
if (!buf) NAPI_THROW(env, "createBuffer failed");
|
|
704
|
-
return wrap_ptr(env, buf);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
static napi_value doe_buffer_release(napi_env env, napi_callback_info info) {
|
|
708
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
709
|
-
void* buf = unwrap_ptr(env, _args[0]);
|
|
710
|
-
if (buf) pfn_wgpuBufferRelease(buf);
|
|
711
|
-
return NULL;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
static napi_value doe_buffer_unmap(napi_env env, napi_callback_info info) {
|
|
715
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
716
|
-
WGPUBuffer buf = unwrap_ptr(env, _args[0]);
|
|
717
|
-
if (buf) pfn_wgpuBufferUnmap(buf);
|
|
718
|
-
return NULL;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
typedef struct {
|
|
722
|
-
uint32_t status;
|
|
723
|
-
} BufferMapResult;
|
|
724
|
-
|
|
725
|
-
static void buffer_map_callback(uint32_t status, WGPUStringView message,
|
|
726
|
-
void* userdata1, void* userdata2) {
|
|
727
|
-
(void)message; (void)userdata2;
|
|
728
|
-
BufferMapResult* r = (BufferMapResult*)userdata1;
|
|
729
|
-
r->status = status;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/* bufferMapSync(instance, buffer, mode, offset, size) */
|
|
733
|
-
static napi_value doe_buffer_map_sync(napi_env env, napi_callback_info info) {
|
|
734
|
-
NAPI_ASSERT_ARGC(env, info, 5);
|
|
735
|
-
CHECK_LIB_LOADED(env);
|
|
736
|
-
WGPUInstance inst = unwrap_ptr(env, _args[0]);
|
|
737
|
-
WGPUBuffer buf = unwrap_ptr(env, _args[1]);
|
|
738
|
-
uint32_t mode;
|
|
739
|
-
napi_get_value_uint32(env, _args[2], &mode);
|
|
740
|
-
int64_t offset_i, size_i;
|
|
741
|
-
napi_get_value_int64(env, _args[3], &offset_i);
|
|
742
|
-
napi_get_value_int64(env, _args[4], &size_i);
|
|
743
|
-
|
|
744
|
-
BufferMapResult result = {0};
|
|
745
|
-
WGPUBufferMapCallbackInfo cb_info = {
|
|
746
|
-
.nextInChain = NULL,
|
|
747
|
-
.mode = 1, /* WaitAnyOnly */
|
|
748
|
-
.callback = buffer_map_callback,
|
|
749
|
-
.userdata1 = &result,
|
|
750
|
-
.userdata2 = NULL,
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
WGPUFuture future = pfn_wgpuBufferMapAsync2(buf, (uint64_t)mode,
|
|
754
|
-
(size_t)offset_i, (size_t)size_i, cb_info);
|
|
755
|
-
|
|
756
|
-
WGPUFutureWaitInfo wait_info = { .future = future, .completed = 0 };
|
|
757
|
-
uint32_t wait_status = pfn_wgpuInstanceWaitAny(
|
|
758
|
-
inst, 1, &wait_info, (uint64_t)5000000000ULL);
|
|
759
|
-
|
|
760
|
-
if (wait_status != WGPU_WAIT_STATUS_SUCCESS ||
|
|
761
|
-
result.status != WGPU_MAP_ASYNC_STATUS_SUCCESS)
|
|
762
|
-
NAPI_THROW(env, "bufferMapAsync failed");
|
|
763
|
-
|
|
764
|
-
napi_value ok;
|
|
765
|
-
napi_get_boolean(env, true, &ok);
|
|
766
|
-
return ok;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
/* bufferGetMappedRange(buffer, offset, size) → ArrayBuffer */
|
|
770
|
-
static napi_value doe_buffer_get_mapped_range(napi_env env, napi_callback_info info) {
|
|
771
|
-
NAPI_ASSERT_ARGC(env, info, 3);
|
|
772
|
-
CHECK_LIB_LOADED(env);
|
|
773
|
-
WGPUBuffer buf = unwrap_ptr(env, _args[0]);
|
|
774
|
-
int64_t offset_i, size_i;
|
|
775
|
-
napi_get_value_int64(env, _args[1], &offset_i);
|
|
776
|
-
napi_get_value_int64(env, _args[2], &size_i);
|
|
777
|
-
|
|
778
|
-
const void* data = pfn_wgpuBufferGetConstMappedRange(buf, (size_t)offset_i, (size_t)size_i);
|
|
779
|
-
if (!data) NAPI_THROW(env, "getMappedRange returned NULL");
|
|
780
|
-
|
|
781
|
-
/* Copy native data into a JS ArrayBuffer */
|
|
782
|
-
void* ab_data = NULL;
|
|
783
|
-
napi_value ab;
|
|
784
|
-
napi_create_arraybuffer(env, (size_t)size_i, &ab_data, &ab);
|
|
785
|
-
memcpy(ab_data, data, (size_t)size_i);
|
|
786
|
-
return ab;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
/* ================================================================
|
|
790
|
-
* Shader Module
|
|
791
|
-
* ================================================================ */
|
|
792
|
-
|
|
793
|
-
static napi_value doe_create_shader_module(napi_env env, napi_callback_info info) {
|
|
794
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
795
|
-
CHECK_LIB_LOADED(env);
|
|
796
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
797
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
798
|
-
|
|
799
|
-
/* _args[1] is the WGSL source code string */
|
|
800
|
-
size_t code_len = 0;
|
|
801
|
-
napi_get_value_string_utf8(env, _args[1], NULL, 0, &code_len);
|
|
802
|
-
char* code = (char*)malloc(code_len + 1);
|
|
803
|
-
napi_get_value_string_utf8(env, _args[1], code, code_len + 1, &code_len);
|
|
804
|
-
|
|
805
|
-
WGPUShaderSourceWGSL wgsl_source = {
|
|
806
|
-
.chain = { .next = NULL, .sType = WGPU_STYPE_SHADER_SOURCE_WGSL },
|
|
807
|
-
.code = { .data = code, .length = code_len },
|
|
808
|
-
};
|
|
809
|
-
WGPUShaderModuleDescriptor desc = {
|
|
810
|
-
.nextInChain = (void*)&wgsl_source,
|
|
811
|
-
.label = { .data = NULL, .length = 0 },
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
WGPUShaderModule mod = pfn_wgpuDeviceCreateShaderModule(device, &desc);
|
|
815
|
-
free(code);
|
|
816
|
-
if (!mod) NAPI_THROW(env, "createShaderModule failed (WGSL translation or compilation error — check stderr for details)");
|
|
817
|
-
return wrap_ptr(env, mod);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
static napi_value doe_shader_module_release(napi_env env, napi_callback_info info) {
|
|
821
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
822
|
-
void* mod = unwrap_ptr(env, _args[0]);
|
|
823
|
-
if (mod) pfn_wgpuShaderModuleRelease(mod);
|
|
824
|
-
return NULL;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
/* ================================================================
|
|
828
|
-
* Compute Pipeline
|
|
829
|
-
* createComputePipeline(device, shaderModule, entryPoint, pipelineLayout?)
|
|
830
|
-
* ================================================================ */
|
|
831
|
-
|
|
832
|
-
static napi_value doe_create_compute_pipeline(napi_env env, napi_callback_info info) {
|
|
833
|
-
NAPI_ASSERT_ARGC(env, info, 4);
|
|
834
|
-
CHECK_LIB_LOADED(env);
|
|
835
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
836
|
-
WGPUShaderModule shader = unwrap_ptr(env, _args[1]);
|
|
837
|
-
if (!device || !shader) NAPI_THROW(env, "Invalid device or shader");
|
|
838
|
-
|
|
839
|
-
size_t ep_len = 0;
|
|
840
|
-
napi_get_value_string_utf8(env, _args[2], NULL, 0, &ep_len);
|
|
841
|
-
char* ep = (char*)malloc(ep_len + 1);
|
|
842
|
-
napi_get_value_string_utf8(env, _args[2], ep, ep_len + 1, &ep_len);
|
|
843
|
-
|
|
844
|
-
/* pipelineLayout can be null (auto layout) */
|
|
845
|
-
napi_valuetype layout_type;
|
|
846
|
-
napi_typeof(env, _args[3], &layout_type);
|
|
847
|
-
void* layout = NULL;
|
|
848
|
-
if (layout_type == napi_external) layout = unwrap_ptr(env, _args[3]);
|
|
849
|
-
|
|
850
|
-
WGPUComputePipelineDescriptor desc;
|
|
851
|
-
memset(&desc, 0, sizeof(desc));
|
|
852
|
-
desc.layout = layout;
|
|
853
|
-
desc.compute.module = shader;
|
|
854
|
-
desc.compute.entryPoint.data = ep;
|
|
855
|
-
desc.compute.entryPoint.length = ep_len;
|
|
856
|
-
|
|
857
|
-
WGPUComputePipeline pipeline = pfn_wgpuDeviceCreateComputePipeline(device, &desc);
|
|
858
|
-
free(ep);
|
|
859
|
-
if (!pipeline) NAPI_THROW(env, "createComputePipeline failed (shader module invalid or entry point not found — check stderr for details)");
|
|
860
|
-
return wrap_ptr(env, pipeline);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
static napi_value doe_compute_pipeline_release(napi_env env, napi_callback_info info) {
|
|
864
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
865
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
866
|
-
if (p) pfn_wgpuComputePipelineRelease(p);
|
|
867
|
-
return NULL;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
/* computePipelineGetBindGroupLayout(pipeline, groupIndex) → bindGroupLayout */
|
|
871
|
-
static napi_value doe_compute_pipeline_get_bind_group_layout(napi_env env, napi_callback_info info) {
|
|
872
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
873
|
-
CHECK_LIB_LOADED(env);
|
|
874
|
-
WGPUComputePipeline pipeline = unwrap_ptr(env, _args[0]);
|
|
875
|
-
if (!pipeline) NAPI_THROW(env, "Invalid pipeline");
|
|
876
|
-
uint32_t index;
|
|
877
|
-
napi_get_value_uint32(env, _args[1], &index);
|
|
878
|
-
WGPUBindGroupLayout layout = pfn_wgpuComputePipelineGetBindGroupLayout(pipeline, index);
|
|
879
|
-
if (!layout) NAPI_THROW(env, "getBindGroupLayout failed");
|
|
880
|
-
return wrap_ptr(env, layout);
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/* ================================================================
|
|
884
|
-
* Bind Group Layout
|
|
885
|
-
* createBindGroupLayout(device, entries[])
|
|
886
|
-
* Each entry: { binding, visibility, buffer?: { type }, storageTexture?: { ... } }
|
|
887
|
-
* ================================================================ */
|
|
888
|
-
|
|
889
|
-
static uint32_t buffer_binding_type_from_string(napi_env env, napi_value val) {
|
|
890
|
-
napi_valuetype vt;
|
|
891
|
-
napi_typeof(env, val, &vt);
|
|
892
|
-
if (vt != napi_string) return 0x00000001; /* Undefined */
|
|
893
|
-
char buf[32] = {0};
|
|
894
|
-
size_t len = 0;
|
|
895
|
-
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
896
|
-
if (strcmp(buf, "uniform") == 0) return 0x00000002;
|
|
897
|
-
if (strcmp(buf, "storage") == 0) return 0x00000003;
|
|
898
|
-
if (strcmp(buf, "read-only-storage") == 0) return 0x00000004;
|
|
899
|
-
return 0x00000001;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
static napi_value doe_create_bind_group_layout(napi_env env, napi_callback_info info) {
|
|
903
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
904
|
-
CHECK_LIB_LOADED(env);
|
|
905
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
906
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
907
|
-
|
|
908
|
-
uint32_t entry_count = 0;
|
|
909
|
-
napi_get_array_length(env, _args[1], &entry_count);
|
|
910
|
-
|
|
911
|
-
WGPUBindGroupLayoutEntry* entries = (WGPUBindGroupLayoutEntry*)calloc(
|
|
912
|
-
entry_count, sizeof(WGPUBindGroupLayoutEntry));
|
|
913
|
-
|
|
914
|
-
for (uint32_t i = 0; i < entry_count; i++) {
|
|
915
|
-
napi_value elem;
|
|
916
|
-
napi_get_element(env, _args[1], i, &elem);
|
|
917
|
-
|
|
918
|
-
entries[i].binding = get_uint32_prop(env, elem, "binding");
|
|
919
|
-
entries[i].visibility = (uint64_t)get_int64_prop(env, elem, "visibility");
|
|
920
|
-
|
|
921
|
-
if (has_prop(env, elem, "buffer") && prop_type(env, elem, "buffer") == napi_object) {
|
|
922
|
-
napi_value buf_obj = get_prop(env, elem, "buffer");
|
|
923
|
-
entries[i].buffer.type = buffer_binding_type_from_string(
|
|
924
|
-
env, get_prop(env, buf_obj, "type"));
|
|
925
|
-
if (has_prop(env, buf_obj, "hasDynamicOffset"))
|
|
926
|
-
entries[i].buffer.hasDynamicOffset = get_bool_prop(env, buf_obj, "hasDynamicOffset") ? 1 : 0;
|
|
927
|
-
if (has_prop(env, buf_obj, "minBindingSize"))
|
|
928
|
-
entries[i].buffer.minBindingSize = (uint64_t)get_int64_prop(env, buf_obj, "minBindingSize");
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
if (has_prop(env, elem, "storageTexture") && prop_type(env, elem, "storageTexture") == napi_object) {
|
|
932
|
-
napi_value st_obj = get_prop(env, elem, "storageTexture");
|
|
933
|
-
entries[i].storageTexture.access = get_uint32_prop(env, st_obj, "access");
|
|
934
|
-
entries[i].storageTexture.format = get_uint32_prop(env, st_obj, "format");
|
|
935
|
-
entries[i].storageTexture.viewDimension = get_uint32_prop(env, st_obj, "viewDimension");
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
WGPUBindGroupLayoutDescriptor desc = {
|
|
940
|
-
.nextInChain = NULL,
|
|
941
|
-
.label = { .data = NULL, .length = 0 },
|
|
942
|
-
.entryCount = entry_count,
|
|
943
|
-
.entries = entries,
|
|
944
|
-
};
|
|
945
|
-
|
|
946
|
-
WGPUBindGroupLayout layout = pfn_wgpuDeviceCreateBindGroupLayout(device, &desc);
|
|
947
|
-
free(entries);
|
|
948
|
-
if (!layout) NAPI_THROW(env, "createBindGroupLayout failed");
|
|
949
|
-
return wrap_ptr(env, layout);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
static napi_value doe_bind_group_layout_release(napi_env env, napi_callback_info info) {
|
|
953
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
954
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
955
|
-
if (p) pfn_wgpuBindGroupLayoutRelease(p);
|
|
956
|
-
return NULL;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
/* ================================================================
|
|
960
|
-
* Bind Group
|
|
961
|
-
* createBindGroup(device, layout, entries[])
|
|
962
|
-
* Each entry: { binding, buffer, offset?, size? }
|
|
963
|
-
* ================================================================ */
|
|
964
|
-
|
|
965
|
-
static napi_value doe_create_bind_group(napi_env env, napi_callback_info info) {
|
|
966
|
-
NAPI_ASSERT_ARGC(env, info, 3);
|
|
967
|
-
CHECK_LIB_LOADED(env);
|
|
968
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
969
|
-
WGPUBindGroupLayout layout = unwrap_ptr(env, _args[1]);
|
|
970
|
-
if (!device || !layout) NAPI_THROW(env, "Invalid device or layout");
|
|
971
|
-
|
|
972
|
-
uint32_t entry_count = 0;
|
|
973
|
-
napi_get_array_length(env, _args[2], &entry_count);
|
|
974
|
-
|
|
975
|
-
WGPUBindGroupEntry* entries = (WGPUBindGroupEntry*)calloc(
|
|
976
|
-
entry_count, sizeof(WGPUBindGroupEntry));
|
|
977
|
-
|
|
978
|
-
for (uint32_t i = 0; i < entry_count; i++) {
|
|
979
|
-
napi_value elem;
|
|
980
|
-
napi_get_element(env, _args[2], i, &elem);
|
|
981
|
-
|
|
982
|
-
entries[i].binding = get_uint32_prop(env, elem, "binding");
|
|
983
|
-
|
|
984
|
-
if (has_prop(env, elem, "buffer") && prop_type(env, elem, "buffer") == napi_external)
|
|
985
|
-
entries[i].buffer = unwrap_ptr(env, get_prop(env, elem, "buffer"));
|
|
986
|
-
|
|
987
|
-
if (has_prop(env, elem, "offset"))
|
|
988
|
-
entries[i].offset = (uint64_t)get_int64_prop(env, elem, "offset");
|
|
989
|
-
|
|
990
|
-
entries[i].size = WGPU_WHOLE_SIZE;
|
|
991
|
-
if (has_prop(env, elem, "size"))
|
|
992
|
-
entries[i].size = (uint64_t)get_int64_prop(env, elem, "size");
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
WGPUBindGroupDescriptor desc = {
|
|
996
|
-
.nextInChain = NULL,
|
|
997
|
-
.label = { .data = NULL, .length = 0 },
|
|
998
|
-
.layout = layout,
|
|
999
|
-
.entryCount = entry_count,
|
|
1000
|
-
.entries = entries,
|
|
1001
|
-
};
|
|
1002
|
-
|
|
1003
|
-
WGPUBindGroup group = pfn_wgpuDeviceCreateBindGroup(device, &desc);
|
|
1004
|
-
free(entries);
|
|
1005
|
-
if (!group) NAPI_THROW(env, "createBindGroup failed");
|
|
1006
|
-
return wrap_ptr(env, group);
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
static napi_value doe_bind_group_release(napi_env env, napi_callback_info info) {
|
|
1010
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1011
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1012
|
-
if (p) pfn_wgpuBindGroupRelease(p);
|
|
1013
|
-
return NULL;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
/* ================================================================
|
|
1017
|
-
* Pipeline Layout
|
|
1018
|
-
* createPipelineLayout(device, bindGroupLayouts[])
|
|
1019
|
-
* ================================================================ */
|
|
1020
|
-
|
|
1021
|
-
static napi_value doe_create_pipeline_layout(napi_env env, napi_callback_info info) {
|
|
1022
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1023
|
-
CHECK_LIB_LOADED(env);
|
|
1024
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1025
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1026
|
-
|
|
1027
|
-
uint32_t layout_count = 0;
|
|
1028
|
-
napi_get_array_length(env, _args[1], &layout_count);
|
|
1029
|
-
|
|
1030
|
-
WGPUBindGroupLayout* layouts = (WGPUBindGroupLayout*)calloc(
|
|
1031
|
-
layout_count, sizeof(WGPUBindGroupLayout));
|
|
1032
|
-
for (uint32_t i = 0; i < layout_count; i++) {
|
|
1033
|
-
napi_value elem;
|
|
1034
|
-
napi_get_element(env, _args[1], i, &elem);
|
|
1035
|
-
layouts[i] = unwrap_ptr(env, elem);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
WGPUPipelineLayoutDescriptor desc = {
|
|
1039
|
-
.nextInChain = NULL,
|
|
1040
|
-
.label = { .data = NULL, .length = 0 },
|
|
1041
|
-
.bindGroupLayoutCount = layout_count,
|
|
1042
|
-
.bindGroupLayouts = layouts,
|
|
1043
|
-
.immediateSize = 0,
|
|
1044
|
-
};
|
|
1045
|
-
|
|
1046
|
-
WGPUPipelineLayout pl = pfn_wgpuDeviceCreatePipelineLayout(device, &desc);
|
|
1047
|
-
free(layouts);
|
|
1048
|
-
if (!pl) NAPI_THROW(env, "createPipelineLayout failed");
|
|
1049
|
-
return wrap_ptr(env, pl);
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
static napi_value doe_pipeline_layout_release(napi_env env, napi_callback_info info) {
|
|
1053
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1054
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1055
|
-
if (p) pfn_wgpuPipelineLayoutRelease(p);
|
|
1056
|
-
return NULL;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
/* ================================================================
|
|
1060
|
-
* Command Encoder
|
|
1061
|
-
* ================================================================ */
|
|
1062
|
-
|
|
1063
|
-
static napi_value doe_create_command_encoder(napi_env env, napi_callback_info info) {
|
|
1064
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1065
|
-
CHECK_LIB_LOADED(env);
|
|
1066
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1067
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1068
|
-
|
|
1069
|
-
WGPUCommandEncoderDescriptor desc = {
|
|
1070
|
-
.nextInChain = NULL,
|
|
1071
|
-
.label = { .data = NULL, .length = 0 },
|
|
1072
|
-
};
|
|
1073
|
-
WGPUCommandEncoder enc = pfn_wgpuDeviceCreateCommandEncoder(device, &desc);
|
|
1074
|
-
if (!enc) NAPI_THROW(env, "createCommandEncoder failed");
|
|
1075
|
-
return wrap_ptr(env, enc);
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
static napi_value doe_command_encoder_release(napi_env env, napi_callback_info info) {
|
|
1079
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1080
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1081
|
-
if (p) pfn_wgpuCommandEncoderRelease(p);
|
|
1082
|
-
return NULL;
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
static napi_value doe_command_encoder_copy_buffer_to_buffer(napi_env env, napi_callback_info info) {
|
|
1086
|
-
NAPI_ASSERT_ARGC(env, info, 6);
|
|
1087
|
-
CHECK_LIB_LOADED(env);
|
|
1088
|
-
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1089
|
-
WGPUBuffer src = unwrap_ptr(env, _args[1]);
|
|
1090
|
-
int64_t src_offset; napi_get_value_int64(env, _args[2], &src_offset);
|
|
1091
|
-
WGPUBuffer dst = unwrap_ptr(env, _args[3]);
|
|
1092
|
-
int64_t dst_offset; napi_get_value_int64(env, _args[4], &dst_offset);
|
|
1093
|
-
int64_t size; napi_get_value_int64(env, _args[5], &size);
|
|
1094
|
-
|
|
1095
|
-
pfn_wgpuCommandEncoderCopyBufferToBuffer(enc, src, (uint64_t)src_offset,
|
|
1096
|
-
dst, (uint64_t)dst_offset, (uint64_t)size);
|
|
1097
|
-
return NULL;
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
static napi_value doe_command_encoder_finish(napi_env env, napi_callback_info info) {
|
|
1101
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1102
|
-
CHECK_LIB_LOADED(env);
|
|
1103
|
-
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1104
|
-
if (!enc) NAPI_THROW(env, "Invalid encoder");
|
|
1105
|
-
|
|
1106
|
-
WGPUCommandBufferDescriptor desc = {
|
|
1107
|
-
.nextInChain = NULL,
|
|
1108
|
-
.label = { .data = NULL, .length = 0 },
|
|
1109
|
-
};
|
|
1110
|
-
WGPUCommandBuffer cmd = pfn_wgpuCommandEncoderFinish(enc, &desc);
|
|
1111
|
-
if (!cmd) NAPI_THROW(env, "commandEncoderFinish failed");
|
|
1112
|
-
return wrap_ptr(env, cmd);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
static napi_value doe_command_buffer_release(napi_env env, napi_callback_info info) {
|
|
1116
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1117
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1118
|
-
if (p) pfn_wgpuCommandBufferRelease(p);
|
|
1119
|
-
return NULL;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
/* ================================================================
|
|
1123
|
-
* Compute Pass
|
|
1124
|
-
* ================================================================ */
|
|
1125
|
-
|
|
1126
|
-
static napi_value doe_begin_compute_pass(napi_env env, napi_callback_info info) {
|
|
1127
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1128
|
-
CHECK_LIB_LOADED(env);
|
|
1129
|
-
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1130
|
-
if (!enc) NAPI_THROW(env, "Invalid encoder");
|
|
1131
|
-
|
|
1132
|
-
WGPUComputePassDescriptor desc = {
|
|
1133
|
-
.nextInChain = NULL,
|
|
1134
|
-
.label = { .data = NULL, .length = 0 },
|
|
1135
|
-
.timestampWrites = NULL,
|
|
1136
|
-
};
|
|
1137
|
-
WGPUComputePassEncoder pass = pfn_wgpuCommandEncoderBeginComputePass(enc, &desc);
|
|
1138
|
-
if (!pass) NAPI_THROW(env, "beginComputePass failed");
|
|
1139
|
-
return wrap_ptr(env, pass);
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
static napi_value doe_compute_pass_set_pipeline(napi_env env, napi_callback_info info) {
|
|
1143
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1144
|
-
pfn_wgpuComputePassEncoderSetPipeline(
|
|
1145
|
-
unwrap_ptr(env, _args[0]), unwrap_ptr(env, _args[1]));
|
|
1146
|
-
return NULL;
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
static napi_value doe_compute_pass_set_bind_group(napi_env env, napi_callback_info info) {
|
|
1150
|
-
NAPI_ASSERT_ARGC(env, info, 3);
|
|
1151
|
-
WGPUComputePassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
1152
|
-
uint32_t index; napi_get_value_uint32(env, _args[1], &index);
|
|
1153
|
-
WGPUBindGroup group = unwrap_ptr(env, _args[2]);
|
|
1154
|
-
pfn_wgpuComputePassEncoderSetBindGroup(pass, index, group, 0, NULL);
|
|
1155
|
-
return NULL;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
static napi_value doe_compute_pass_dispatch(napi_env env, napi_callback_info info) {
|
|
1159
|
-
NAPI_ASSERT_ARGC(env, info, 4);
|
|
1160
|
-
WGPUComputePassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
1161
|
-
uint32_t x, y, z;
|
|
1162
|
-
napi_get_value_uint32(env, _args[1], &x);
|
|
1163
|
-
napi_get_value_uint32(env, _args[2], &y);
|
|
1164
|
-
napi_get_value_uint32(env, _args[3], &z);
|
|
1165
|
-
pfn_wgpuComputePassEncoderDispatchWorkgroups(pass, x, y, z);
|
|
1166
|
-
return NULL;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
/* computePassDispatchWorkgroupsIndirect(pass, buffer, offset) */
|
|
1170
|
-
static napi_value doe_compute_pass_dispatch_indirect(napi_env env, napi_callback_info info) {
|
|
1171
|
-
NAPI_ASSERT_ARGC(env, info, 3);
|
|
1172
|
-
WGPUComputePassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
1173
|
-
WGPUBuffer buffer = unwrap_ptr(env, _args[1]);
|
|
1174
|
-
int64_t offset;
|
|
1175
|
-
napi_get_value_int64(env, _args[2], &offset);
|
|
1176
|
-
pfn_wgpuComputePassEncoderDispatchWorkgroupsIndirect(pass, buffer, (uint64_t)offset);
|
|
1177
|
-
return NULL;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
static napi_value doe_compute_pass_end(napi_env env, napi_callback_info info) {
|
|
1181
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1182
|
-
pfn_wgpuComputePassEncoderEnd(unwrap_ptr(env, _args[0]));
|
|
1183
|
-
return NULL;
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
static napi_value doe_compute_pass_release(napi_env env, napi_callback_info info) {
|
|
1187
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1188
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1189
|
-
if (p) pfn_wgpuComputePassEncoderRelease(p);
|
|
1190
|
-
return NULL;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/* ================================================================
|
|
1194
|
-
* Queue
|
|
1195
|
-
* ================================================================ */
|
|
1196
|
-
|
|
1197
|
-
static napi_value doe_queue_submit(napi_env env, napi_callback_info info) {
|
|
1198
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1199
|
-
CHECK_LIB_LOADED(env);
|
|
1200
|
-
WGPUQueue queue = unwrap_ptr(env, _args[0]);
|
|
1201
|
-
if (!queue) NAPI_THROW(env, "Invalid queue");
|
|
1202
|
-
|
|
1203
|
-
uint32_t cmd_count = 0;
|
|
1204
|
-
napi_get_array_length(env, _args[1], &cmd_count);
|
|
1205
|
-
|
|
1206
|
-
WGPUCommandBuffer* cmds = (WGPUCommandBuffer*)calloc(
|
|
1207
|
-
cmd_count, sizeof(WGPUCommandBuffer));
|
|
1208
|
-
for (uint32_t i = 0; i < cmd_count; i++) {
|
|
1209
|
-
napi_value elem;
|
|
1210
|
-
napi_get_element(env, _args[1], i, &elem);
|
|
1211
|
-
cmds[i] = unwrap_ptr(env, elem);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
pfn_wgpuQueueSubmit(queue, cmd_count, cmds);
|
|
1215
|
-
free(cmds);
|
|
1216
|
-
return NULL;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
/* queueWriteBuffer(queue, buffer, offset, typedArray) */
|
|
1220
|
-
static napi_value doe_queue_write_buffer(napi_env env, napi_callback_info info) {
|
|
1221
|
-
NAPI_ASSERT_ARGC(env, info, 4);
|
|
1222
|
-
CHECK_LIB_LOADED(env);
|
|
1223
|
-
WGPUQueue queue = unwrap_ptr(env, _args[0]);
|
|
1224
|
-
WGPUBuffer buf = unwrap_ptr(env, _args[1]);
|
|
1225
|
-
int64_t offset; napi_get_value_int64(env, _args[2], &offset);
|
|
1226
|
-
|
|
1227
|
-
void* data = NULL;
|
|
1228
|
-
size_t byte_length = 0;
|
|
1229
|
-
bool is_typedarray = false;
|
|
1230
|
-
napi_is_typedarray(env, _args[3], &is_typedarray);
|
|
1231
|
-
if (is_typedarray) {
|
|
1232
|
-
napi_typedarray_type ta_type;
|
|
1233
|
-
size_t ta_length;
|
|
1234
|
-
napi_value ab;
|
|
1235
|
-
size_t byte_offset;
|
|
1236
|
-
napi_get_typedarray_info(env, _args[3], &ta_type, &ta_length, &data, &ab, &byte_offset);
|
|
1237
|
-
/* Use typed array element count * element size for correct byte length. */
|
|
1238
|
-
size_t elem_size = 1;
|
|
1239
|
-
switch (ta_type) {
|
|
1240
|
-
case napi_int8_array: case napi_uint8_array: case napi_uint8_clamped_array: elem_size = 1; break;
|
|
1241
|
-
case napi_int16_array: case napi_uint16_array: elem_size = 2; break;
|
|
1242
|
-
case napi_int32_array: case napi_uint32_array: case napi_float32_array: elem_size = 4; break;
|
|
1243
|
-
case napi_float64_array: case napi_bigint64_array: case napi_biguint64_array: elem_size = 8; break;
|
|
1244
|
-
default: elem_size = 1; break;
|
|
1245
|
-
}
|
|
1246
|
-
byte_length = ta_length * elem_size;
|
|
1247
|
-
} else {
|
|
1248
|
-
bool is_ab = false;
|
|
1249
|
-
napi_is_arraybuffer(env, _args[3], &is_ab);
|
|
1250
|
-
if (is_ab) {
|
|
1251
|
-
napi_get_arraybuffer_info(env, _args[3], &data, &byte_length);
|
|
1252
|
-
} else {
|
|
1253
|
-
bool is_buffer = false;
|
|
1254
|
-
napi_is_buffer(env, _args[3], &is_buffer);
|
|
1255
|
-
if (is_buffer) {
|
|
1256
|
-
napi_get_buffer_info(env, _args[3], &data, &byte_length);
|
|
1257
|
-
} else {
|
|
1258
|
-
NAPI_THROW(env, "queueWriteBuffer: data must be TypedArray, ArrayBuffer, or Buffer");
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
pfn_wgpuQueueWriteBuffer(queue, buf, (uint64_t)offset, data, byte_length);
|
|
1264
|
-
return NULL;
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
/* queueFlush(queue) — wait for all pending GPU work to complete. */
|
|
1268
|
-
static napi_value doe_queue_flush(napi_env env, napi_callback_info info) {
|
|
1269
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1270
|
-
CHECK_LIB_LOADED(env);
|
|
1271
|
-
WGPUQueue queue = unwrap_ptr(env, _args[0]);
|
|
1272
|
-
if (queue && pfn_doeNativeQueueFlush) pfn_doeNativeQueueFlush(queue);
|
|
1273
|
-
return NULL;
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
static napi_value doe_queue_release(napi_env env, napi_callback_info info) {
|
|
1277
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1278
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1279
|
-
if (p) pfn_wgpuQueueRelease(p);
|
|
1280
|
-
return NULL;
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
/* ================================================================
|
|
1284
|
-
* Texture
|
|
1285
|
-
* createTexture(device, { format, width, height, usage, mipLevelCount?, dimension? })
|
|
1286
|
-
* ================================================================ */
|
|
1287
|
-
|
|
1288
|
-
/* WebGPU texture format string → numeric value mapping. */
|
|
1289
|
-
static uint32_t texture_format_from_string(napi_env env, napi_value val) {
|
|
1290
|
-
napi_valuetype vt;
|
|
1291
|
-
napi_typeof(env, val, &vt);
|
|
1292
|
-
if (vt == napi_number) {
|
|
1293
|
-
uint32_t out = 0;
|
|
1294
|
-
napi_get_value_uint32(env, val, &out);
|
|
1295
|
-
return out;
|
|
1296
|
-
}
|
|
1297
|
-
if (vt != napi_string) return 0x00000016; /* rgba8unorm */
|
|
1298
|
-
char buf[32] = {0};
|
|
1299
|
-
size_t len = 0;
|
|
1300
|
-
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1301
|
-
if (strcmp(buf, "rgba8unorm") == 0) return 0x00000016;
|
|
1302
|
-
if (strcmp(buf, "rgba8unorm-srgb") == 0) return 0x00000017;
|
|
1303
|
-
if (strcmp(buf, "bgra8unorm") == 0) return 0x0000001B;
|
|
1304
|
-
if (strcmp(buf, "bgra8unorm-srgb") == 0) return 0x0000001C;
|
|
1305
|
-
if (strcmp(buf, "depth32float") == 0) return 0x00000030;
|
|
1306
|
-
return 0x00000016;
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
static napi_value doe_create_texture(napi_env env, napi_callback_info info) {
|
|
1310
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1311
|
-
CHECK_LIB_LOADED(env);
|
|
1312
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1313
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1314
|
-
|
|
1315
|
-
WGPUTextureDescriptor desc;
|
|
1316
|
-
memset(&desc, 0, sizeof(desc));
|
|
1317
|
-
desc.format = texture_format_from_string(env, get_prop(env, _args[1], "format"));
|
|
1318
|
-
desc.size.width = get_uint32_prop(env, _args[1], "width");
|
|
1319
|
-
desc.size.height = get_uint32_prop(env, _args[1], "height");
|
|
1320
|
-
desc.size.depthOrArrayLayers = 1;
|
|
1321
|
-
if (has_prop(env, _args[1], "depthOrArrayLayers"))
|
|
1322
|
-
desc.size.depthOrArrayLayers = get_uint32_prop(env, _args[1], "depthOrArrayLayers");
|
|
1323
|
-
desc.usage = (uint64_t)get_int64_prop(env, _args[1], "usage");
|
|
1324
|
-
desc.mipLevelCount = 1;
|
|
1325
|
-
if (has_prop(env, _args[1], "mipLevelCount"))
|
|
1326
|
-
desc.mipLevelCount = get_uint32_prop(env, _args[1], "mipLevelCount");
|
|
1327
|
-
desc.sampleCount = 1;
|
|
1328
|
-
desc.dimension = 1; /* 2D */
|
|
1329
|
-
|
|
1330
|
-
WGPUTexture tex = pfn_wgpuDeviceCreateTexture(device, &desc);
|
|
1331
|
-
if (!tex) NAPI_THROW(env, "createTexture failed");
|
|
1332
|
-
return wrap_ptr(env, tex);
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
static napi_value doe_texture_release(napi_env env, napi_callback_info info) {
|
|
1336
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1337
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1338
|
-
if (p) pfn_wgpuTextureRelease(p);
|
|
1339
|
-
return NULL;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
/* textureCreateView(texture) */
|
|
1343
|
-
static napi_value doe_texture_create_view(napi_env env, napi_callback_info info) {
|
|
1344
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1345
|
-
CHECK_LIB_LOADED(env);
|
|
1346
|
-
WGPUTexture tex = unwrap_ptr(env, _args[0]);
|
|
1347
|
-
if (!tex) NAPI_THROW(env, "Invalid texture");
|
|
1348
|
-
WGPUTextureView view = pfn_wgpuTextureCreateView(tex, NULL);
|
|
1349
|
-
if (!view) NAPI_THROW(env, "textureCreateView failed");
|
|
1350
|
-
return wrap_ptr(env, view);
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
static napi_value doe_texture_view_release(napi_env env, napi_callback_info info) {
|
|
1354
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1355
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1356
|
-
if (p) pfn_wgpuTextureViewRelease(p);
|
|
1357
|
-
return NULL;
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
/* ================================================================
|
|
1361
|
-
* Sampler
|
|
1362
|
-
* createSampler(device, { magFilter?, minFilter?, mipmapFilter?,
|
|
1363
|
-
* addressModeU?, addressModeV?, addressModeW?, lodMinClamp?, lodMaxClamp?, maxAnisotropy? })
|
|
1364
|
-
* ================================================================ */
|
|
1365
|
-
|
|
1366
|
-
static uint32_t filter_mode_from_string(napi_env env, napi_value val) {
|
|
1367
|
-
napi_valuetype vt;
|
|
1368
|
-
napi_typeof(env, val, &vt);
|
|
1369
|
-
if (vt != napi_string) return 0; /* nearest */
|
|
1370
|
-
char buf[16] = {0};
|
|
1371
|
-
size_t len = 0;
|
|
1372
|
-
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1373
|
-
if (strcmp(buf, "linear") == 0) return 1;
|
|
1374
|
-
return 0; /* nearest */
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
static uint32_t address_mode_from_string(napi_env env, napi_value val) {
|
|
1378
|
-
napi_valuetype vt;
|
|
1379
|
-
napi_typeof(env, val, &vt);
|
|
1380
|
-
if (vt != napi_string) return 1; /* clamp-to-edge */
|
|
1381
|
-
char buf[24] = {0};
|
|
1382
|
-
size_t len = 0;
|
|
1383
|
-
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1384
|
-
if (strcmp(buf, "repeat") == 0) return 2;
|
|
1385
|
-
if (strcmp(buf, "mirror-repeat") == 0) return 3;
|
|
1386
|
-
return 1; /* clamp-to-edge */
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
static napi_value doe_create_sampler(napi_env env, napi_callback_info info) {
|
|
1390
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1391
|
-
CHECK_LIB_LOADED(env);
|
|
1392
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1393
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1394
|
-
|
|
1395
|
-
WGPUSamplerDescriptor desc;
|
|
1396
|
-
memset(&desc, 0, sizeof(desc));
|
|
1397
|
-
desc.lodMaxClamp = 32.0f;
|
|
1398
|
-
desc.maxAnisotropy = 1;
|
|
1399
|
-
|
|
1400
|
-
napi_valuetype desc_type;
|
|
1401
|
-
napi_typeof(env, _args[1], &desc_type);
|
|
1402
|
-
if (desc_type == napi_object) {
|
|
1403
|
-
if (has_prop(env, _args[1], "magFilter"))
|
|
1404
|
-
desc.magFilter = filter_mode_from_string(env, get_prop(env, _args[1], "magFilter"));
|
|
1405
|
-
if (has_prop(env, _args[1], "minFilter"))
|
|
1406
|
-
desc.minFilter = filter_mode_from_string(env, get_prop(env, _args[1], "minFilter"));
|
|
1407
|
-
if (has_prop(env, _args[1], "mipmapFilter"))
|
|
1408
|
-
desc.mipmapFilter = filter_mode_from_string(env, get_prop(env, _args[1], "mipmapFilter"));
|
|
1409
|
-
if (has_prop(env, _args[1], "addressModeU"))
|
|
1410
|
-
desc.addressModeU = address_mode_from_string(env, get_prop(env, _args[1], "addressModeU"));
|
|
1411
|
-
if (has_prop(env, _args[1], "addressModeV"))
|
|
1412
|
-
desc.addressModeV = address_mode_from_string(env, get_prop(env, _args[1], "addressModeV"));
|
|
1413
|
-
if (has_prop(env, _args[1], "addressModeW"))
|
|
1414
|
-
desc.addressModeW = address_mode_from_string(env, get_prop(env, _args[1], "addressModeW"));
|
|
1415
|
-
if (has_prop(env, _args[1], "maxAnisotropy"))
|
|
1416
|
-
desc.maxAnisotropy = (uint16_t)get_uint32_prop(env, _args[1], "maxAnisotropy");
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
WGPUSampler sampler = pfn_wgpuDeviceCreateSampler(device, &desc);
|
|
1420
|
-
if (!sampler) NAPI_THROW(env, "createSampler failed");
|
|
1421
|
-
return wrap_ptr(env, sampler);
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
static napi_value doe_sampler_release(napi_env env, napi_callback_info info) {
|
|
1425
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1426
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1427
|
-
if (p) pfn_wgpuSamplerRelease(p);
|
|
1428
|
-
return NULL;
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
/* ================================================================
|
|
1432
|
-
* Render Pipeline (noop stub — uses built-in Metal shaders)
|
|
1433
|
-
* createRenderPipeline(device)
|
|
1434
|
-
* ================================================================ */
|
|
1435
|
-
|
|
1436
|
-
static napi_value doe_create_render_pipeline(napi_env env, napi_callback_info info) {
|
|
1437
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1438
|
-
CHECK_LIB_LOADED(env);
|
|
1439
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1440
|
-
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1441
|
-
WGPURenderPipeline rp = pfn_wgpuDeviceCreateRenderPipeline(device, NULL);
|
|
1442
|
-
if (!rp) NAPI_THROW(env, "createRenderPipeline failed");
|
|
1443
|
-
return wrap_ptr(env, rp);
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
static napi_value doe_render_pipeline_release(napi_env env, napi_callback_info info) {
|
|
1447
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1448
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1449
|
-
if (p) pfn_wgpuRenderPipelineRelease(p);
|
|
1450
|
-
return NULL;
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
/* ================================================================
|
|
1454
|
-
* Render Pass
|
|
1455
|
-
* beginRenderPass(encoder, colorAttachments[])
|
|
1456
|
-
* ================================================================ */
|
|
1457
|
-
|
|
1458
|
-
static napi_value doe_begin_render_pass(napi_env env, napi_callback_info info) {
|
|
1459
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1460
|
-
CHECK_LIB_LOADED(env);
|
|
1461
|
-
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1462
|
-
if (!enc) NAPI_THROW(env, "Invalid encoder");
|
|
1463
|
-
|
|
1464
|
-
/* _args[1] is array of color attachments */
|
|
1465
|
-
uint32_t att_count = 0;
|
|
1466
|
-
napi_get_array_length(env, _args[1], &att_count);
|
|
1467
|
-
if (att_count == 0) NAPI_THROW(env, "beginRenderPass: need at least one color attachment");
|
|
1468
|
-
|
|
1469
|
-
WGPURenderPassColorAttachment* atts = (WGPURenderPassColorAttachment*)calloc(
|
|
1470
|
-
att_count, sizeof(WGPURenderPassColorAttachment));
|
|
1471
|
-
for (uint32_t i = 0; i < att_count; i++) {
|
|
1472
|
-
napi_value elem;
|
|
1473
|
-
napi_get_element(env, _args[1], i, &elem);
|
|
1474
|
-
atts[i].view = unwrap_ptr(env, get_prop(env, elem, "view"));
|
|
1475
|
-
atts[i].loadOp = 1; /* clear */
|
|
1476
|
-
atts[i].storeOp = 1; /* store */
|
|
1477
|
-
if (has_prop(env, elem, "clearValue") && prop_type(env, elem, "clearValue") == napi_object) {
|
|
1478
|
-
napi_value cv = get_prop(env, elem, "clearValue");
|
|
1479
|
-
double r = 0, g = 0, b = 0, a = 1;
|
|
1480
|
-
napi_value tmp;
|
|
1481
|
-
if (napi_get_named_property(env, cv, "r", &tmp) == napi_ok)
|
|
1482
|
-
napi_get_value_double(env, tmp, &r);
|
|
1483
|
-
if (napi_get_named_property(env, cv, "g", &tmp) == napi_ok)
|
|
1484
|
-
napi_get_value_double(env, tmp, &g);
|
|
1485
|
-
if (napi_get_named_property(env, cv, "b", &tmp) == napi_ok)
|
|
1486
|
-
napi_get_value_double(env, tmp, &b);
|
|
1487
|
-
if (napi_get_named_property(env, cv, "a", &tmp) == napi_ok)
|
|
1488
|
-
napi_get_value_double(env, tmp, &a);
|
|
1489
|
-
atts[i].clearValue = (WGPUColor){ r, g, b, a };
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
WGPURenderPassDescriptor desc;
|
|
1494
|
-
memset(&desc, 0, sizeof(desc));
|
|
1495
|
-
desc.colorAttachmentCount = att_count;
|
|
1496
|
-
desc.colorAttachments = atts;
|
|
1497
|
-
|
|
1498
|
-
WGPURenderPassEncoder pass = pfn_wgpuCommandEncoderBeginRenderPass(enc, &desc);
|
|
1499
|
-
free(atts);
|
|
1500
|
-
if (!pass) NAPI_THROW(env, "beginRenderPass failed");
|
|
1501
|
-
return wrap_ptr(env, pass);
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
static napi_value doe_render_pass_set_pipeline(napi_env env, napi_callback_info info) {
|
|
1505
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1506
|
-
pfn_wgpuRenderPassEncoderSetPipeline(
|
|
1507
|
-
unwrap_ptr(env, _args[0]), unwrap_ptr(env, _args[1]));
|
|
1508
|
-
return NULL;
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
/* renderPassDraw(pass, vertexCount, instanceCount, firstVertex, firstInstance) */
|
|
1512
|
-
static napi_value doe_render_pass_draw(napi_env env, napi_callback_info info) {
|
|
1513
|
-
NAPI_ASSERT_ARGC(env, info, 5);
|
|
1514
|
-
WGPURenderPassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
1515
|
-
uint32_t vc, ic, fv, fi;
|
|
1516
|
-
napi_get_value_uint32(env, _args[1], &vc);
|
|
1517
|
-
napi_get_value_uint32(env, _args[2], &ic);
|
|
1518
|
-
napi_get_value_uint32(env, _args[3], &fv);
|
|
1519
|
-
napi_get_value_uint32(env, _args[4], &fi);
|
|
1520
|
-
pfn_wgpuRenderPassEncoderDraw(pass, vc, ic, fv, fi);
|
|
1521
|
-
return NULL;
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
static napi_value doe_render_pass_end(napi_env env, napi_callback_info info) {
|
|
1525
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1526
|
-
pfn_wgpuRenderPassEncoderEnd(unwrap_ptr(env, _args[0]));
|
|
1527
|
-
return NULL;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
static napi_value doe_render_pass_release(napi_env env, napi_callback_info info) {
|
|
1531
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1532
|
-
void* p = unwrap_ptr(env, _args[0]);
|
|
1533
|
-
if (p) pfn_wgpuRenderPassEncoderRelease(p);
|
|
1534
|
-
return NULL;
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
/* ================================================================
|
|
1538
|
-
* Device capabilities: limits, features
|
|
1539
|
-
* ================================================================ */
|
|
1540
|
-
|
|
1541
|
-
static napi_value doe_device_get_limits(napi_env env, napi_callback_info info) {
|
|
1542
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1543
|
-
CHECK_LIB_LOADED(env);
|
|
1544
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1545
|
-
if (!device) NAPI_THROW(env, "deviceGetLimits: null device");
|
|
1546
|
-
|
|
1547
|
-
WGPULimits limits;
|
|
1548
|
-
memset(&limits, 0, sizeof(limits));
|
|
1549
|
-
pfn_wgpuDeviceGetLimits(device, &limits);
|
|
1550
|
-
|
|
1551
|
-
napi_value obj;
|
|
1552
|
-
napi_create_object(env, &obj);
|
|
1553
|
-
|
|
1554
|
-
#define SET_U32(name) do { napi_value v; napi_create_uint32(env, limits.name, &v); napi_set_named_property(env, obj, #name, v); } while(0)
|
|
1555
|
-
#define SET_U64(name) do { napi_value v; napi_create_double(env, (double)limits.name, &v); napi_set_named_property(env, obj, #name, v); } while(0)
|
|
1556
|
-
|
|
1557
|
-
SET_U32(maxTextureDimension1D);
|
|
1558
|
-
SET_U32(maxTextureDimension2D);
|
|
1559
|
-
SET_U32(maxTextureDimension3D);
|
|
1560
|
-
SET_U32(maxTextureArrayLayers);
|
|
1561
|
-
SET_U32(maxBindGroups);
|
|
1562
|
-
SET_U32(maxBindGroupsPlusVertexBuffers);
|
|
1563
|
-
SET_U32(maxBindingsPerBindGroup);
|
|
1564
|
-
SET_U32(maxDynamicUniformBuffersPerPipelineLayout);
|
|
1565
|
-
SET_U32(maxDynamicStorageBuffersPerPipelineLayout);
|
|
1566
|
-
SET_U32(maxSampledTexturesPerShaderStage);
|
|
1567
|
-
SET_U32(maxSamplersPerShaderStage);
|
|
1568
|
-
SET_U32(maxStorageBuffersPerShaderStage);
|
|
1569
|
-
SET_U32(maxStorageTexturesPerShaderStage);
|
|
1570
|
-
SET_U32(maxUniformBuffersPerShaderStage);
|
|
1571
|
-
SET_U64(maxUniformBufferBindingSize);
|
|
1572
|
-
SET_U64(maxStorageBufferBindingSize);
|
|
1573
|
-
SET_U32(minUniformBufferOffsetAlignment);
|
|
1574
|
-
SET_U32(minStorageBufferOffsetAlignment);
|
|
1575
|
-
SET_U32(maxVertexBuffers);
|
|
1576
|
-
SET_U64(maxBufferSize);
|
|
1577
|
-
SET_U32(maxVertexAttributes);
|
|
1578
|
-
SET_U32(maxVertexBufferArrayStride);
|
|
1579
|
-
SET_U32(maxInterStageShaderVariables);
|
|
1580
|
-
SET_U32(maxColorAttachments);
|
|
1581
|
-
SET_U32(maxColorAttachmentBytesPerSample);
|
|
1582
|
-
SET_U32(maxComputeWorkgroupStorageSize);
|
|
1583
|
-
SET_U32(maxComputeInvocationsPerWorkgroup);
|
|
1584
|
-
SET_U32(maxComputeWorkgroupSizeX);
|
|
1585
|
-
SET_U32(maxComputeWorkgroupSizeY);
|
|
1586
|
-
SET_U32(maxComputeWorkgroupSizeZ);
|
|
1587
|
-
SET_U32(maxComputeWorkgroupsPerDimension);
|
|
1588
|
-
|
|
1589
|
-
#undef SET_U32
|
|
1590
|
-
#undef SET_U64
|
|
1591
|
-
|
|
1592
|
-
return obj;
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
static napi_value doe_device_has_feature(napi_env env, napi_callback_info info) {
|
|
1596
|
-
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1597
|
-
CHECK_LIB_LOADED(env);
|
|
1598
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1599
|
-
uint32_t feature;
|
|
1600
|
-
napi_get_value_uint32(env, _args[1], &feature);
|
|
1601
|
-
uint32_t result = pfn_wgpuDeviceHasFeature(device, feature);
|
|
1602
|
-
napi_value ret;
|
|
1603
|
-
napi_get_boolean(env, result != 0, &ret);
|
|
1604
|
-
return ret;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
/* ================================================================
|
|
1608
|
-
* Module initialization
|
|
1609
|
-
* ================================================================ */
|
|
1610
|
-
|
|
1611
|
-
#define EXPORT_FN(name, fn) { name, 0, fn, 0, 0, 0, napi_default, 0 }
|
|
1612
|
-
|
|
1613
|
-
static napi_value doe_module_init(napi_env env, napi_value exports) {
|
|
1614
|
-
napi_property_descriptor descriptors[] = {
|
|
1615
|
-
EXPORT_FN("loadLibrary", doe_load_library),
|
|
1616
|
-
EXPORT_FN("createInstance", doe_create_instance),
|
|
1617
|
-
EXPORT_FN("instanceRelease", doe_instance_release),
|
|
1618
|
-
EXPORT_FN("requestAdapter", doe_request_adapter),
|
|
1619
|
-
EXPORT_FN("adapterRelease", doe_adapter_release),
|
|
1620
|
-
EXPORT_FN("requestDevice", doe_request_device),
|
|
1621
|
-
EXPORT_FN("deviceRelease", doe_device_release),
|
|
1622
|
-
EXPORT_FN("deviceGetQueue", doe_device_get_queue),
|
|
1623
|
-
EXPORT_FN("createBuffer", doe_create_buffer),
|
|
1624
|
-
EXPORT_FN("bufferRelease", doe_buffer_release),
|
|
1625
|
-
EXPORT_FN("bufferUnmap", doe_buffer_unmap),
|
|
1626
|
-
EXPORT_FN("bufferMapSync", doe_buffer_map_sync),
|
|
1627
|
-
EXPORT_FN("bufferGetMappedRange", doe_buffer_get_mapped_range),
|
|
1628
|
-
EXPORT_FN("createShaderModule", doe_create_shader_module),
|
|
1629
|
-
EXPORT_FN("shaderModuleRelease", doe_shader_module_release),
|
|
1630
|
-
EXPORT_FN("createComputePipeline", doe_create_compute_pipeline),
|
|
1631
|
-
EXPORT_FN("computePipelineRelease", doe_compute_pipeline_release),
|
|
1632
|
-
EXPORT_FN("computePipelineGetBindGroupLayout", doe_compute_pipeline_get_bind_group_layout),
|
|
1633
|
-
EXPORT_FN("createBindGroupLayout", doe_create_bind_group_layout),
|
|
1634
|
-
EXPORT_FN("bindGroupLayoutRelease", doe_bind_group_layout_release),
|
|
1635
|
-
EXPORT_FN("createBindGroup", doe_create_bind_group),
|
|
1636
|
-
EXPORT_FN("bindGroupRelease", doe_bind_group_release),
|
|
1637
|
-
EXPORT_FN("createPipelineLayout", doe_create_pipeline_layout),
|
|
1638
|
-
EXPORT_FN("pipelineLayoutRelease", doe_pipeline_layout_release),
|
|
1639
|
-
EXPORT_FN("createCommandEncoder", doe_create_command_encoder),
|
|
1640
|
-
EXPORT_FN("commandEncoderRelease", doe_command_encoder_release),
|
|
1641
|
-
EXPORT_FN("commandEncoderCopyBufferToBuffer", doe_command_encoder_copy_buffer_to_buffer),
|
|
1642
|
-
EXPORT_FN("commandEncoderFinish", doe_command_encoder_finish),
|
|
1643
|
-
EXPORT_FN("commandBufferRelease", doe_command_buffer_release),
|
|
1644
|
-
EXPORT_FN("beginComputePass", doe_begin_compute_pass),
|
|
1645
|
-
EXPORT_FN("computePassSetPipeline", doe_compute_pass_set_pipeline),
|
|
1646
|
-
EXPORT_FN("computePassSetBindGroup", doe_compute_pass_set_bind_group),
|
|
1647
|
-
EXPORT_FN("computePassDispatchWorkgroups", doe_compute_pass_dispatch),
|
|
1648
|
-
EXPORT_FN("computePassDispatchWorkgroupsIndirect", doe_compute_pass_dispatch_indirect),
|
|
1649
|
-
EXPORT_FN("computePassEnd", doe_compute_pass_end),
|
|
1650
|
-
EXPORT_FN("computePassRelease", doe_compute_pass_release),
|
|
1651
|
-
EXPORT_FN("queueSubmit", doe_queue_submit),
|
|
1652
|
-
EXPORT_FN("queueWriteBuffer", doe_queue_write_buffer),
|
|
1653
|
-
EXPORT_FN("queueFlush", doe_queue_flush),
|
|
1654
|
-
EXPORT_FN("queueRelease", doe_queue_release),
|
|
1655
|
-
EXPORT_FN("createTexture", doe_create_texture),
|
|
1656
|
-
EXPORT_FN("textureRelease", doe_texture_release),
|
|
1657
|
-
EXPORT_FN("textureCreateView", doe_texture_create_view),
|
|
1658
|
-
EXPORT_FN("textureViewRelease", doe_texture_view_release),
|
|
1659
|
-
EXPORT_FN("createSampler", doe_create_sampler),
|
|
1660
|
-
EXPORT_FN("samplerRelease", doe_sampler_release),
|
|
1661
|
-
EXPORT_FN("createRenderPipeline", doe_create_render_pipeline),
|
|
1662
|
-
EXPORT_FN("renderPipelineRelease", doe_render_pipeline_release),
|
|
1663
|
-
EXPORT_FN("beginRenderPass", doe_begin_render_pass),
|
|
1664
|
-
EXPORT_FN("renderPassSetPipeline", doe_render_pass_set_pipeline),
|
|
1665
|
-
EXPORT_FN("renderPassDraw", doe_render_pass_draw),
|
|
1666
|
-
EXPORT_FN("renderPassEnd", doe_render_pass_end),
|
|
1667
|
-
EXPORT_FN("renderPassRelease", doe_render_pass_release),
|
|
1668
|
-
EXPORT_FN("deviceGetLimits", doe_device_get_limits),
|
|
1669
|
-
EXPORT_FN("deviceHasFeature", doe_device_has_feature),
|
|
1670
|
-
};
|
|
1671
|
-
|
|
1672
|
-
size_t count = sizeof(descriptors) / sizeof(descriptors[0]);
|
|
1673
|
-
napi_define_properties(env, exports, count, descriptors);
|
|
1674
|
-
return exports;
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
NAPI_MODULE(NODE_GYP_MODULE_NAME, doe_module_init)
|