@simulatte/webgpu 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -12
- package/LICENSE +191 -0
- package/README.md +55 -41
- package/api-contract.md +67 -49
- package/architecture.md +317 -0
- package/assets/package-layers.svg +3 -3
- package/docs/doe-api-reference.html +1842 -0
- package/doe-api-design.md +237 -0
- package/examples/doe-api/README.md +19 -0
- package/examples/doe-api/buffers-readback.js +3 -2
- package/examples/{doe-routines/compute-once-like-input.js → doe-api/compute-one-shot-like-input.js} +1 -1
- package/examples/{doe-routines/compute-once-matmul.js → doe-api/compute-one-shot-matmul.js} +2 -2
- package/examples/{doe-routines/compute-once-multiple-inputs.js → doe-api/compute-one-shot-multiple-inputs.js} +1 -1
- package/examples/{doe-routines/compute-once.js → doe-api/compute-one-shot.js} +1 -1
- package/examples/doe-api/{compile-and-dispatch.js → kernel-create-and-dispatch.js} +4 -6
- package/examples/doe-api/{compute-dispatch.js → kernel-run.js} +4 -6
- package/headless-webgpu-comparison.md +3 -3
- package/jsdoc-style-guide.md +435 -0
- package/native/doe_napi.c +1481 -84
- package/package.json +18 -6
- package/prebuilds/darwin-arm64/doe_napi.node +0 -0
- package/prebuilds/darwin-arm64/libwebgpu_doe.dylib +0 -0
- package/prebuilds/darwin-arm64/metadata.json +5 -5
- package/prebuilds/linux-x64/metadata.json +1 -1
- package/scripts/generate-doe-api-docs.js +1607 -0
- package/scripts/generate-readme-assets.js +3 -3
- package/src/build_metadata.js +7 -4
- package/src/bun-ffi.js +1229 -474
- package/src/bun.js +5 -1
- package/src/compute.d.ts +16 -7
- package/src/compute.js +84 -53
- package/src/full.d.ts +16 -7
- package/src/full.js +12 -10
- package/src/index.js +679 -1324
- package/src/runtime_cli.js +17 -17
- package/src/shared/capabilities.js +144 -0
- package/src/shared/compiler-errors.js +78 -0
- package/src/shared/encoder-surface.js +295 -0
- package/src/shared/full-surface.js +514 -0
- package/src/shared/public-surface.js +82 -0
- package/src/shared/resource-lifecycle.js +120 -0
- package/src/shared/validation.js +495 -0
- package/src/webgpu_constants.js +30 -0
- package/support-contracts.md +2 -2
- package/compat-scope.md +0 -46
- package/layering-plan.md +0 -259
- package/src/auto_bind_group_layout.js +0 -32
- package/src/doe.d.ts +0 -184
- package/src/doe.js +0 -641
- package/zig-source-inventory.md +0 -468
package/native/doe_napi.c
CHANGED
|
@@ -62,11 +62,13 @@ typedef uint32_t WGPUBool;
|
|
|
62
62
|
#define WGPU_WAIT_STATUS_SUCCESS 1
|
|
63
63
|
#define WGPU_WAIT_STATUS_TIMED_OUT 2
|
|
64
64
|
#define WGPU_WAIT_STATUS_ERROR 3
|
|
65
|
+
#define WGPU_STATUS_SUCCESS 1
|
|
65
66
|
#define WGPU_MAP_ASYNC_STATUS_SUCCESS 1
|
|
66
67
|
#define WGPU_REQUEST_STATUS_SUCCESS 1
|
|
67
68
|
#define WGPU_CALLBACK_MODE_ALLOW_PROCESS_EVENTS 2
|
|
68
69
|
#define DOE_DEFAULT_TIMEOUT_NS 2000000000ULL
|
|
69
70
|
#define DOE_WAIT_SLICE_NS 1000ULL
|
|
71
|
+
#define DOE_ERROR_BUF_CAP 512
|
|
70
72
|
|
|
71
73
|
typedef struct { uint64_t id; } WGPUFuture;
|
|
72
74
|
typedef struct { const char* data; size_t length; } WGPUStringView;
|
|
@@ -187,6 +189,14 @@ typedef struct {
|
|
|
187
189
|
uint32_t immediateSize;
|
|
188
190
|
} WGPUPipelineLayoutDescriptor;
|
|
189
191
|
|
|
192
|
+
typedef struct {
|
|
193
|
+
uint32_t group;
|
|
194
|
+
uint32_t binding;
|
|
195
|
+
uint32_t kind;
|
|
196
|
+
uint32_t addr_space;
|
|
197
|
+
uint32_t access;
|
|
198
|
+
} DoeShaderBindingInfo;
|
|
199
|
+
|
|
190
200
|
typedef struct {
|
|
191
201
|
void* nextInChain;
|
|
192
202
|
WGPUStringView label;
|
|
@@ -199,6 +209,30 @@ typedef struct {
|
|
|
199
209
|
uint32_t depthOrArrayLayers;
|
|
200
210
|
} WGPUExtent3D;
|
|
201
211
|
|
|
212
|
+
typedef struct {
|
|
213
|
+
uint32_t x;
|
|
214
|
+
uint32_t y;
|
|
215
|
+
uint32_t z;
|
|
216
|
+
} WGPUOrigin3D;
|
|
217
|
+
|
|
218
|
+
typedef struct {
|
|
219
|
+
uint64_t offset;
|
|
220
|
+
uint32_t bytesPerRow;
|
|
221
|
+
uint32_t rowsPerImage;
|
|
222
|
+
} WGPUTexelCopyBufferLayout;
|
|
223
|
+
|
|
224
|
+
typedef struct {
|
|
225
|
+
WGPUTexelCopyBufferLayout layout;
|
|
226
|
+
WGPUBuffer buffer;
|
|
227
|
+
} WGPUTexelCopyBufferInfo;
|
|
228
|
+
|
|
229
|
+
typedef struct {
|
|
230
|
+
WGPUTexture texture;
|
|
231
|
+
uint32_t mipLevel;
|
|
232
|
+
WGPUOrigin3D origin;
|
|
233
|
+
uint32_t aspect;
|
|
234
|
+
} WGPUTexelCopyTextureInfo;
|
|
235
|
+
|
|
202
236
|
typedef struct {
|
|
203
237
|
void* nextInChain;
|
|
204
238
|
WGPUStringView label;
|
|
@@ -252,6 +286,19 @@ typedef struct {
|
|
|
252
286
|
WGPUColor clearValue;
|
|
253
287
|
} WGPURenderPassColorAttachment;
|
|
254
288
|
|
|
289
|
+
typedef struct {
|
|
290
|
+
void* nextInChain;
|
|
291
|
+
WGPUTextureView view;
|
|
292
|
+
uint32_t depthLoadOp;
|
|
293
|
+
uint32_t depthStoreOp;
|
|
294
|
+
float depthClearValue;
|
|
295
|
+
WGPUBool depthReadOnly;
|
|
296
|
+
uint32_t stencilLoadOp;
|
|
297
|
+
uint32_t stencilStoreOp;
|
|
298
|
+
uint32_t stencilClearValue;
|
|
299
|
+
WGPUBool stencilReadOnly;
|
|
300
|
+
} WGPURenderPassDepthStencilAttachment;
|
|
301
|
+
|
|
255
302
|
typedef struct {
|
|
256
303
|
void* nextInChain;
|
|
257
304
|
WGPUStringView label;
|
|
@@ -262,6 +309,102 @@ typedef struct {
|
|
|
262
309
|
void* timestampWrites;
|
|
263
310
|
} WGPURenderPassDescriptor;
|
|
264
311
|
|
|
312
|
+
typedef struct {
|
|
313
|
+
void* nextInChain;
|
|
314
|
+
WGPUStringView key;
|
|
315
|
+
double value;
|
|
316
|
+
} WGPUConstantEntry;
|
|
317
|
+
|
|
318
|
+
typedef struct {
|
|
319
|
+
void* nextInChain;
|
|
320
|
+
WGPUShaderModule module;
|
|
321
|
+
WGPUStringView entryPoint;
|
|
322
|
+
size_t constantCount;
|
|
323
|
+
const WGPUConstantEntry* constants;
|
|
324
|
+
size_t bufferCount;
|
|
325
|
+
const void* buffers;
|
|
326
|
+
} WGPURenderVertexState;
|
|
327
|
+
|
|
328
|
+
typedef struct {
|
|
329
|
+
void* nextInChain;
|
|
330
|
+
uint32_t format;
|
|
331
|
+
uint64_t offset;
|
|
332
|
+
uint32_t shaderLocation;
|
|
333
|
+
} WGPURenderVertexAttribute;
|
|
334
|
+
|
|
335
|
+
typedef struct {
|
|
336
|
+
void* nextInChain;
|
|
337
|
+
uint32_t stepMode;
|
|
338
|
+
uint64_t arrayStride;
|
|
339
|
+
size_t attributeCount;
|
|
340
|
+
const WGPURenderVertexAttribute* attributes;
|
|
341
|
+
} WGPURenderVertexBufferLayout;
|
|
342
|
+
|
|
343
|
+
typedef struct {
|
|
344
|
+
void* nextInChain;
|
|
345
|
+
uint32_t format;
|
|
346
|
+
const void* blend;
|
|
347
|
+
uint64_t writeMask;
|
|
348
|
+
} WGPURenderColorTargetState;
|
|
349
|
+
|
|
350
|
+
typedef struct {
|
|
351
|
+
void* nextInChain;
|
|
352
|
+
WGPUShaderModule module;
|
|
353
|
+
WGPUStringView entryPoint;
|
|
354
|
+
size_t constantCount;
|
|
355
|
+
const WGPUConstantEntry* constants;
|
|
356
|
+
size_t targetCount;
|
|
357
|
+
const WGPURenderColorTargetState* targets;
|
|
358
|
+
} WGPURenderFragmentState;
|
|
359
|
+
|
|
360
|
+
typedef struct {
|
|
361
|
+
void* nextInChain;
|
|
362
|
+
uint32_t topology;
|
|
363
|
+
uint32_t stripIndexFormat;
|
|
364
|
+
uint32_t frontFace;
|
|
365
|
+
uint32_t cullMode;
|
|
366
|
+
WGPUBool unclippedDepth;
|
|
367
|
+
} WGPURenderPrimitiveState;
|
|
368
|
+
|
|
369
|
+
typedef struct {
|
|
370
|
+
void* nextInChain;
|
|
371
|
+
uint32_t count;
|
|
372
|
+
uint32_t mask;
|
|
373
|
+
WGPUBool alphaToCoverageEnabled;
|
|
374
|
+
} WGPURenderMultisampleState;
|
|
375
|
+
|
|
376
|
+
typedef struct {
|
|
377
|
+
uint32_t compare;
|
|
378
|
+
uint32_t failOp;
|
|
379
|
+
uint32_t depthFailOp;
|
|
380
|
+
uint32_t passOp;
|
|
381
|
+
} WGPURenderStencilFaceState;
|
|
382
|
+
|
|
383
|
+
typedef struct {
|
|
384
|
+
void* nextInChain;
|
|
385
|
+
uint32_t format;
|
|
386
|
+
uint32_t depthWriteEnabled;
|
|
387
|
+
uint32_t depthCompare;
|
|
388
|
+
WGPURenderStencilFaceState stencilFront;
|
|
389
|
+
WGPURenderStencilFaceState stencilBack;
|
|
390
|
+
uint32_t stencilReadMask;
|
|
391
|
+
uint32_t stencilWriteMask;
|
|
392
|
+
int32_t depthBias;
|
|
393
|
+
float depthBiasSlopeScale;
|
|
394
|
+
float depthBiasClamp;
|
|
395
|
+
} WGPURenderDepthStencilState;
|
|
396
|
+
|
|
397
|
+
typedef struct {
|
|
398
|
+
void* nextInChain;
|
|
399
|
+
WGPUStringView label;
|
|
400
|
+
WGPUPipelineLayout layout;
|
|
401
|
+
WGPURenderVertexState vertex;
|
|
402
|
+
WGPURenderPrimitiveState primitive;
|
|
403
|
+
const WGPURenderDepthStencilState* depthStencil;
|
|
404
|
+
WGPURenderMultisampleState multisample;
|
|
405
|
+
const WGPURenderFragmentState* fragment;
|
|
406
|
+
} WGPURenderPipelineDescriptor;
|
|
407
|
+
|
|
265
408
|
typedef struct {
|
|
266
409
|
void* nextInChain;
|
|
267
410
|
uint32_t maxTextureDimension1D;
|
|
@@ -357,9 +500,11 @@ DECL_PFN(uint32_t, wgpuInstanceWaitAny, (WGPUInstance, size_t, WGPUFutureWaitInf
|
|
|
357
500
|
DECL_PFN(void, wgpuInstanceProcessEvents, (WGPUInstance));
|
|
358
501
|
DECL_PFN(void, wgpuAdapterRelease, (WGPUAdapter));
|
|
359
502
|
DECL_PFN(WGPUBool, wgpuAdapterHasFeature, (WGPUAdapter, uint32_t));
|
|
503
|
+
DECL_PFN(uint32_t, wgpuAdapterGetLimits, (WGPUAdapter, void*));
|
|
360
504
|
DECL_PFN(WGPUFuture, wgpuAdapterRequestDevice, (WGPUAdapter, const void*, WGPURequestDeviceCallbackInfo));
|
|
361
505
|
DECL_PFN(void, wgpuDeviceRelease, (WGPUDevice));
|
|
362
506
|
DECL_PFN(WGPUBool, wgpuDeviceHasFeature, (WGPUDevice, uint32_t));
|
|
507
|
+
DECL_PFN(uint32_t, wgpuDeviceGetLimits, (WGPUDevice, void*));
|
|
363
508
|
DECL_PFN(WGPUQueue, wgpuDeviceGetQueue, (WGPUDevice));
|
|
364
509
|
DECL_PFN(WGPUBuffer, wgpuDeviceCreateBuffer, (WGPUDevice, const WGPUBufferDescriptor*));
|
|
365
510
|
DECL_PFN(WGPUShaderModule, wgpuDeviceCreateShaderModule, (WGPUDevice, const WGPUShaderModuleDescriptor*));
|
|
@@ -377,6 +522,8 @@ DECL_PFN(WGPUCommandEncoder, wgpuDeviceCreateCommandEncoder, (WGPUDevice, const
|
|
|
377
522
|
DECL_PFN(void, wgpuCommandEncoderRelease, (WGPUCommandEncoder));
|
|
378
523
|
DECL_PFN(WGPUComputePassEncoder, wgpuCommandEncoderBeginComputePass, (WGPUCommandEncoder, const WGPUComputePassDescriptor*));
|
|
379
524
|
DECL_PFN(void, wgpuCommandEncoderCopyBufferToBuffer, (WGPUCommandEncoder, WGPUBuffer, uint64_t, WGPUBuffer, uint64_t, uint64_t));
|
|
525
|
+
DECL_PFN(void, wgpuCommandEncoderCopyTextureToBuffer, (WGPUCommandEncoder, const WGPUTexelCopyTextureInfo*, const WGPUTexelCopyBufferInfo*, const WGPUExtent3D*));
|
|
526
|
+
DECL_PFN(void, doeNativeCommandEncoderCopyTextureToBuffer, (WGPUCommandEncoder, WGPUTexture, uint32_t, WGPUBuffer, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t));
|
|
380
527
|
DECL_PFN(WGPUCommandBuffer, wgpuCommandEncoderFinish, (WGPUCommandEncoder, const WGPUCommandBufferDescriptor*));
|
|
381
528
|
DECL_PFN(void, wgpuComputePassEncoderSetPipeline, (WGPUComputePassEncoder, WGPUComputePipeline));
|
|
382
529
|
DECL_PFN(void, wgpuComputePassEncoderSetBindGroup, (WGPUComputePassEncoder, uint32_t, WGPUBindGroup, size_t, const uint32_t*));
|
|
@@ -403,10 +550,25 @@ DECL_PFN(WGPURenderPipeline, wgpuDeviceCreateRenderPipeline, (WGPUDevice, const
|
|
|
403
550
|
DECL_PFN(void, wgpuRenderPipelineRelease, (WGPURenderPipeline));
|
|
404
551
|
DECL_PFN(WGPURenderPassEncoder, wgpuCommandEncoderBeginRenderPass, (WGPUCommandEncoder, const WGPURenderPassDescriptor*));
|
|
405
552
|
DECL_PFN(void, wgpuRenderPassEncoderSetPipeline, (WGPURenderPassEncoder, WGPURenderPipeline));
|
|
553
|
+
DECL_PFN(void, wgpuRenderPassEncoderSetBindGroup, (WGPURenderPassEncoder, uint32_t, WGPUBindGroup, size_t, const uint32_t*));
|
|
554
|
+
DECL_PFN(void, wgpuRenderPassEncoderSetVertexBuffer, (WGPURenderPassEncoder, uint32_t, WGPUBuffer, uint64_t, uint64_t));
|
|
555
|
+
DECL_PFN(void, wgpuRenderPassEncoderSetIndexBuffer, (WGPURenderPassEncoder, WGPUBuffer, uint32_t, uint64_t, uint64_t));
|
|
406
556
|
DECL_PFN(void, wgpuRenderPassEncoderDraw, (WGPURenderPassEncoder, uint32_t, uint32_t, uint32_t, uint32_t));
|
|
557
|
+
DECL_PFN(void, wgpuRenderPassEncoderDrawIndexed, (WGPURenderPassEncoder, uint32_t, uint32_t, uint32_t, int32_t, uint32_t));
|
|
407
558
|
DECL_PFN(void, wgpuRenderPassEncoderEnd, (WGPURenderPassEncoder));
|
|
408
559
|
DECL_PFN(void, wgpuRenderPassEncoderRelease, (WGPURenderPassEncoder));
|
|
409
|
-
DECL_PFN(uint32_t,
|
|
560
|
+
DECL_PFN(uint32_t, doeNativeAdapterGetLimits, (WGPUAdapter, void*));
|
|
561
|
+
DECL_PFN(uint32_t, doeNativeDeviceGetLimits, (WGPUDevice, void*));
|
|
562
|
+
DECL_PFN(uint32_t, doeNativeAdapterHasFeature, (WGPUAdapter, uint32_t));
|
|
563
|
+
DECL_PFN(uint32_t, doeNativeDeviceHasFeature, (WGPUDevice, uint32_t));
|
|
564
|
+
DECL_PFN(size_t, doeNativeCopyLastErrorMessage, (char*, size_t));
|
|
565
|
+
DECL_PFN(size_t, doeNativeCopyLastErrorStage, (char*, size_t));
|
|
566
|
+
DECL_PFN(size_t, doeNativeCopyLastErrorKind, (char*, size_t));
|
|
567
|
+
DECL_PFN(uint32_t, doeNativeGetLastErrorLine, (void));
|
|
568
|
+
DECL_PFN(uint32_t, doeNativeGetLastErrorColumn, (void));
|
|
569
|
+
DECL_PFN(uint32_t, doeNativeCheckShaderSource, (const char*, size_t));
|
|
570
|
+
DECL_PFN(size_t, doeNativeShaderModuleGetBindings, (WGPUShaderModule, DoeShaderBindingInfo*, size_t));
|
|
571
|
+
DECL_PFN(WGPUFuture, doeNativeAdapterRequestDevice, (WGPUAdapter, const void*, WGPURequestDeviceCallbackInfo));
|
|
410
572
|
|
|
411
573
|
/* Flat helpers are optional. When absent, the addon assembles the callback-info
|
|
412
574
|
* structs directly and calls the standard WebGPU request entrypoints. */
|
|
@@ -414,6 +576,10 @@ DECL_PFN(WGPUFuture, doeRequestAdapterFlat, (WGPUInstance, const void*, uint32_t
|
|
|
414
576
|
DECL_PFN(WGPUFuture, doeRequestDeviceFlat, (WGPUAdapter, const void*, uint32_t, WGPURequestDeviceCallback, void*, void*));
|
|
415
577
|
DECL_PFN(void, doeNativeQueueFlush, (void*));
|
|
416
578
|
DECL_PFN(void, doeNativeComputeDispatchFlush, (void*, void*, void**, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint64_t, void*, uint64_t, uint64_t));
|
|
579
|
+
DECL_PFN(WGPUQuerySet, doeNativeDeviceCreateQuerySet, (WGPUDevice, uint32_t, uint32_t));
|
|
580
|
+
DECL_PFN(void, doeNativeCommandEncoderWriteTimestamp, (WGPUCommandEncoder, WGPUQuerySet, uint32_t));
|
|
581
|
+
DECL_PFN(void, doeNativeCommandEncoderResolveQuerySet, (WGPUCommandEncoder, WGPUQuerySet, uint32_t, uint32_t, WGPUBuffer, uint64_t));
|
|
582
|
+
DECL_PFN(void, doeNativeQuerySetDestroy, (WGPUQuerySet));
|
|
417
583
|
typedef struct {
|
|
418
584
|
void* nextInChain;
|
|
419
585
|
uint32_t mode;
|
|
@@ -426,6 +592,25 @@ typedef WGPUFuture (*PFN_wgpuBufferMapAsync2)(WGPUBuffer, uint64_t, size_t, size
|
|
|
426
592
|
static PFN_wgpuBufferMapAsync2 pfn_wgpuBufferMapAsync2 = NULL;
|
|
427
593
|
|
|
428
594
|
static void* g_lib = NULL;
|
|
595
|
+
static uint64_t g_timeout_ns = DOE_DEFAULT_TIMEOUT_NS;
|
|
596
|
+
|
|
597
|
+
static uint64_t current_timeout_ns(void) {
|
|
598
|
+
return g_timeout_ns;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
static void copy_library_error_message(char* out, size_t out_len) {
|
|
602
|
+
if (!out || out_len == 0) return;
|
|
603
|
+
out[0] = '\0';
|
|
604
|
+
if (!pfn_doeNativeCopyLastErrorMessage) return;
|
|
605
|
+
pfn_doeNativeCopyLastErrorMessage(out, out_len);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
static void copy_library_error_meta(PFN_doeNativeCopyLastErrorMessage fn, char* out, size_t out_len) {
|
|
609
|
+
if (!out || out_len == 0) return;
|
|
610
|
+
out[0] = '\0';
|
|
611
|
+
if (!fn) return;
|
|
612
|
+
fn(out, out_len);
|
|
613
|
+
}
|
|
429
614
|
|
|
430
615
|
static uint64_t monotonic_now_ns(void) {
|
|
431
616
|
#ifdef _WIN32
|
|
@@ -463,12 +648,33 @@ static int process_events_until(WGPUInstance inst, volatile uint32_t* done, uint
|
|
|
463
648
|
return 1;
|
|
464
649
|
}
|
|
465
650
|
|
|
651
|
+
static void copy_string_view_message(WGPUStringView message, char* out, size_t out_len) {
|
|
652
|
+
if (!out || out_len == 0) return;
|
|
653
|
+
out[0] = '\0';
|
|
654
|
+
if (!message.data || message.length == 0) return;
|
|
655
|
+
size_t copy_len = message.length;
|
|
656
|
+
if (copy_len >= out_len) copy_len = out_len - 1;
|
|
657
|
+
memcpy(out, message.data, copy_len);
|
|
658
|
+
out[copy_len] = '\0';
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
static napi_value throw_status_error(napi_env env, const char* code, const char* prefix, uint32_t status, const char* detail) {
|
|
662
|
+
char msg[DOE_ERROR_BUF_CAP];
|
|
663
|
+
if (detail && detail[0] != '\0') {
|
|
664
|
+
snprintf(msg, sizeof(msg), "%s (status=%u, detail=%s)", prefix, status, detail);
|
|
665
|
+
} else {
|
|
666
|
+
snprintf(msg, sizeof(msg), "%s (status=%u)", prefix, status);
|
|
667
|
+
}
|
|
668
|
+
napi_throw_error(env, code, msg);
|
|
669
|
+
return NULL;
|
|
670
|
+
}
|
|
671
|
+
|
|
466
672
|
/* ================================================================
|
|
467
673
|
* N-API utility helpers
|
|
468
674
|
* ================================================================ */
|
|
469
675
|
|
|
470
|
-
#define NAPI_THROW(env, msg) do { napi_throw_error(env,
|
|
471
|
-
#define MAX_NAPI_ARGS
|
|
676
|
+
#define NAPI_THROW(env, msg) do { napi_throw_error(env, "DOE_ERROR", msg); return NULL; } while(0)
|
|
677
|
+
#define MAX_NAPI_ARGS 16
|
|
472
678
|
#define NAPI_ASSERT_ARGC(env, info, n) \
|
|
473
679
|
size_t _argc = (n); napi_value _args[MAX_NAPI_ARGS]; \
|
|
474
680
|
if ((n) > MAX_NAPI_ARGS) NAPI_THROW(env, "too many args"); \
|
|
@@ -514,6 +720,20 @@ static int64_t get_int64_prop(napi_env env, napi_value obj, const char* key) {
|
|
|
514
720
|
return out;
|
|
515
721
|
}
|
|
516
722
|
|
|
723
|
+
static int64_t get_int64_value(napi_env env, napi_value value) {
|
|
724
|
+
int64_t out = 0;
|
|
725
|
+
napi_get_value_int64(env, value, &out);
|
|
726
|
+
return out;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
static double get_double_prop(napi_env env, napi_value obj, const char* key) {
|
|
730
|
+
napi_value val;
|
|
731
|
+
napi_get_named_property(env, obj, key, &val);
|
|
732
|
+
double out = 0.0;
|
|
733
|
+
napi_get_value_double(env, val, &out);
|
|
734
|
+
return out;
|
|
735
|
+
}
|
|
736
|
+
|
|
517
737
|
static bool get_bool_prop(napi_env env, napi_value obj, const char* key) {
|
|
518
738
|
napi_value val;
|
|
519
739
|
napi_get_named_property(env, obj, key, &val);
|
|
@@ -537,6 +757,16 @@ static napi_value get_prop(napi_env env, napi_value obj, const char* key) {
|
|
|
537
757
|
return val;
|
|
538
758
|
}
|
|
539
759
|
|
|
760
|
+
static char* dup_string_value(napi_env env, napi_value value, size_t* out_len) {
|
|
761
|
+
size_t len = 0;
|
|
762
|
+
napi_get_value_string_utf8(env, value, NULL, 0, &len);
|
|
763
|
+
char* out = (char*)malloc(len + 1);
|
|
764
|
+
if (!out) return NULL;
|
|
765
|
+
napi_get_value_string_utf8(env, value, out, len + 1, &len);
|
|
766
|
+
if (out_len) *out_len = len;
|
|
767
|
+
return out;
|
|
768
|
+
}
|
|
769
|
+
|
|
540
770
|
static napi_valuetype prop_type(napi_env env, napi_value obj, const char* key) {
|
|
541
771
|
napi_value val;
|
|
542
772
|
napi_get_named_property(env, obj, key, &val);
|
|
@@ -563,6 +793,15 @@ static napi_value doe_load_library(napi_env env, napi_callback_info info) {
|
|
|
563
793
|
free(path);
|
|
564
794
|
if (!g_lib) NAPI_THROW(env, "Failed to load libwebgpu_doe");
|
|
565
795
|
|
|
796
|
+
const char* timeout_env = getenv("DOE_TIMEOUT_MS");
|
|
797
|
+
if (timeout_env && timeout_env[0] != '\0') {
|
|
798
|
+
char* end = NULL;
|
|
799
|
+
unsigned long parsed = strtoul(timeout_env, &end, 10);
|
|
800
|
+
if (end && *end == '\0') {
|
|
801
|
+
g_timeout_ns = (uint64_t)parsed * 1000000ULL;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
566
805
|
LOAD_SYM(wgpuCreateInstance);
|
|
567
806
|
LOAD_SYM(wgpuInstanceRelease);
|
|
568
807
|
LOAD_SYM(wgpuInstanceRequestAdapter);
|
|
@@ -570,6 +809,7 @@ static napi_value doe_load_library(napi_env env, napi_callback_info info) {
|
|
|
570
809
|
LOAD_SYM(wgpuInstanceProcessEvents);
|
|
571
810
|
LOAD_SYM(wgpuAdapterRelease);
|
|
572
811
|
LOAD_SYM(wgpuAdapterHasFeature);
|
|
812
|
+
LOAD_SYM(wgpuAdapterGetLimits);
|
|
573
813
|
LOAD_SYM(wgpuAdapterRequestDevice);
|
|
574
814
|
LOAD_SYM(wgpuDeviceRelease);
|
|
575
815
|
LOAD_SYM(wgpuDeviceHasFeature);
|
|
@@ -590,6 +830,8 @@ static napi_value doe_load_library(napi_env env, napi_callback_info info) {
|
|
|
590
830
|
LOAD_SYM(wgpuCommandEncoderRelease);
|
|
591
831
|
LOAD_SYM(wgpuCommandEncoderBeginComputePass);
|
|
592
832
|
LOAD_SYM(wgpuCommandEncoderCopyBufferToBuffer);
|
|
833
|
+
LOAD_SYM(wgpuCommandEncoderCopyTextureToBuffer);
|
|
834
|
+
LOAD_SYM(doeNativeCommandEncoderCopyTextureToBuffer);
|
|
593
835
|
LOAD_SYM(wgpuCommandEncoderFinish);
|
|
594
836
|
LOAD_SYM(wgpuComputePassEncoderSetPipeline);
|
|
595
837
|
LOAD_SYM(wgpuComputePassEncoderSetBindGroup);
|
|
@@ -616,15 +858,38 @@ static napi_value doe_load_library(napi_env env, napi_callback_info info) {
|
|
|
616
858
|
LOAD_SYM(wgpuRenderPipelineRelease);
|
|
617
859
|
LOAD_SYM(wgpuCommandEncoderBeginRenderPass);
|
|
618
860
|
LOAD_SYM(wgpuRenderPassEncoderSetPipeline);
|
|
861
|
+
LOAD_SYM(wgpuRenderPassEncoderSetBindGroup);
|
|
862
|
+
LOAD_SYM(wgpuRenderPassEncoderSetVertexBuffer);
|
|
863
|
+
LOAD_SYM(wgpuRenderPassEncoderSetIndexBuffer);
|
|
619
864
|
LOAD_SYM(wgpuRenderPassEncoderDraw);
|
|
865
|
+
LOAD_SYM(wgpuRenderPassEncoderDrawIndexed);
|
|
620
866
|
LOAD_SYM(wgpuRenderPassEncoderEnd);
|
|
621
867
|
LOAD_SYM(wgpuRenderPassEncoderRelease);
|
|
868
|
+
LOAD_SYM(wgpuAdapterGetLimits);
|
|
869
|
+
LOAD_SYM(wgpuAdapterHasFeature);
|
|
870
|
+
LOAD_SYM(wgpuDeviceHasFeature);
|
|
622
871
|
LOAD_SYM(wgpuDeviceGetLimits);
|
|
872
|
+
pfn_doeNativeAdapterGetLimits = (PFN_doeNativeAdapterGetLimits)LIB_SYM(g_lib, "doeNativeAdapterGetLimits");
|
|
873
|
+
pfn_doeNativeDeviceGetLimits = (PFN_doeNativeDeviceGetLimits)LIB_SYM(g_lib, "doeNativeDeviceGetLimits");
|
|
874
|
+
pfn_doeNativeAdapterHasFeature = (PFN_doeNativeAdapterHasFeature)LIB_SYM(g_lib, "doeNativeAdapterHasFeature");
|
|
875
|
+
pfn_doeNativeDeviceHasFeature = (PFN_doeNativeDeviceHasFeature)LIB_SYM(g_lib, "doeNativeDeviceHasFeature");
|
|
876
|
+
pfn_doeNativeCopyLastErrorMessage = (PFN_doeNativeCopyLastErrorMessage)LIB_SYM(g_lib, "doeNativeCopyLastErrorMessage");
|
|
877
|
+
pfn_doeNativeCopyLastErrorStage = (PFN_doeNativeCopyLastErrorStage)LIB_SYM(g_lib, "doeNativeCopyLastErrorStage");
|
|
878
|
+
pfn_doeNativeCopyLastErrorKind = (PFN_doeNativeCopyLastErrorKind)LIB_SYM(g_lib, "doeNativeCopyLastErrorKind");
|
|
879
|
+
pfn_doeNativeGetLastErrorLine = (PFN_doeNativeGetLastErrorLine)LIB_SYM(g_lib, "doeNativeGetLastErrorLine");
|
|
880
|
+
pfn_doeNativeGetLastErrorColumn = (PFN_doeNativeGetLastErrorColumn)LIB_SYM(g_lib, "doeNativeGetLastErrorColumn");
|
|
881
|
+
pfn_doeNativeCheckShaderSource = (PFN_doeNativeCheckShaderSource)LIB_SYM(g_lib, "doeNativeCheckShaderSource");
|
|
882
|
+
pfn_doeNativeShaderModuleGetBindings = (PFN_doeNativeShaderModuleGetBindings)LIB_SYM(g_lib, "doeNativeShaderModuleGetBindings");
|
|
883
|
+
pfn_doeNativeAdapterRequestDevice = (PFN_doeNativeAdapterRequestDevice)LIB_SYM(g_lib, "doeNativeAdapterRequestDevice");
|
|
623
884
|
pfn_doeRequestAdapterFlat = (PFN_doeRequestAdapterFlat)LIB_SYM(g_lib, "doeRequestAdapterFlat");
|
|
624
885
|
pfn_doeRequestDeviceFlat = (PFN_doeRequestDeviceFlat)LIB_SYM(g_lib, "doeRequestDeviceFlat");
|
|
625
886
|
pfn_wgpuBufferMapAsync2 = (PFN_wgpuBufferMapAsync2)LIB_SYM(g_lib, "wgpuBufferMapAsync");
|
|
626
887
|
pfn_doeNativeQueueFlush = (PFN_doeNativeQueueFlush)LIB_SYM(g_lib, "doeNativeQueueFlush");
|
|
627
888
|
pfn_doeNativeComputeDispatchFlush = (PFN_doeNativeComputeDispatchFlush)LIB_SYM(g_lib, "doeNativeComputeDispatchFlush");
|
|
889
|
+
pfn_doeNativeDeviceCreateQuerySet = (PFN_doeNativeDeviceCreateQuerySet)LIB_SYM(g_lib, "doeNativeDeviceCreateQuerySet");
|
|
890
|
+
pfn_doeNativeCommandEncoderWriteTimestamp = (PFN_doeNativeCommandEncoderWriteTimestamp)LIB_SYM(g_lib, "doeNativeCommandEncoderWriteTimestamp");
|
|
891
|
+
pfn_doeNativeCommandEncoderResolveQuerySet = (PFN_doeNativeCommandEncoderResolveQuerySet)LIB_SYM(g_lib, "doeNativeCommandEncoderResolveQuerySet");
|
|
892
|
+
pfn_doeNativeQuerySetDestroy = (PFN_doeNativeQuerySetDestroy)LIB_SYM(g_lib, "doeNativeQuerySetDestroy");
|
|
628
893
|
|
|
629
894
|
/* Validate all critical function pointers were resolved. */
|
|
630
895
|
if (!pfn_wgpuCreateInstance || !pfn_wgpuInstanceRelease || !pfn_wgpuInstanceRequestAdapter ||
|
|
@@ -674,14 +939,16 @@ typedef struct {
|
|
|
674
939
|
uint32_t status;
|
|
675
940
|
WGPUAdapter adapter;
|
|
676
941
|
uint32_t done;
|
|
942
|
+
char message[DOE_ERROR_BUF_CAP];
|
|
677
943
|
} AdapterRequestResult;
|
|
678
944
|
|
|
679
945
|
static void adapter_callback(uint32_t status, WGPUAdapter adapter,
|
|
680
946
|
WGPUStringView message, void* userdata1, void* userdata2) {
|
|
681
|
-
(void)
|
|
947
|
+
(void)userdata2;
|
|
682
948
|
AdapterRequestResult* r = (AdapterRequestResult*)userdata1;
|
|
683
949
|
r->status = status;
|
|
684
950
|
r->adapter = adapter;
|
|
951
|
+
copy_string_view_message(message, r->message, sizeof(r->message));
|
|
685
952
|
r->done = 1;
|
|
686
953
|
}
|
|
687
954
|
|
|
@@ -691,7 +958,7 @@ static napi_value doe_request_adapter(napi_env env, napi_callback_info info) {
|
|
|
691
958
|
WGPUInstance inst = unwrap_ptr(env, _args[0]);
|
|
692
959
|
if (!inst) NAPI_THROW(env, "Invalid instance");
|
|
693
960
|
|
|
694
|
-
AdapterRequestResult result = {0
|
|
961
|
+
AdapterRequestResult result = {0};
|
|
695
962
|
WGPUFuture future;
|
|
696
963
|
if (pfn_doeRequestAdapterFlat) {
|
|
697
964
|
future = pfn_doeRequestAdapterFlat(
|
|
@@ -707,9 +974,10 @@ static napi_value doe_request_adapter(napi_env env, napi_callback_info info) {
|
|
|
707
974
|
future = pfn_wgpuInstanceRequestAdapter(inst, NULL, callback_info);
|
|
708
975
|
}
|
|
709
976
|
if (future.id == 0) NAPI_THROW(env, "requestAdapter future unavailable");
|
|
710
|
-
if (!process_events_until(inst, &result.done,
|
|
711
|
-
|
|
712
|
-
|
|
977
|
+
if (!process_events_until(inst, &result.done, current_timeout_ns()))
|
|
978
|
+
return throw_status_error(env, "DOE_REQUEST_ADAPTER_TIMEOUT", "requestAdapter timed out", result.status, result.message);
|
|
979
|
+
if (result.status != WGPU_REQUEST_STATUS_SUCCESS || !result.adapter)
|
|
980
|
+
return throw_status_error(env, "DOE_REQUEST_ADAPTER_ERROR", "requestAdapter failed", result.status, result.message);
|
|
713
981
|
|
|
714
982
|
return wrap_ptr(env, result.adapter);
|
|
715
983
|
}
|
|
@@ -729,14 +997,16 @@ typedef struct {
|
|
|
729
997
|
uint32_t status;
|
|
730
998
|
WGPUDevice device;
|
|
731
999
|
uint32_t done;
|
|
1000
|
+
char message[DOE_ERROR_BUF_CAP];
|
|
732
1001
|
} DeviceRequestResult;
|
|
733
1002
|
|
|
734
1003
|
static void device_callback(uint32_t status, WGPUDevice device,
|
|
735
1004
|
WGPUStringView message, void* userdata1, void* userdata2) {
|
|
736
|
-
(void)
|
|
1005
|
+
(void)userdata2;
|
|
737
1006
|
DeviceRequestResult* r = (DeviceRequestResult*)userdata1;
|
|
738
1007
|
r->status = status;
|
|
739
1008
|
r->device = device;
|
|
1009
|
+
copy_string_view_message(message, r->message, sizeof(r->message));
|
|
740
1010
|
r->done = 1;
|
|
741
1011
|
}
|
|
742
1012
|
|
|
@@ -747,25 +1017,22 @@ static napi_value doe_request_device(napi_env env, napi_callback_info info) {
|
|
|
747
1017
|
WGPUAdapter adapter = unwrap_ptr(env, _args[1]);
|
|
748
1018
|
if (!inst || !adapter) NAPI_THROW(env, "Invalid instance or adapter");
|
|
749
1019
|
|
|
750
|
-
DeviceRequestResult result = {0
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
.userdata2 = NULL,
|
|
762
|
-
};
|
|
763
|
-
future = pfn_wgpuAdapterRequestDevice(adapter, NULL, callback_info);
|
|
764
|
-
}
|
|
1020
|
+
DeviceRequestResult result = {0};
|
|
1021
|
+
const WGPURequestDeviceCallbackInfo callback_info = {
|
|
1022
|
+
.nextInChain = NULL,
|
|
1023
|
+
.mode = WGPU_CALLBACK_MODE_ALLOW_PROCESS_EVENTS,
|
|
1024
|
+
.callback = device_callback,
|
|
1025
|
+
.userdata1 = &result,
|
|
1026
|
+
.userdata2 = NULL,
|
|
1027
|
+
};
|
|
1028
|
+
WGPUFuture future = pfn_doeNativeAdapterRequestDevice
|
|
1029
|
+
? pfn_doeNativeAdapterRequestDevice(adapter, NULL, callback_info)
|
|
1030
|
+
: pfn_wgpuAdapterRequestDevice(adapter, NULL, callback_info);
|
|
765
1031
|
if (future.id == 0) NAPI_THROW(env, "requestDevice future unavailable");
|
|
766
|
-
if (!process_events_until(inst, &result.done,
|
|
767
|
-
|
|
768
|
-
|
|
1032
|
+
if (!process_events_until(inst, &result.done, current_timeout_ns()))
|
|
1033
|
+
return throw_status_error(env, "DOE_REQUEST_DEVICE_TIMEOUT", "requestDevice timed out", result.status, result.message);
|
|
1034
|
+
if (result.status != WGPU_REQUEST_STATUS_SUCCESS || !result.device)
|
|
1035
|
+
return throw_status_error(env, "DOE_REQUEST_DEVICE_ERROR", "requestDevice failed", result.status, result.message);
|
|
769
1036
|
|
|
770
1037
|
return wrap_ptr(env, result.device);
|
|
771
1038
|
}
|
|
@@ -824,26 +1091,30 @@ static napi_value doe_buffer_unmap(napi_env env, napi_callback_info info) {
|
|
|
824
1091
|
typedef struct {
|
|
825
1092
|
uint32_t status;
|
|
826
1093
|
uint32_t done;
|
|
1094
|
+
char message[DOE_ERROR_BUF_CAP];
|
|
827
1095
|
} BufferMapResult;
|
|
828
1096
|
|
|
829
1097
|
typedef struct {
|
|
830
1098
|
uint32_t status;
|
|
831
1099
|
uint32_t done;
|
|
1100
|
+
char message[DOE_ERROR_BUF_CAP];
|
|
832
1101
|
} QueueWorkDoneResult;
|
|
833
1102
|
|
|
834
1103
|
static void buffer_map_callback(uint32_t status, WGPUStringView message,
|
|
835
1104
|
void* userdata1, void* userdata2) {
|
|
836
|
-
(void)
|
|
1105
|
+
(void)userdata2;
|
|
837
1106
|
BufferMapResult* r = (BufferMapResult*)userdata1;
|
|
838
1107
|
r->status = status;
|
|
1108
|
+
copy_string_view_message(message, r->message, sizeof(r->message));
|
|
839
1109
|
r->done = 1;
|
|
840
1110
|
}
|
|
841
1111
|
|
|
842
1112
|
static void queue_work_done_callback(uint32_t status, WGPUStringView message,
|
|
843
1113
|
void* userdata1, void* userdata2) {
|
|
844
|
-
(void)
|
|
1114
|
+
(void)userdata2;
|
|
845
1115
|
QueueWorkDoneResult* r = (QueueWorkDoneResult*)userdata1;
|
|
846
1116
|
r->status = status;
|
|
1117
|
+
copy_string_view_message(message, r->message, sizeof(r->message));
|
|
847
1118
|
r->done = 1;
|
|
848
1119
|
}
|
|
849
1120
|
|
|
@@ -853,13 +1124,14 @@ static napi_value doe_buffer_map_sync(napi_env env, napi_callback_info info) {
|
|
|
853
1124
|
CHECK_LIB_LOADED(env);
|
|
854
1125
|
WGPUInstance inst = unwrap_ptr(env, _args[0]);
|
|
855
1126
|
WGPUBuffer buf = unwrap_ptr(env, _args[1]);
|
|
1127
|
+
if (!inst || !buf) NAPI_THROW(env, "bufferMapSync requires instance and buffer");
|
|
856
1128
|
uint32_t mode;
|
|
857
1129
|
napi_get_value_uint32(env, _args[2], &mode);
|
|
858
1130
|
int64_t offset_i, size_i;
|
|
859
1131
|
napi_get_value_int64(env, _args[3], &offset_i);
|
|
860
1132
|
napi_get_value_int64(env, _args[4], &size_i);
|
|
861
1133
|
|
|
862
|
-
BufferMapResult result = {0
|
|
1134
|
+
BufferMapResult result = {0};
|
|
863
1135
|
WGPUBufferMapCallbackInfo cb_info = {
|
|
864
1136
|
.nextInChain = NULL,
|
|
865
1137
|
.mode = WGPU_CALLBACK_MODE_ALLOW_PROCESS_EVENTS,
|
|
@@ -871,9 +1143,10 @@ static napi_value doe_buffer_map_sync(napi_env env, napi_callback_info info) {
|
|
|
871
1143
|
WGPUFuture future = pfn_wgpuBufferMapAsync2(buf, (uint64_t)mode,
|
|
872
1144
|
(size_t)offset_i, (size_t)size_i, cb_info);
|
|
873
1145
|
if (future.id == 0) NAPI_THROW(env, "bufferMapAsync future unavailable");
|
|
874
|
-
if (!process_events_until(inst, &result.done,
|
|
875
|
-
result.status
|
|
876
|
-
|
|
1146
|
+
if (!process_events_until(inst, &result.done, current_timeout_ns()))
|
|
1147
|
+
return throw_status_error(env, "DOE_BUFFER_MAP_TIMEOUT", "bufferMapAsync timed out", result.status, result.message);
|
|
1148
|
+
if (result.status != WGPU_MAP_ASYNC_STATUS_SUCCESS)
|
|
1149
|
+
return throw_status_error(env, "DOE_BUFFER_MAP_ERROR", "bufferMapAsync failed", result.status, result.message);
|
|
877
1150
|
|
|
878
1151
|
napi_value ok;
|
|
879
1152
|
napi_get_boolean(env, true, &ok);
|
|
@@ -889,17 +1162,90 @@ static napi_value doe_buffer_get_mapped_range(napi_env env, napi_callback_info i
|
|
|
889
1162
|
napi_get_value_int64(env, _args[1], &offset_i);
|
|
890
1163
|
napi_get_value_int64(env, _args[2], &size_i);
|
|
891
1164
|
|
|
892
|
-
|
|
1165
|
+
void* data = pfn_wgpuBufferGetMappedRange(buf, (size_t)offset_i, (size_t)size_i);
|
|
1166
|
+
if (!data) {
|
|
1167
|
+
data = (void*)pfn_wgpuBufferGetConstMappedRange(buf, (size_t)offset_i, (size_t)size_i);
|
|
1168
|
+
}
|
|
893
1169
|
if (!data) NAPI_THROW(env, "getMappedRange returned NULL");
|
|
894
1170
|
|
|
895
|
-
/* Copy native data into a JS ArrayBuffer */
|
|
896
|
-
void* ab_data = NULL;
|
|
897
1171
|
napi_value ab;
|
|
898
|
-
|
|
899
|
-
memcpy(ab_data, data, (size_t)size_i);
|
|
1172
|
+
napi_create_external_arraybuffer(env, data, (size_t)size_i, NULL, NULL, &ab);
|
|
900
1173
|
return ab;
|
|
901
1174
|
}
|
|
902
1175
|
|
|
1176
|
+
static napi_value doe_buffer_write_mapped_range(napi_env env, napi_callback_info info) {
|
|
1177
|
+
NAPI_ASSERT_ARGC(env, info, 3);
|
|
1178
|
+
CHECK_LIB_LOADED(env);
|
|
1179
|
+
WGPUBuffer buf = unwrap_ptr(env, _args[0]);
|
|
1180
|
+
int64_t offset_i = 0;
|
|
1181
|
+
napi_get_value_int64(env, _args[1], &offset_i);
|
|
1182
|
+
|
|
1183
|
+
void* data = NULL;
|
|
1184
|
+
size_t byte_length = 0;
|
|
1185
|
+
bool is_typed_array = false;
|
|
1186
|
+
napi_is_typedarray(env, _args[2], &is_typed_array);
|
|
1187
|
+
if (is_typed_array) {
|
|
1188
|
+
napi_typedarray_type ta_type;
|
|
1189
|
+
size_t ta_length = 0;
|
|
1190
|
+
void* ta_data = NULL;
|
|
1191
|
+
napi_value ta_arraybuffer;
|
|
1192
|
+
size_t ta_byte_offset = 0;
|
|
1193
|
+
napi_get_typedarray_info(env, _args[2], &ta_type, &ta_length, &ta_data, &ta_arraybuffer, &ta_byte_offset);
|
|
1194
|
+
data = ta_data;
|
|
1195
|
+
switch (ta_type) {
|
|
1196
|
+
case napi_uint16_array: case napi_int16_array: byte_length = ta_length * 2; break;
|
|
1197
|
+
case napi_uint32_array: case napi_int32_array: case napi_float32_array: byte_length = ta_length * 4; break;
|
|
1198
|
+
case napi_float64_array: case napi_bigint64_array: case napi_biguint64_array: byte_length = ta_length * 8; break;
|
|
1199
|
+
default: byte_length = ta_length; break;
|
|
1200
|
+
}
|
|
1201
|
+
} else {
|
|
1202
|
+
bool is_ab = false;
|
|
1203
|
+
napi_is_arraybuffer(env, _args[2], &is_ab);
|
|
1204
|
+
if (is_ab) {
|
|
1205
|
+
napi_get_arraybuffer_info(env, _args[2], &data, &byte_length);
|
|
1206
|
+
} else {
|
|
1207
|
+
bool is_buffer = false;
|
|
1208
|
+
napi_is_buffer(env, _args[2], &is_buffer);
|
|
1209
|
+
if (is_buffer) {
|
|
1210
|
+
napi_get_buffer_info(env, _args[2], &data, &byte_length);
|
|
1211
|
+
} else {
|
|
1212
|
+
NAPI_THROW(env, "bufferWriteMappedRange: data must be TypedArray, ArrayBuffer, or Buffer");
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
void* mapped = pfn_wgpuBufferGetMappedRange(buf, (size_t)offset_i, byte_length);
|
|
1218
|
+
if (!mapped) NAPI_THROW(env, "bufferWriteMappedRange: mapped range unavailable");
|
|
1219
|
+
memcpy(mapped, data, byte_length);
|
|
1220
|
+
return NULL;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
static napi_value doe_buffer_read_indirect_counts(napi_env env, napi_callback_info info) {
|
|
1224
|
+
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1225
|
+
CHECK_LIB_LOADED(env);
|
|
1226
|
+
WGPUBuffer buf = unwrap_ptr(env, _args[0]);
|
|
1227
|
+
int64_t offset_i = 0;
|
|
1228
|
+
napi_get_value_int64(env, _args[1], &offset_i);
|
|
1229
|
+
if (!buf) NAPI_THROW(env, "bufferReadIndirectCounts requires buffer");
|
|
1230
|
+
if (offset_i < 0) NAPI_THROW(env, "bufferReadIndirectCounts offset must be non-negative");
|
|
1231
|
+
|
|
1232
|
+
const uint32_t* counts = (const uint32_t*)pfn_wgpuBufferGetConstMappedRange(buf, (size_t)offset_i, 3 * sizeof(uint32_t));
|
|
1233
|
+
if (!counts) NAPI_THROW(env, "bufferReadIndirectCounts: unable to read indirect data");
|
|
1234
|
+
|
|
1235
|
+
napi_value result;
|
|
1236
|
+
napi_create_object(env, &result);
|
|
1237
|
+
napi_value x;
|
|
1238
|
+
napi_value y;
|
|
1239
|
+
napi_value z;
|
|
1240
|
+
napi_create_uint32(env, counts[0], &x);
|
|
1241
|
+
napi_create_uint32(env, counts[1], &y);
|
|
1242
|
+
napi_create_uint32(env, counts[2], &z);
|
|
1243
|
+
napi_set_named_property(env, result, "x", x);
|
|
1244
|
+
napi_set_named_property(env, result, "y", y);
|
|
1245
|
+
napi_set_named_property(env, result, "z", z);
|
|
1246
|
+
return result;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
903
1249
|
/* bufferAssertMappedPrefixF32(buffer, expected, count) */
|
|
904
1250
|
static napi_value doe_buffer_assert_mapped_prefix_f32(napi_env env, napi_callback_info info) {
|
|
905
1251
|
NAPI_ASSERT_ARGC(env, info, 3);
|
|
@@ -951,10 +1297,100 @@ static napi_value doe_create_shader_module(napi_env env, napi_callback_info info
|
|
|
951
1297
|
|
|
952
1298
|
WGPUShaderModule mod = pfn_wgpuDeviceCreateShaderModule(device, &desc);
|
|
953
1299
|
free(code);
|
|
954
|
-
if (!mod)
|
|
1300
|
+
if (!mod) {
|
|
1301
|
+
char msg[DOE_ERROR_BUF_CAP];
|
|
1302
|
+
char stage[64];
|
|
1303
|
+
char kind[64];
|
|
1304
|
+
copy_library_error_message(msg, sizeof(msg));
|
|
1305
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorStage, stage, sizeof(stage));
|
|
1306
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorKind, kind, sizeof(kind));
|
|
1307
|
+
if (msg[0] != '\0') {
|
|
1308
|
+
char full_msg[DOE_ERROR_BUF_CAP];
|
|
1309
|
+
if (stage[0] != '\0' && kind[0] != '\0') {
|
|
1310
|
+
snprintf(full_msg, sizeof(full_msg), "[%s/%s] %s", stage, kind, msg);
|
|
1311
|
+
} else if (stage[0] != '\0') {
|
|
1312
|
+
snprintf(full_msg, sizeof(full_msg), "[%s] %s", stage, msg);
|
|
1313
|
+
} else {
|
|
1314
|
+
snprintf(full_msg, sizeof(full_msg), "%s", msg);
|
|
1315
|
+
}
|
|
1316
|
+
napi_throw_error(env, "DOE_SHADER_MODULE_ERROR", full_msg);
|
|
1317
|
+
} else {
|
|
1318
|
+
napi_throw_error(env, "DOE_SHADER_MODULE_ERROR", "createShaderModule failed (WGSL translation or compilation error)");
|
|
1319
|
+
}
|
|
1320
|
+
return NULL;
|
|
1321
|
+
}
|
|
955
1322
|
return wrap_ptr(env, mod);
|
|
956
1323
|
}
|
|
957
1324
|
|
|
1325
|
+
static napi_value doe_check_shader_source(napi_env env, napi_callback_info info) {
|
|
1326
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1327
|
+
CHECK_LIB_LOADED(env);
|
|
1328
|
+
napi_valuetype value_type;
|
|
1329
|
+
if (napi_typeof(env, _args[0], &value_type) != napi_ok || value_type != napi_string) {
|
|
1330
|
+
NAPI_THROW(env, "checkShaderSource requires a WGSL source string");
|
|
1331
|
+
}
|
|
1332
|
+
napi_value result;
|
|
1333
|
+
napi_create_object(env, &result);
|
|
1334
|
+
if (!pfn_doeNativeCheckShaderSource) {
|
|
1335
|
+
napi_value ok;
|
|
1336
|
+
napi_get_boolean(env, true, &ok);
|
|
1337
|
+
napi_set_named_property(env, result, "ok", ok);
|
|
1338
|
+
return result;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
size_t code_len = 0;
|
|
1342
|
+
napi_get_value_string_utf8(env, _args[0], NULL, 0, &code_len);
|
|
1343
|
+
char* code = (char*)malloc(code_len + 1);
|
|
1344
|
+
if (!code) NAPI_THROW(env, "checkShaderSource: out of memory");
|
|
1345
|
+
napi_get_value_string_utf8(env, _args[0], code, code_len + 1, &code_len);
|
|
1346
|
+
|
|
1347
|
+
const uint32_t ok_status = pfn_doeNativeCheckShaderSource(code, code_len);
|
|
1348
|
+
free(code);
|
|
1349
|
+
|
|
1350
|
+
napi_value ok;
|
|
1351
|
+
napi_get_boolean(env, ok_status != 0, &ok);
|
|
1352
|
+
napi_set_named_property(env, result, "ok", ok);
|
|
1353
|
+
if (ok_status != 0) return result;
|
|
1354
|
+
|
|
1355
|
+
char message[DOE_ERROR_BUF_CAP];
|
|
1356
|
+
char stage[64];
|
|
1357
|
+
char kind[64];
|
|
1358
|
+
copy_library_error_message(message, sizeof(message));
|
|
1359
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorStage, stage, sizeof(stage));
|
|
1360
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorKind, kind, sizeof(kind));
|
|
1361
|
+
|
|
1362
|
+
napi_value message_val;
|
|
1363
|
+
napi_create_string_utf8(env, message, NAPI_AUTO_LENGTH, &message_val);
|
|
1364
|
+
napi_set_named_property(env, result, "message", message_val);
|
|
1365
|
+
if (stage[0] != '\0') {
|
|
1366
|
+
napi_value stage_val;
|
|
1367
|
+
napi_create_string_utf8(env, stage, NAPI_AUTO_LENGTH, &stage_val);
|
|
1368
|
+
napi_set_named_property(env, result, "stage", stage_val);
|
|
1369
|
+
}
|
|
1370
|
+
if (kind[0] != '\0') {
|
|
1371
|
+
napi_value kind_val;
|
|
1372
|
+
napi_create_string_utf8(env, kind, NAPI_AUTO_LENGTH, &kind_val);
|
|
1373
|
+
napi_set_named_property(env, result, "kind", kind_val);
|
|
1374
|
+
}
|
|
1375
|
+
if (pfn_doeNativeGetLastErrorLine) {
|
|
1376
|
+
uint32_t line = pfn_doeNativeGetLastErrorLine();
|
|
1377
|
+
if (line > 0) {
|
|
1378
|
+
napi_value line_val;
|
|
1379
|
+
napi_create_uint32(env, line, &line_val);
|
|
1380
|
+
napi_set_named_property(env, result, "line", line_val);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
if (pfn_doeNativeGetLastErrorColumn) {
|
|
1384
|
+
uint32_t col = pfn_doeNativeGetLastErrorColumn();
|
|
1385
|
+
if (col > 0) {
|
|
1386
|
+
napi_value col_val;
|
|
1387
|
+
napi_create_uint32(env, col, &col_val);
|
|
1388
|
+
napi_set_named_property(env, result, "column", col_val);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
return result;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
958
1394
|
static napi_value doe_shader_module_release(napi_env env, napi_callback_info info) {
|
|
959
1395
|
NAPI_ASSERT_ARGC(env, info, 1);
|
|
960
1396
|
void* mod = unwrap_ptr(env, _args[0]);
|
|
@@ -962,6 +1398,70 @@ static napi_value doe_shader_module_release(napi_env env, napi_callback_info inf
|
|
|
962
1398
|
return NULL;
|
|
963
1399
|
}
|
|
964
1400
|
|
|
1401
|
+
static const char* doe_binding_kind_name(uint32_t kind) {
|
|
1402
|
+
switch (kind) {
|
|
1403
|
+
case 0: return "buffer";
|
|
1404
|
+
case 1: return "sampler";
|
|
1405
|
+
case 2: return "texture";
|
|
1406
|
+
case 3: return "storage_texture";
|
|
1407
|
+
default: return "unknown";
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
static const char* doe_binding_space_name(uint32_t addr_space) {
|
|
1412
|
+
switch (addr_space) {
|
|
1413
|
+
case 0: return "function";
|
|
1414
|
+
case 1: return "private";
|
|
1415
|
+
case 2: return "workgroup";
|
|
1416
|
+
case 3: return "uniform";
|
|
1417
|
+
case 4: return "storage";
|
|
1418
|
+
case 5: return "handle";
|
|
1419
|
+
default: return "unknown";
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
static const char* doe_binding_access_name(uint32_t access) {
|
|
1424
|
+
switch (access) {
|
|
1425
|
+
case 0: return "read";
|
|
1426
|
+
case 1: return "write";
|
|
1427
|
+
case 2: return "read_write";
|
|
1428
|
+
default: return "unknown";
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
static napi_value doe_shader_module_get_bindings(napi_env env, napi_callback_info info) {
|
|
1433
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1434
|
+
WGPUShaderModule shader_module = unwrap_ptr(env, _args[0]);
|
|
1435
|
+
if (!shader_module) NAPI_THROW(env, "shaderModuleGetBindings: null shader module");
|
|
1436
|
+
if (!pfn_doeNativeShaderModuleGetBindings) NAPI_THROW(env, "shaderModuleGetBindings: native binding metadata not available");
|
|
1437
|
+
|
|
1438
|
+
DoeShaderBindingInfo bindings[16];
|
|
1439
|
+
size_t count = pfn_doeNativeShaderModuleGetBindings(shader_module, bindings, 16);
|
|
1440
|
+
|
|
1441
|
+
napi_value array;
|
|
1442
|
+
napi_create_array_with_length(env, count, &array);
|
|
1443
|
+
for (size_t i = 0; i < count; i++) {
|
|
1444
|
+
napi_value entry;
|
|
1445
|
+
napi_create_object(env, &entry);
|
|
1446
|
+
|
|
1447
|
+
napi_value group, binding, kind, space, access;
|
|
1448
|
+
napi_create_uint32(env, bindings[i].group, &group);
|
|
1449
|
+
napi_create_uint32(env, bindings[i].binding, &binding);
|
|
1450
|
+
napi_create_string_utf8(env, doe_binding_kind_name(bindings[i].kind), NAPI_AUTO_LENGTH, &kind);
|
|
1451
|
+
napi_create_string_utf8(env, doe_binding_space_name(bindings[i].addr_space), NAPI_AUTO_LENGTH, &space);
|
|
1452
|
+
napi_create_string_utf8(env, doe_binding_access_name(bindings[i].access), NAPI_AUTO_LENGTH, &access);
|
|
1453
|
+
|
|
1454
|
+
napi_set_named_property(env, entry, "group", group);
|
|
1455
|
+
napi_set_named_property(env, entry, "binding", binding);
|
|
1456
|
+
napi_set_named_property(env, entry, "type", kind);
|
|
1457
|
+
napi_set_named_property(env, entry, "space", space);
|
|
1458
|
+
napi_set_named_property(env, entry, "access", access);
|
|
1459
|
+
napi_set_element(env, array, i, entry);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
return array;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
965
1465
|
/* ================================================================
|
|
966
1466
|
* Compute Pipeline
|
|
967
1467
|
* createComputePipeline(device, shaderModule, entryPoint, pipelineLayout?)
|
|
@@ -994,7 +1494,28 @@ static napi_value doe_create_compute_pipeline(napi_env env, napi_callback_info i
|
|
|
994
1494
|
|
|
995
1495
|
WGPUComputePipeline pipeline = pfn_wgpuDeviceCreateComputePipeline(device, &desc);
|
|
996
1496
|
free(ep);
|
|
997
|
-
if (!pipeline)
|
|
1497
|
+
if (!pipeline) {
|
|
1498
|
+
char msg[DOE_ERROR_BUF_CAP];
|
|
1499
|
+
char stage[64];
|
|
1500
|
+
char kind[64];
|
|
1501
|
+
copy_library_error_message(msg, sizeof(msg));
|
|
1502
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorStage, stage, sizeof(stage));
|
|
1503
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorKind, kind, sizeof(kind));
|
|
1504
|
+
if (msg[0] != '\0') {
|
|
1505
|
+
char full_msg[DOE_ERROR_BUF_CAP];
|
|
1506
|
+
if (stage[0] != '\0' && kind[0] != '\0') {
|
|
1507
|
+
snprintf(full_msg, sizeof(full_msg), "[%s/%s] %s", stage, kind, msg);
|
|
1508
|
+
} else if (stage[0] != '\0') {
|
|
1509
|
+
snprintf(full_msg, sizeof(full_msg), "[%s] %s", stage, msg);
|
|
1510
|
+
} else {
|
|
1511
|
+
snprintf(full_msg, sizeof(full_msg), "%s", msg);
|
|
1512
|
+
}
|
|
1513
|
+
napi_throw_error(env, "DOE_COMPUTE_PIPELINE_ERROR", full_msg);
|
|
1514
|
+
} else {
|
|
1515
|
+
napi_throw_error(env, "DOE_COMPUTE_PIPELINE_ERROR", "createComputePipeline failed");
|
|
1516
|
+
}
|
|
1517
|
+
return NULL;
|
|
1518
|
+
}
|
|
998
1519
|
return wrap_ptr(env, pipeline);
|
|
999
1520
|
}
|
|
1000
1521
|
|
|
@@ -1021,7 +1542,9 @@ static napi_value doe_compute_pipeline_get_bind_group_layout(napi_env env, napi_
|
|
|
1021
1542
|
/* ================================================================
|
|
1022
1543
|
* Bind Group Layout
|
|
1023
1544
|
* createBindGroupLayout(device, entries[])
|
|
1024
|
-
* Each entry: { binding, visibility, buffer?: { type },
|
|
1545
|
+
* Each entry: { binding, visibility, buffer?: { type }, sampler?: { type },
|
|
1546
|
+
* texture?: { sampleType, viewDimension, multisampled },
|
|
1547
|
+
* storageTexture?: { access, format, viewDimension } }
|
|
1025
1548
|
* ================================================================ */
|
|
1026
1549
|
|
|
1027
1550
|
static uint32_t buffer_binding_type_from_string(napi_env env, napi_value val) {
|
|
@@ -1037,6 +1560,68 @@ static uint32_t buffer_binding_type_from_string(napi_env env, napi_value val) {
|
|
|
1037
1560
|
return 0x00000001;
|
|
1038
1561
|
}
|
|
1039
1562
|
|
|
1563
|
+
static uint32_t sampler_binding_type_from_string(napi_env env, napi_value val) {
|
|
1564
|
+
napi_valuetype vt;
|
|
1565
|
+
napi_typeof(env, val, &vt);
|
|
1566
|
+
if (vt != napi_string) return 0x00000001; /* Undefined */
|
|
1567
|
+
char buf[32] = {0};
|
|
1568
|
+
size_t len = 0;
|
|
1569
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1570
|
+
if (strcmp(buf, "filtering") == 0) return 0x00000002;
|
|
1571
|
+
if (strcmp(buf, "non-filtering") == 0 || strcmp(buf, "non_filtering") == 0) return 0x00000003;
|
|
1572
|
+
if (strcmp(buf, "comparison") == 0) return 0x00000004;
|
|
1573
|
+
return 0x00000001;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
static uint32_t texture_sample_type_from_string(napi_env env, napi_value val) {
|
|
1577
|
+
napi_valuetype vt;
|
|
1578
|
+
napi_typeof(env, val, &vt);
|
|
1579
|
+
if (vt != napi_string) return 0x00000001; /* Undefined */
|
|
1580
|
+
char buf[64] = {0};
|
|
1581
|
+
size_t len = 0;
|
|
1582
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1583
|
+
if (strcmp(buf, "float") == 0) return 0x00000002;
|
|
1584
|
+
if (strcmp(buf, "unfilterable-float") == 0 || strcmp(buf, "unfilterable_float") == 0) return 0x00000003;
|
|
1585
|
+
if (strcmp(buf, "depth") == 0) return 0x00000004;
|
|
1586
|
+
if (strcmp(buf, "sint") == 0) return 0x00000005;
|
|
1587
|
+
if (strcmp(buf, "uint") == 0) return 0x00000006;
|
|
1588
|
+
return 0x00000001;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
static uint32_t texture_view_dimension_from_string(napi_env env, napi_value val) {
|
|
1592
|
+
napi_valuetype vt;
|
|
1593
|
+
napi_typeof(env, val, &vt);
|
|
1594
|
+
if (vt != napi_string) return 0x00000000; /* Undefined */
|
|
1595
|
+
char buf[32] = {0};
|
|
1596
|
+
size_t len = 0;
|
|
1597
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1598
|
+
if (strcmp(buf, "1d") == 0) return 0x00000001;
|
|
1599
|
+
if (strcmp(buf, "2d") == 0) return 0x00000002;
|
|
1600
|
+
if (strcmp(buf, "2d-array") == 0 || strcmp(buf, "2d_array") == 0) return 0x00000003;
|
|
1601
|
+
if (strcmp(buf, "cube") == 0) return 0x00000004;
|
|
1602
|
+
if (strcmp(buf, "cube-array") == 0 || strcmp(buf, "cube_array") == 0) return 0x00000005;
|
|
1603
|
+
if (strcmp(buf, "3d") == 0) return 0x00000006;
|
|
1604
|
+
return 0x00000000;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
static uint32_t storage_texture_access_from_string(napi_env env, napi_value val) {
|
|
1608
|
+
napi_valuetype vt;
|
|
1609
|
+
napi_typeof(env, val, &vt);
|
|
1610
|
+
if (vt != napi_string) return 0x00000001; /* Undefined */
|
|
1611
|
+
char buf[32] = {0};
|
|
1612
|
+
size_t len = 0;
|
|
1613
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1614
|
+
if (strcmp(buf, "write-only") == 0 || strcmp(buf, "write_only") == 0) return 0x00000002;
|
|
1615
|
+
if (strcmp(buf, "read-only") == 0 || strcmp(buf, "read_only") == 0) return 0x00000003;
|
|
1616
|
+
if (strcmp(buf, "read-write") == 0 || strcmp(buf, "read_write") == 0) return 0x00000004;
|
|
1617
|
+
return 0x00000001;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
static uint32_t texture_format_from_string(napi_env env, napi_value val);
|
|
1621
|
+
static uint32_t primitive_topology_from_string(napi_env env, napi_value val);
|
|
1622
|
+
static uint32_t front_face_from_string(napi_env env, napi_value val);
|
|
1623
|
+
static uint32_t cull_mode_from_string(napi_env env, napi_value val);
|
|
1624
|
+
|
|
1040
1625
|
static napi_value doe_create_bind_group_layout(napi_env env, napi_callback_info info) {
|
|
1041
1626
|
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1042
1627
|
CHECK_LIB_LOADED(env);
|
|
@@ -1066,11 +1651,27 @@ static napi_value doe_create_bind_group_layout(napi_env env, napi_callback_info
|
|
|
1066
1651
|
entries[i].buffer.minBindingSize = (uint64_t)get_int64_prop(env, buf_obj, "minBindingSize");
|
|
1067
1652
|
}
|
|
1068
1653
|
|
|
1654
|
+
if (has_prop(env, elem, "sampler") && prop_type(env, elem, "sampler") == napi_object) {
|
|
1655
|
+
napi_value sampler_obj = get_prop(env, elem, "sampler");
|
|
1656
|
+
entries[i].sampler.type = sampler_binding_type_from_string(
|
|
1657
|
+
env, get_prop(env, sampler_obj, "type"));
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
if (has_prop(env, elem, "texture") && prop_type(env, elem, "texture") == napi_object) {
|
|
1661
|
+
napi_value tex_obj = get_prop(env, elem, "texture");
|
|
1662
|
+
entries[i].texture.sampleType = texture_sample_type_from_string(
|
|
1663
|
+
env, get_prop(env, tex_obj, "sampleType"));
|
|
1664
|
+
entries[i].texture.viewDimension = texture_view_dimension_from_string(
|
|
1665
|
+
env, get_prop(env, tex_obj, "viewDimension"));
|
|
1666
|
+
if (has_prop(env, tex_obj, "multisampled"))
|
|
1667
|
+
entries[i].texture.multisampled = get_bool_prop(env, tex_obj, "multisampled") ? 1 : 0;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1069
1670
|
if (has_prop(env, elem, "storageTexture") && prop_type(env, elem, "storageTexture") == napi_object) {
|
|
1070
1671
|
napi_value st_obj = get_prop(env, elem, "storageTexture");
|
|
1071
|
-
entries[i].storageTexture.access =
|
|
1072
|
-
entries[i].storageTexture.format =
|
|
1073
|
-
entries[i].storageTexture.viewDimension =
|
|
1672
|
+
entries[i].storageTexture.access = storage_texture_access_from_string(env, get_prop(env, st_obj, "access"));
|
|
1673
|
+
entries[i].storageTexture.format = texture_format_from_string(env, get_prop(env, st_obj, "format"));
|
|
1674
|
+
entries[i].storageTexture.viewDimension = texture_view_dimension_from_string(env, get_prop(env, st_obj, "viewDimension"));
|
|
1074
1675
|
}
|
|
1075
1676
|
}
|
|
1076
1677
|
|
|
@@ -1097,7 +1698,7 @@ static napi_value doe_bind_group_layout_release(napi_env env, napi_callback_info
|
|
|
1097
1698
|
/* ================================================================
|
|
1098
1699
|
* Bind Group
|
|
1099
1700
|
* createBindGroup(device, layout, entries[])
|
|
1100
|
-
* Each entry: { binding, buffer
|
|
1701
|
+
* Each entry: { binding, buffer?, offset?, size?, sampler?, textureView? }
|
|
1101
1702
|
* ================================================================ */
|
|
1102
1703
|
|
|
1103
1704
|
static napi_value doe_create_bind_group(napi_env env, napi_callback_info info) {
|
|
@@ -1122,6 +1723,12 @@ static napi_value doe_create_bind_group(napi_env env, napi_callback_info info) {
|
|
|
1122
1723
|
if (has_prop(env, elem, "buffer") && prop_type(env, elem, "buffer") == napi_external)
|
|
1123
1724
|
entries[i].buffer = unwrap_ptr(env, get_prop(env, elem, "buffer"));
|
|
1124
1725
|
|
|
1726
|
+
if (has_prop(env, elem, "sampler") && prop_type(env, elem, "sampler") == napi_external)
|
|
1727
|
+
entries[i].sampler = unwrap_ptr(env, get_prop(env, elem, "sampler"));
|
|
1728
|
+
|
|
1729
|
+
if (has_prop(env, elem, "textureView") && prop_type(env, elem, "textureView") == napi_external)
|
|
1730
|
+
entries[i].textureView = unwrap_ptr(env, get_prop(env, elem, "textureView"));
|
|
1731
|
+
|
|
1125
1732
|
if (has_prop(env, elem, "offset"))
|
|
1126
1733
|
entries[i].offset = (uint64_t)get_int64_prop(env, elem, "offset");
|
|
1127
1734
|
|
|
@@ -1235,6 +1842,56 @@ static napi_value doe_command_encoder_copy_buffer_to_buffer(napi_env env, napi_c
|
|
|
1235
1842
|
return NULL;
|
|
1236
1843
|
}
|
|
1237
1844
|
|
|
1845
|
+
static napi_value doe_command_encoder_copy_texture_to_buffer(napi_env env, napi_callback_info info) {
|
|
1846
|
+
NAPI_ASSERT_ARGC(env, info, 14);
|
|
1847
|
+
CHECK_LIB_LOADED(env);
|
|
1848
|
+
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1849
|
+
WGPUTexture src_texture = unwrap_ptr(env, _args[1]);
|
|
1850
|
+
if (!enc || !src_texture) NAPI_THROW(env, "commandEncoderCopyTextureToBuffer requires encoder and texture");
|
|
1851
|
+
|
|
1852
|
+
WGPUTexelCopyTextureInfo src;
|
|
1853
|
+
memset(&src, 0, sizeof(src));
|
|
1854
|
+
src.texture = src_texture;
|
|
1855
|
+
napi_get_value_uint32(env, _args[2], &src.mipLevel);
|
|
1856
|
+
napi_get_value_uint32(env, _args[3], &src.origin.x);
|
|
1857
|
+
napi_get_value_uint32(env, _args[4], &src.origin.y);
|
|
1858
|
+
napi_get_value_uint32(env, _args[5], &src.origin.z);
|
|
1859
|
+
napi_get_value_uint32(env, _args[6], &src.aspect);
|
|
1860
|
+
|
|
1861
|
+
WGPUTexelCopyBufferInfo dst;
|
|
1862
|
+
memset(&dst, 0, sizeof(dst));
|
|
1863
|
+
dst.buffer = unwrap_ptr(env, _args[7]);
|
|
1864
|
+
if (!dst.buffer) NAPI_THROW(env, "commandEncoderCopyTextureToBuffer requires destination buffer");
|
|
1865
|
+
int64_t dst_offset = 0;
|
|
1866
|
+
napi_get_value_int64(env, _args[8], &dst_offset);
|
|
1867
|
+
dst.layout.offset = (uint64_t)dst_offset;
|
|
1868
|
+
napi_get_value_uint32(env, _args[9], &dst.layout.bytesPerRow);
|
|
1869
|
+
napi_get_value_uint32(env, _args[10], &dst.layout.rowsPerImage);
|
|
1870
|
+
|
|
1871
|
+
WGPUExtent3D size;
|
|
1872
|
+
napi_get_value_uint32(env, _args[11], &size.width);
|
|
1873
|
+
napi_get_value_uint32(env, _args[12], &size.height);
|
|
1874
|
+
napi_get_value_uint32(env, _args[13], &size.depthOrArrayLayers);
|
|
1875
|
+
|
|
1876
|
+
if (pfn_doeNativeCommandEncoderCopyTextureToBuffer) {
|
|
1877
|
+
pfn_doeNativeCommandEncoderCopyTextureToBuffer(
|
|
1878
|
+
enc,
|
|
1879
|
+
src.texture,
|
|
1880
|
+
src.mipLevel,
|
|
1881
|
+
dst.buffer,
|
|
1882
|
+
dst.layout.offset,
|
|
1883
|
+
dst.layout.bytesPerRow,
|
|
1884
|
+
dst.layout.rowsPerImage,
|
|
1885
|
+
size.width,
|
|
1886
|
+
size.height,
|
|
1887
|
+
size.depthOrArrayLayers
|
|
1888
|
+
);
|
|
1889
|
+
} else {
|
|
1890
|
+
pfn_wgpuCommandEncoderCopyTextureToBuffer(enc, &src, &dst, &size);
|
|
1891
|
+
}
|
|
1892
|
+
return NULL;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1238
1895
|
static napi_value doe_command_encoder_finish(napi_env env, napi_callback_info info) {
|
|
1239
1896
|
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1240
1897
|
CHECK_LIB_LOADED(env);
|
|
@@ -1360,6 +2017,7 @@ static napi_value doe_queue_write_buffer(napi_env env, napi_callback_info info)
|
|
|
1360
2017
|
CHECK_LIB_LOADED(env);
|
|
1361
2018
|
WGPUQueue queue = unwrap_ptr(env, _args[0]);
|
|
1362
2019
|
WGPUBuffer buf = unwrap_ptr(env, _args[1]);
|
|
2020
|
+
if (!queue || !buf) NAPI_THROW(env, "queueWriteBuffer requires queue and buffer");
|
|
1363
2021
|
int64_t offset; napi_get_value_int64(env, _args[2], &offset);
|
|
1364
2022
|
|
|
1365
2023
|
void* data = NULL;
|
|
@@ -1415,9 +2073,12 @@ static napi_value doe_queue_flush(napi_env env, napi_callback_info info) {
|
|
|
1415
2073
|
pfn_doeNativeQueueFlush(queue);
|
|
1416
2074
|
return NULL;
|
|
1417
2075
|
}
|
|
1418
|
-
if (!inst)
|
|
2076
|
+
if (!inst) {
|
|
2077
|
+
napi_throw_error(env, "DOE_QUEUE_UNAVAILABLE", "queueFlush requires instance when doeNativeQueueFlush is unavailable");
|
|
2078
|
+
return NULL;
|
|
2079
|
+
}
|
|
1419
2080
|
|
|
1420
|
-
QueueWorkDoneResult result = {0
|
|
2081
|
+
QueueWorkDoneResult result = {0};
|
|
1421
2082
|
WGPUQueueWorkDoneCallbackInfo cb_info = {
|
|
1422
2083
|
.nextInChain = NULL,
|
|
1423
2084
|
.mode = WGPU_CALLBACK_MODE_WAIT_ANY_ONLY,
|
|
@@ -1441,19 +2102,20 @@ static napi_value doe_queue_flush(napi_env env, napi_callback_info info) {
|
|
|
1441
2102
|
}
|
|
1442
2103
|
} else if (wait_status == WGPU_WAIT_STATUS_TIMED_OUT) {
|
|
1443
2104
|
pfn_wgpuInstanceProcessEvents(inst);
|
|
1444
|
-
if (monotonic_now_ns() - start_ns >=
|
|
1445
|
-
|
|
2105
|
+
if (monotonic_now_ns() - start_ns >= current_timeout_ns()) {
|
|
2106
|
+
napi_throw_error(env, "DOE_QUEUE_TIMEOUT", "queueFlush: queue wait timed out");
|
|
2107
|
+
return NULL;
|
|
1446
2108
|
}
|
|
1447
2109
|
wait_slice();
|
|
1448
2110
|
} else if (wait_status == WGPU_WAIT_STATUS_ERROR) {
|
|
1449
|
-
|
|
2111
|
+
napi_throw_error(env, "DOE_QUEUE_UNAVAILABLE", "queueFlush: wgpuInstanceWaitAny failed");
|
|
2112
|
+
return NULL;
|
|
1450
2113
|
} else {
|
|
1451
2114
|
NAPI_THROW(env, "queueFlush: unsupported wait status");
|
|
1452
2115
|
}
|
|
1453
2116
|
}
|
|
1454
|
-
if (result.status != WGPU_QUEUE_WORK_DONE_STATUS_SUCCESS)
|
|
1455
|
-
|
|
1456
|
-
}
|
|
2117
|
+
if (result.status != WGPU_QUEUE_WORK_DONE_STATUS_SUCCESS)
|
|
2118
|
+
return throw_status_error(env, "DOE_QUEUE_FLUSH_ERROR", "queueFlush: queue work did not complete", result.status, result.message);
|
|
1457
2119
|
return NULL;
|
|
1458
2120
|
}
|
|
1459
2121
|
|
|
@@ -1677,7 +2339,7 @@ static napi_value doe_flush_and_map_sync(napi_env env, napi_callback_info info)
|
|
|
1677
2339
|
}
|
|
1678
2340
|
|
|
1679
2341
|
/* Map the buffer synchronously via processEvents polling. */
|
|
1680
|
-
BufferMapResult result = {0
|
|
2342
|
+
BufferMapResult result = {0};
|
|
1681
2343
|
WGPUBufferMapCallbackInfo cb_info = {
|
|
1682
2344
|
.nextInChain = NULL,
|
|
1683
2345
|
.mode = WGPU_CALLBACK_MODE_ALLOW_PROCESS_EVENTS,
|
|
@@ -1688,9 +2350,10 @@ static napi_value doe_flush_and_map_sync(napi_env env, napi_callback_info info)
|
|
|
1688
2350
|
WGPUFuture future = pfn_wgpuBufferMapAsync2(buf, (uint64_t)mode,
|
|
1689
2351
|
(size_t)offset_i, (size_t)size_i, cb_info);
|
|
1690
2352
|
if (future.id == 0) NAPI_THROW(env, "flushAndMapSync: bufferMapAsync future unavailable");
|
|
1691
|
-
if (!process_events_until(inst, &result.done,
|
|
1692
|
-
result.status
|
|
1693
|
-
|
|
2353
|
+
if (!process_events_until(inst, &result.done, current_timeout_ns()))
|
|
2354
|
+
return throw_status_error(env, "DOE_BUFFER_MAP_TIMEOUT", "flushAndMapSync: bufferMapAsync timed out", result.status, result.message);
|
|
2355
|
+
if (result.status != WGPU_MAP_ASYNC_STATUS_SUCCESS)
|
|
2356
|
+
return throw_status_error(env, "DOE_BUFFER_MAP_ERROR", "flushAndMapSync: bufferMapAsync failed", result.status, result.message);
|
|
1694
2357
|
|
|
1695
2358
|
napi_value ok;
|
|
1696
2359
|
napi_get_boolean(env, true, &ok);
|
|
@@ -1722,14 +2385,246 @@ static uint32_t texture_format_from_string(napi_env env, napi_value val) {
|
|
|
1722
2385
|
char buf[32] = {0};
|
|
1723
2386
|
size_t len = 0;
|
|
1724
2387
|
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
1725
|
-
if (strcmp(buf, "
|
|
1726
|
-
if (strcmp(buf, "
|
|
1727
|
-
if (strcmp(buf, "
|
|
1728
|
-
if (strcmp(buf, "
|
|
1729
|
-
if (strcmp(buf, "
|
|
2388
|
+
if (strcmp(buf, "r8unorm") == 0) return 0x00000001;
|
|
2389
|
+
if (strcmp(buf, "r8snorm") == 0) return 0x00000002;
|
|
2390
|
+
if (strcmp(buf, "r8uint") == 0) return 0x00000003;
|
|
2391
|
+
if (strcmp(buf, "r8sint") == 0) return 0x00000004;
|
|
2392
|
+
if (strcmp(buf, "r16uint") == 0) return 0x00000007;
|
|
2393
|
+
if (strcmp(buf, "r16sint") == 0) return 0x00000008;
|
|
2394
|
+
if (strcmp(buf, "r16float") == 0) return 0x00000009;
|
|
2395
|
+
if (strcmp(buf, "rg8unorm") == 0) return 0x0000000A;
|
|
2396
|
+
if (strcmp(buf, "rg8snorm") == 0) return 0x0000000B;
|
|
2397
|
+
if (strcmp(buf, "rg8uint") == 0) return 0x0000000C;
|
|
2398
|
+
if (strcmp(buf, "rg8sint") == 0) return 0x0000000D;
|
|
2399
|
+
if (strcmp(buf, "r32float") == 0) return 0x0000000E;
|
|
2400
|
+
if (strcmp(buf, "r32uint") == 0) return 0x0000000F;
|
|
2401
|
+
if (strcmp(buf, "r32sint") == 0) return 0x00000010;
|
|
2402
|
+
if (strcmp(buf, "rg16uint") == 0) return 0x00000013;
|
|
2403
|
+
if (strcmp(buf, "rg16sint") == 0) return 0x00000014;
|
|
2404
|
+
if (strcmp(buf, "rg16float") == 0) return 0x00000015;
|
|
2405
|
+
if (strcmp(buf, "rgba8unorm") == 0) return 0x00000016;
|
|
2406
|
+
if (strcmp(buf, "rgba8unorm-srgb") == 0) return 0x00000017;
|
|
2407
|
+
if (strcmp(buf, "rgba8snorm") == 0) return 0x00000018;
|
|
2408
|
+
if (strcmp(buf, "rgba8uint") == 0) return 0x00000019;
|
|
2409
|
+
if (strcmp(buf, "rgba8sint") == 0) return 0x0000001A;
|
|
2410
|
+
if (strcmp(buf, "bgra8unorm") == 0) return 0x0000001B;
|
|
2411
|
+
if (strcmp(buf, "bgra8unorm-srgb") == 0) return 0x0000001C;
|
|
2412
|
+
if (strcmp(buf, "rgb10a2uint") == 0) return 0x0000001D;
|
|
2413
|
+
if (strcmp(buf, "rgb10a2unorm") == 0) return 0x0000001E;
|
|
2414
|
+
if (strcmp(buf, "rg11b10ufloat") == 0) return 0x0000001F;
|
|
2415
|
+
if (strcmp(buf, "rgb9e5ufloat") == 0) return 0x00000020;
|
|
2416
|
+
if (strcmp(buf, "rg32float") == 0) return 0x00000021;
|
|
2417
|
+
if (strcmp(buf, "rg32uint") == 0) return 0x00000022;
|
|
2418
|
+
if (strcmp(buf, "rg32sint") == 0) return 0x00000023;
|
|
2419
|
+
if (strcmp(buf, "rgba16uint") == 0) return 0x00000024;
|
|
2420
|
+
if (strcmp(buf, "rgba16sint") == 0) return 0x00000025;
|
|
2421
|
+
if (strcmp(buf, "rgba16float") == 0) return 0x00000026;
|
|
2422
|
+
if (strcmp(buf, "rgba32float") == 0) return 0x00000027;
|
|
2423
|
+
if (strcmp(buf, "rgba32uint") == 0) return 0x00000028;
|
|
2424
|
+
if (strcmp(buf, "rgba32sint") == 0) return 0x00000029;
|
|
2425
|
+
if (strcmp(buf, "stencil8") == 0) return 0x0000002C;
|
|
2426
|
+
if (strcmp(buf, "depth16unorm") == 0) return 0x0000002D;
|
|
2427
|
+
if (strcmp(buf, "depth24plus") == 0) return 0x0000002E;
|
|
2428
|
+
if (strcmp(buf, "depth24plus-stencil8") == 0) return 0x0000002F;
|
|
2429
|
+
if (strcmp(buf, "depth32float") == 0) return 0x00000030;
|
|
2430
|
+
if (strcmp(buf, "depth32float-stencil8") == 0) return 0x00000031;
|
|
2431
|
+
/* BC compressed formats */
|
|
2432
|
+
if (strcmp(buf, "bc1-rgba-unorm") == 0) return 0x00000032;
|
|
2433
|
+
if (strcmp(buf, "bc1-rgba-unorm-srgb") == 0) return 0x00000033;
|
|
2434
|
+
if (strcmp(buf, "bc2-rgba-unorm") == 0) return 0x00000034;
|
|
2435
|
+
if (strcmp(buf, "bc2-rgba-unorm-srgb") == 0) return 0x00000035;
|
|
2436
|
+
if (strcmp(buf, "bc3-rgba-unorm") == 0) return 0x00000036;
|
|
2437
|
+
if (strcmp(buf, "bc3-rgba-unorm-srgb") == 0) return 0x00000037;
|
|
2438
|
+
if (strcmp(buf, "bc4-r-unorm") == 0) return 0x00000038;
|
|
2439
|
+
if (strcmp(buf, "bc4-r-snorm") == 0) return 0x00000039;
|
|
2440
|
+
if (strcmp(buf, "bc5-rg-unorm") == 0) return 0x0000003A;
|
|
2441
|
+
if (strcmp(buf, "bc5-rg-snorm") == 0) return 0x0000003B;
|
|
2442
|
+
if (strcmp(buf, "bc6h-rgb-ufloat") == 0) return 0x0000003C;
|
|
2443
|
+
if (strcmp(buf, "bc6h-rgb-float") == 0) return 0x0000003D;
|
|
2444
|
+
if (strcmp(buf, "bc7-rgba-unorm") == 0) return 0x0000003E;
|
|
2445
|
+
if (strcmp(buf, "bc7-rgba-unorm-srgb") == 0) return 0x0000003F;
|
|
2446
|
+
/* ETC2/EAC compressed formats */
|
|
2447
|
+
if (strcmp(buf, "etc2-rgb8unorm") == 0) return 0x00000040;
|
|
2448
|
+
if (strcmp(buf, "etc2-rgb8unorm-srgb") == 0) return 0x00000041;
|
|
2449
|
+
if (strcmp(buf, "etc2-rgb8a1unorm") == 0) return 0x00000042;
|
|
2450
|
+
if (strcmp(buf, "etc2-rgb8a1unorm-srgb") == 0) return 0x00000043;
|
|
2451
|
+
if (strcmp(buf, "etc2-rgba8unorm") == 0) return 0x00000044;
|
|
2452
|
+
if (strcmp(buf, "etc2-rgba8unorm-srgb") == 0) return 0x00000045;
|
|
2453
|
+
if (strcmp(buf, "eac-r11unorm") == 0) return 0x00000046;
|
|
2454
|
+
if (strcmp(buf, "eac-r11snorm") == 0) return 0x00000047;
|
|
2455
|
+
if (strcmp(buf, "eac-rg11unorm") == 0) return 0x00000048;
|
|
2456
|
+
if (strcmp(buf, "eac-rg11snorm") == 0) return 0x00000049;
|
|
2457
|
+
/* ASTC compressed formats */
|
|
2458
|
+
if (strcmp(buf, "astc-4x4-unorm") == 0) return 0x0000004A;
|
|
2459
|
+
if (strcmp(buf, "astc-4x4-unorm-srgb") == 0) return 0x0000004B;
|
|
2460
|
+
if (strcmp(buf, "astc-5x4-unorm") == 0) return 0x0000004C;
|
|
2461
|
+
if (strcmp(buf, "astc-5x4-unorm-srgb") == 0) return 0x0000004D;
|
|
2462
|
+
if (strcmp(buf, "astc-5x5-unorm") == 0) return 0x0000004E;
|
|
2463
|
+
if (strcmp(buf, "astc-5x5-unorm-srgb") == 0) return 0x0000004F;
|
|
2464
|
+
if (strcmp(buf, "astc-6x5-unorm") == 0) return 0x00000050;
|
|
2465
|
+
if (strcmp(buf, "astc-6x5-unorm-srgb") == 0) return 0x00000051;
|
|
2466
|
+
if (strcmp(buf, "astc-6x6-unorm") == 0) return 0x00000052;
|
|
2467
|
+
if (strcmp(buf, "astc-6x6-unorm-srgb") == 0) return 0x00000053;
|
|
2468
|
+
if (strcmp(buf, "astc-8x5-unorm") == 0) return 0x00000054;
|
|
2469
|
+
if (strcmp(buf, "astc-8x5-unorm-srgb") == 0) return 0x00000055;
|
|
2470
|
+
if (strcmp(buf, "astc-8x6-unorm") == 0) return 0x00000056;
|
|
2471
|
+
if (strcmp(buf, "astc-8x6-unorm-srgb") == 0) return 0x00000057;
|
|
2472
|
+
if (strcmp(buf, "astc-8x8-unorm") == 0) return 0x00000058;
|
|
2473
|
+
if (strcmp(buf, "astc-8x8-unorm-srgb") == 0) return 0x00000059;
|
|
2474
|
+
if (strcmp(buf, "astc-10x5-unorm") == 0) return 0x0000005A;
|
|
2475
|
+
if (strcmp(buf, "astc-10x5-unorm-srgb") == 0) return 0x0000005B;
|
|
2476
|
+
if (strcmp(buf, "astc-10x6-unorm") == 0) return 0x0000005C;
|
|
2477
|
+
if (strcmp(buf, "astc-10x6-unorm-srgb") == 0) return 0x0000005D;
|
|
2478
|
+
if (strcmp(buf, "astc-10x8-unorm") == 0) return 0x0000005E;
|
|
2479
|
+
if (strcmp(buf, "astc-10x8-unorm-srgb") == 0) return 0x0000005F;
|
|
2480
|
+
if (strcmp(buf, "astc-10x10-unorm") == 0) return 0x00000060;
|
|
2481
|
+
if (strcmp(buf, "astc-10x10-unorm-srgb") == 0) return 0x00000061;
|
|
2482
|
+
if (strcmp(buf, "astc-12x10-unorm") == 0) return 0x00000062;
|
|
2483
|
+
if (strcmp(buf, "astc-12x10-unorm-srgb") == 0) return 0x00000063;
|
|
2484
|
+
if (strcmp(buf, "astc-12x12-unorm") == 0) return 0x00000064;
|
|
2485
|
+
if (strcmp(buf, "astc-12x12-unorm-srgb") == 0) return 0x00000065;
|
|
1730
2486
|
return 0x00000016;
|
|
1731
2487
|
}
|
|
1732
2488
|
|
|
2489
|
+
static uint32_t primitive_topology_from_string(napi_env env, napi_value val) {
|
|
2490
|
+
napi_valuetype vt;
|
|
2491
|
+
napi_typeof(env, val, &vt);
|
|
2492
|
+
if (vt == napi_number) {
|
|
2493
|
+
uint32_t out = 0;
|
|
2494
|
+
napi_get_value_uint32(env, val, &out);
|
|
2495
|
+
return out;
|
|
2496
|
+
}
|
|
2497
|
+
char buf[32] = {0};
|
|
2498
|
+
size_t len = 0;
|
|
2499
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2500
|
+
if (strcmp(buf, "point-list") == 0) return 0x00000001;
|
|
2501
|
+
if (strcmp(buf, "line-list") == 0) return 0x00000002;
|
|
2502
|
+
if (strcmp(buf, "line-strip") == 0) return 0x00000003;
|
|
2503
|
+
if (strcmp(buf, "triangle-list") == 0) return 0x00000004;
|
|
2504
|
+
if (strcmp(buf, "triangle-strip") == 0) return 0x00000005;
|
|
2505
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported primitive topology");
|
|
2506
|
+
return 0;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
static uint32_t front_face_from_string(napi_env env, napi_value val) {
|
|
2510
|
+
napi_valuetype vt;
|
|
2511
|
+
napi_typeof(env, val, &vt);
|
|
2512
|
+
if (vt == napi_number) {
|
|
2513
|
+
uint32_t out = 0;
|
|
2514
|
+
napi_get_value_uint32(env, val, &out);
|
|
2515
|
+
return out;
|
|
2516
|
+
}
|
|
2517
|
+
char buf[16] = {0};
|
|
2518
|
+
size_t len = 0;
|
|
2519
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2520
|
+
if (strcmp(buf, "ccw") == 0) return 0x00000001;
|
|
2521
|
+
if (strcmp(buf, "cw") == 0) return 0x00000002;
|
|
2522
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported frontFace");
|
|
2523
|
+
return 0;
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
static uint32_t cull_mode_from_string(napi_env env, napi_value val) {
|
|
2527
|
+
napi_valuetype vt;
|
|
2528
|
+
napi_typeof(env, val, &vt);
|
|
2529
|
+
if (vt == napi_number) {
|
|
2530
|
+
uint32_t out = 0;
|
|
2531
|
+
napi_get_value_uint32(env, val, &out);
|
|
2532
|
+
return out;
|
|
2533
|
+
}
|
|
2534
|
+
char buf[16] = {0};
|
|
2535
|
+
size_t len = 0;
|
|
2536
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2537
|
+
if (strcmp(buf, "none") == 0) return 0x00000001;
|
|
2538
|
+
if (strcmp(buf, "front") == 0) return 0x00000002;
|
|
2539
|
+
if (strcmp(buf, "back") == 0) return 0x00000003;
|
|
2540
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported cullMode");
|
|
2541
|
+
return 0;
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
static uint32_t compare_func_from_value(napi_env env, napi_value val) {
|
|
2545
|
+
napi_valuetype vt;
|
|
2546
|
+
napi_typeof(env, val, &vt);
|
|
2547
|
+
if (vt == napi_number) {
|
|
2548
|
+
uint32_t out = 0;
|
|
2549
|
+
napi_get_value_uint32(env, val, &out);
|
|
2550
|
+
return out;
|
|
2551
|
+
}
|
|
2552
|
+
char buf[24] = {0};
|
|
2553
|
+
size_t len = 0;
|
|
2554
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2555
|
+
if (strcmp(buf, "never") == 0) return 0x00000001;
|
|
2556
|
+
if (strcmp(buf, "less") == 0) return 0x00000002;
|
|
2557
|
+
if (strcmp(buf, "equal") == 0) return 0x00000003;
|
|
2558
|
+
if (strcmp(buf, "less-equal") == 0) return 0x00000004;
|
|
2559
|
+
if (strcmp(buf, "greater") == 0) return 0x00000005;
|
|
2560
|
+
if (strcmp(buf, "not-equal") == 0) return 0x00000006;
|
|
2561
|
+
if (strcmp(buf, "greater-equal") == 0) return 0x00000007;
|
|
2562
|
+
if (strcmp(buf, "always") == 0) return 0x00000008;
|
|
2563
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported compare function");
|
|
2564
|
+
return 0;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
static uint32_t vertex_step_mode_from_value(napi_env env, napi_value val) {
|
|
2568
|
+
napi_valuetype vt;
|
|
2569
|
+
napi_typeof(env, val, &vt);
|
|
2570
|
+
if (vt == napi_number) {
|
|
2571
|
+
uint32_t out = 0;
|
|
2572
|
+
napi_get_value_uint32(env, val, &out);
|
|
2573
|
+
return out;
|
|
2574
|
+
}
|
|
2575
|
+
char buf[24] = {0};
|
|
2576
|
+
size_t len = 0;
|
|
2577
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2578
|
+
if (strcmp(buf, "vertex") == 0) return 0x00000001;
|
|
2579
|
+
if (strcmp(buf, "instance") == 0) return 0x00000002;
|
|
2580
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported vertex stepMode");
|
|
2581
|
+
return 0;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
static uint32_t vertex_format_from_value(napi_env env, napi_value val) {
|
|
2585
|
+
napi_valuetype vt;
|
|
2586
|
+
napi_typeof(env, val, &vt);
|
|
2587
|
+
if (vt == napi_number) {
|
|
2588
|
+
uint32_t out = 0;
|
|
2589
|
+
napi_get_value_uint32(env, val, &out);
|
|
2590
|
+
return out;
|
|
2591
|
+
}
|
|
2592
|
+
char buf[32] = {0};
|
|
2593
|
+
size_t len = 0;
|
|
2594
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2595
|
+
if (strcmp(buf, "float32") == 0) return 0x00000019;
|
|
2596
|
+
if (strcmp(buf, "float32x2") == 0) return 0x0000001A;
|
|
2597
|
+
if (strcmp(buf, "float32x3") == 0) return 0x0000001B;
|
|
2598
|
+
if (strcmp(buf, "float32x4") == 0) return 0x0000001C;
|
|
2599
|
+
if (strcmp(buf, "uint32") == 0) return 0x00000021;
|
|
2600
|
+
if (strcmp(buf, "uint32x2") == 0) return 0x00000022;
|
|
2601
|
+
if (strcmp(buf, "uint32x3") == 0) return 0x00000023;
|
|
2602
|
+
if (strcmp(buf, "uint32x4") == 0) return 0x00000024;
|
|
2603
|
+
if (strcmp(buf, "sint32") == 0) return 0x00000025;
|
|
2604
|
+
if (strcmp(buf, "sint32x2") == 0) return 0x00000026;
|
|
2605
|
+
if (strcmp(buf, "sint32x3") == 0) return 0x00000027;
|
|
2606
|
+
if (strcmp(buf, "sint32x4") == 0) return 0x00000028;
|
|
2607
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported vertex format");
|
|
2608
|
+
return 0;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
static uint32_t index_format_from_value(napi_env env, napi_value val) {
|
|
2612
|
+
napi_valuetype vt;
|
|
2613
|
+
napi_typeof(env, val, &vt);
|
|
2614
|
+
if (vt == napi_number) {
|
|
2615
|
+
uint32_t out = 0;
|
|
2616
|
+
napi_get_value_uint32(env, val, &out);
|
|
2617
|
+
return out;
|
|
2618
|
+
}
|
|
2619
|
+
char buf[16] = {0};
|
|
2620
|
+
size_t len = 0;
|
|
2621
|
+
napi_get_value_string_utf8(env, val, buf, sizeof(buf), &len);
|
|
2622
|
+
if (strcmp(buf, "uint16") == 0) return 0x00000001;
|
|
2623
|
+
if (strcmp(buf, "uint32") == 0) return 0x00000002;
|
|
2624
|
+
napi_throw_error(env, "DOE_ERROR", "Unsupported index format");
|
|
2625
|
+
return 0;
|
|
2626
|
+
}
|
|
2627
|
+
|
|
1733
2628
|
static napi_value doe_create_texture(napi_env env, napi_callback_info info) {
|
|
1734
2629
|
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1735
2630
|
CHECK_LIB_LOADED(env);
|
|
@@ -1749,7 +2644,9 @@ static napi_value doe_create_texture(napi_env env, napi_callback_info info) {
|
|
|
1749
2644
|
if (has_prop(env, _args[1], "mipLevelCount"))
|
|
1750
2645
|
desc.mipLevelCount = get_uint32_prop(env, _args[1], "mipLevelCount");
|
|
1751
2646
|
desc.sampleCount = 1;
|
|
1752
|
-
desc.dimension =
|
|
2647
|
+
desc.dimension = 2; /* WGPUTextureDimension_2D */
|
|
2648
|
+
if (has_prop(env, _args[1], "dimension"))
|
|
2649
|
+
desc.dimension = get_uint32_prop(env, _args[1], "dimension");
|
|
1753
2650
|
|
|
1754
2651
|
WGPUTexture tex = pfn_wgpuDeviceCreateTexture(device, &desc);
|
|
1755
2652
|
if (!tex) NAPI_THROW(env, "createTexture failed");
|
|
@@ -1853,16 +2750,246 @@ static napi_value doe_sampler_release(napi_env env, napi_callback_info info) {
|
|
|
1853
2750
|
}
|
|
1854
2751
|
|
|
1855
2752
|
/* ================================================================
|
|
1856
|
-
* Render Pipeline
|
|
1857
|
-
* createRenderPipeline(device)
|
|
2753
|
+
* Render Pipeline
|
|
2754
|
+
* createRenderPipeline(device, descriptor)
|
|
1858
2755
|
* ================================================================ */
|
|
1859
2756
|
|
|
1860
2757
|
static napi_value doe_create_render_pipeline(napi_env env, napi_callback_info info) {
|
|
1861
|
-
NAPI_ASSERT_ARGC(env, info,
|
|
2758
|
+
NAPI_ASSERT_ARGC(env, info, 2);
|
|
1862
2759
|
CHECK_LIB_LOADED(env);
|
|
1863
2760
|
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1864
2761
|
if (!device) NAPI_THROW(env, "Invalid device");
|
|
1865
|
-
|
|
2762
|
+
napi_valuetype descriptor_type;
|
|
2763
|
+
napi_typeof(env, _args[1], &descriptor_type);
|
|
2764
|
+
if (descriptor_type != napi_object) NAPI_THROW(env, "createRenderPipeline requires a descriptor object");
|
|
2765
|
+
|
|
2766
|
+
if (prop_type(env, _args[1], "vertex") != napi_object) {
|
|
2767
|
+
NAPI_THROW(env, "createRenderPipeline requires descriptor.vertex");
|
|
2768
|
+
}
|
|
2769
|
+
if (prop_type(env, _args[1], "fragment") != napi_object) {
|
|
2770
|
+
NAPI_THROW(env, "createRenderPipeline requires descriptor.fragment");
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
napi_value vertex = get_prop(env, _args[1], "vertex");
|
|
2774
|
+
napi_value fragment = get_prop(env, _args[1], "fragment");
|
|
2775
|
+
|
|
2776
|
+
napi_value targets = get_prop(env, fragment, "targets");
|
|
2777
|
+
bool is_targets_array = false;
|
|
2778
|
+
napi_is_array(env, targets, &is_targets_array);
|
|
2779
|
+
if (!is_targets_array) NAPI_THROW(env, "createRenderPipeline requires descriptor.fragment.targets");
|
|
2780
|
+
uint32_t target_count = 0;
|
|
2781
|
+
napi_get_array_length(env, targets, &target_count);
|
|
2782
|
+
if (target_count == 0) NAPI_THROW(env, "createRenderPipeline requires at least one fragment target");
|
|
2783
|
+
if (target_count > 1) NAPI_THROW(env, "createRenderPipeline currently supports one color target on this package surface");
|
|
2784
|
+
|
|
2785
|
+
napi_value vertex_module_value = get_prop(env, vertex, "module");
|
|
2786
|
+
WGPUShaderModule vertex_module = unwrap_ptr(env, vertex_module_value);
|
|
2787
|
+
if (!vertex_module) NAPI_THROW(env, "createRenderPipeline: descriptor.vertex.module must be a shader module");
|
|
2788
|
+
napi_value fragment_module_value = get_prop(env, fragment, "module");
|
|
2789
|
+
WGPUShaderModule fragment_module = unwrap_ptr(env, fragment_module_value);
|
|
2790
|
+
if (!fragment_module) NAPI_THROW(env, "createRenderPipeline: descriptor.fragment.module must be a shader module");
|
|
2791
|
+
|
|
2792
|
+
size_t vertex_entry_len = 0;
|
|
2793
|
+
size_t fragment_entry_len = 0;
|
|
2794
|
+
char* vertex_entry = has_prop(env, vertex, "entryPoint")
|
|
2795
|
+
? dup_string_value(env, get_prop(env, vertex, "entryPoint"), &vertex_entry_len)
|
|
2796
|
+
: strdup("main");
|
|
2797
|
+
if (!has_prop(env, vertex, "entryPoint")) vertex_entry_len = 4;
|
|
2798
|
+
char* fragment_entry = has_prop(env, fragment, "entryPoint")
|
|
2799
|
+
? dup_string_value(env, get_prop(env, fragment, "entryPoint"), &fragment_entry_len)
|
|
2800
|
+
: strdup("main");
|
|
2801
|
+
if (!has_prop(env, fragment, "entryPoint")) fragment_entry_len = 4;
|
|
2802
|
+
if (!vertex_entry || !fragment_entry) {
|
|
2803
|
+
free(vertex_entry);
|
|
2804
|
+
free(fragment_entry);
|
|
2805
|
+
NAPI_THROW(env, "createRenderPipeline: out of memory");
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
WGPURenderVertexBufferLayout* vertex_buffers = NULL;
|
|
2809
|
+
WGPURenderVertexAttribute* vertex_attributes = NULL;
|
|
2810
|
+
WGPURenderDepthStencilState* depth_stencil = NULL;
|
|
2811
|
+
uint32_t vertex_buffer_count = 0;
|
|
2812
|
+
|
|
2813
|
+
if (has_prop(env, vertex, "buffers")) {
|
|
2814
|
+
napi_value buffers = get_prop(env, vertex, "buffers");
|
|
2815
|
+
bool is_array = false;
|
|
2816
|
+
napi_is_array(env, buffers, &is_array);
|
|
2817
|
+
if (!is_array) {
|
|
2818
|
+
free(vertex_entry);
|
|
2819
|
+
free(fragment_entry);
|
|
2820
|
+
NAPI_THROW(env, "createRenderPipeline: descriptor.vertex.buffers must be an array");
|
|
2821
|
+
}
|
|
2822
|
+
napi_get_array_length(env, buffers, &vertex_buffer_count);
|
|
2823
|
+
if (vertex_buffer_count > 0) {
|
|
2824
|
+
size_t total_attributes = 0;
|
|
2825
|
+
for (uint32_t i = 0; i < vertex_buffer_count; i++) {
|
|
2826
|
+
napi_value buffer_desc;
|
|
2827
|
+
napi_get_element(env, buffers, i, &buffer_desc);
|
|
2828
|
+
if (prop_type(env, buffer_desc, "attributes") == napi_object) {
|
|
2829
|
+
napi_value attrs = get_prop(env, buffer_desc, "attributes");
|
|
2830
|
+
bool attrs_is_array = false;
|
|
2831
|
+
napi_is_array(env, attrs, &attrs_is_array);
|
|
2832
|
+
if (!attrs_is_array) {
|
|
2833
|
+
free(vertex_entry);
|
|
2834
|
+
free(fragment_entry);
|
|
2835
|
+
NAPI_THROW(env, "createRenderPipeline: descriptor.vertex.buffers[*].attributes must be an array");
|
|
2836
|
+
}
|
|
2837
|
+
uint32_t attr_count = 0;
|
|
2838
|
+
napi_get_array_length(env, attrs, &attr_count);
|
|
2839
|
+
total_attributes += attr_count;
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
vertex_buffers = (WGPURenderVertexBufferLayout*)calloc(vertex_buffer_count, sizeof(WGPURenderVertexBufferLayout));
|
|
2844
|
+
if (!vertex_buffers) {
|
|
2845
|
+
free(vertex_entry);
|
|
2846
|
+
free(fragment_entry);
|
|
2847
|
+
NAPI_THROW(env, "createRenderPipeline: out of memory");
|
|
2848
|
+
}
|
|
2849
|
+
if (total_attributes > 0) {
|
|
2850
|
+
vertex_attributes = (WGPURenderVertexAttribute*)calloc(total_attributes, sizeof(WGPURenderVertexAttribute));
|
|
2851
|
+
if (!vertex_attributes) {
|
|
2852
|
+
free(vertex_buffers);
|
|
2853
|
+
free(vertex_entry);
|
|
2854
|
+
free(fragment_entry);
|
|
2855
|
+
NAPI_THROW(env, "createRenderPipeline: out of memory");
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
size_t attr_index = 0;
|
|
2860
|
+
for (uint32_t i = 0; i < vertex_buffer_count; i++) {
|
|
2861
|
+
napi_value buffer_desc;
|
|
2862
|
+
napi_get_element(env, buffers, i, &buffer_desc);
|
|
2863
|
+
vertex_buffers[i].nextInChain = NULL;
|
|
2864
|
+
vertex_buffers[i].stepMode = has_prop(env, buffer_desc, "stepMode")
|
|
2865
|
+
? vertex_step_mode_from_value(env, get_prop(env, buffer_desc, "stepMode"))
|
|
2866
|
+
: 0x00000001;
|
|
2867
|
+
vertex_buffers[i].arrayStride = has_prop(env, buffer_desc, "arrayStride")
|
|
2868
|
+
? (uint64_t)get_int64_prop(env, buffer_desc, "arrayStride")
|
|
2869
|
+
: 0;
|
|
2870
|
+
vertex_buffers[i].attributeCount = 0;
|
|
2871
|
+
vertex_buffers[i].attributes = NULL;
|
|
2872
|
+
|
|
2873
|
+
if (prop_type(env, buffer_desc, "attributes") == napi_object) {
|
|
2874
|
+
napi_value attrs = get_prop(env, buffer_desc, "attributes");
|
|
2875
|
+
uint32_t attr_count = 0;
|
|
2876
|
+
napi_get_array_length(env, attrs, &attr_count);
|
|
2877
|
+
vertex_buffers[i].attributeCount = attr_count;
|
|
2878
|
+
vertex_buffers[i].attributes = attr_count > 0 ? &vertex_attributes[attr_index] : NULL;
|
|
2879
|
+
for (uint32_t j = 0; j < attr_count; j++) {
|
|
2880
|
+
napi_value attr;
|
|
2881
|
+
napi_get_element(env, attrs, j, &attr);
|
|
2882
|
+
vertex_attributes[attr_index].nextInChain = NULL;
|
|
2883
|
+
vertex_attributes[attr_index].format = vertex_format_from_value(env, get_prop(env, attr, "format"));
|
|
2884
|
+
vertex_attributes[attr_index].offset = has_prop(env, attr, "offset")
|
|
2885
|
+
? (uint64_t)get_int64_prop(env, attr, "offset")
|
|
2886
|
+
: 0;
|
|
2887
|
+
vertex_attributes[attr_index].shaderLocation = get_uint32_prop(env, attr, "shaderLocation");
|
|
2888
|
+
attr_index += 1;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
napi_value target0;
|
|
2896
|
+
napi_get_element(env, targets, 0, &target0);
|
|
2897
|
+
|
|
2898
|
+
WGPURenderColorTargetState color_target;
|
|
2899
|
+
memset(&color_target, 0, sizeof(color_target));
|
|
2900
|
+
color_target.nextInChain = NULL;
|
|
2901
|
+
color_target.format = texture_format_from_string(env, get_prop(env, target0, "format"));
|
|
2902
|
+
color_target.blend = NULL;
|
|
2903
|
+
color_target.writeMask = 0xF;
|
|
2904
|
+
|
|
2905
|
+
WGPURenderFragmentState fragment_state;
|
|
2906
|
+
memset(&fragment_state, 0, sizeof(fragment_state));
|
|
2907
|
+
fragment_state.nextInChain = NULL;
|
|
2908
|
+
fragment_state.module = fragment_module;
|
|
2909
|
+
fragment_state.entryPoint.data = fragment_entry;
|
|
2910
|
+
fragment_state.entryPoint.length = fragment_entry_len;
|
|
2911
|
+
fragment_state.constantCount = 0;
|
|
2912
|
+
fragment_state.constants = NULL;
|
|
2913
|
+
fragment_state.targetCount = 1;
|
|
2914
|
+
fragment_state.targets = &color_target;
|
|
2915
|
+
|
|
2916
|
+
WGPURenderPipelineDescriptor desc;
|
|
2917
|
+
memset(&desc, 0, sizeof(desc));
|
|
2918
|
+
desc.nextInChain = NULL;
|
|
2919
|
+
desc.label.data = NULL;
|
|
2920
|
+
desc.label.length = 0;
|
|
2921
|
+
desc.layout = has_prop(env, _args[1], "layout") && prop_type(env, _args[1], "layout") == napi_external
|
|
2922
|
+
? unwrap_ptr(env, get_prop(env, _args[1], "layout"))
|
|
2923
|
+
: NULL;
|
|
2924
|
+
desc.vertex.nextInChain = NULL;
|
|
2925
|
+
desc.vertex.module = vertex_module;
|
|
2926
|
+
desc.vertex.entryPoint.data = vertex_entry;
|
|
2927
|
+
desc.vertex.entryPoint.length = vertex_entry_len;
|
|
2928
|
+
desc.vertex.constantCount = 0;
|
|
2929
|
+
desc.vertex.constants = NULL;
|
|
2930
|
+
desc.vertex.bufferCount = vertex_buffer_count;
|
|
2931
|
+
desc.vertex.buffers = vertex_buffers;
|
|
2932
|
+
desc.primitive.nextInChain = NULL;
|
|
2933
|
+
desc.primitive.topology = 0x00000004;
|
|
2934
|
+
desc.primitive.stripIndexFormat = 0;
|
|
2935
|
+
desc.primitive.frontFace = 0x00000001;
|
|
2936
|
+
desc.primitive.cullMode = 0x00000001;
|
|
2937
|
+
desc.primitive.unclippedDepth = 0;
|
|
2938
|
+
if (has_prop(env, _args[1], "primitive") && prop_type(env, _args[1], "primitive") == napi_object) {
|
|
2939
|
+
napi_value primitive = get_prop(env, _args[1], "primitive");
|
|
2940
|
+
if (has_prop(env, primitive, "topology"))
|
|
2941
|
+
desc.primitive.topology = primitive_topology_from_string(env, get_prop(env, primitive, "topology"));
|
|
2942
|
+
if (has_prop(env, primitive, "frontFace"))
|
|
2943
|
+
desc.primitive.frontFace = front_face_from_string(env, get_prop(env, primitive, "frontFace"));
|
|
2944
|
+
if (has_prop(env, primitive, "cullMode"))
|
|
2945
|
+
desc.primitive.cullMode = cull_mode_from_string(env, get_prop(env, primitive, "cullMode"));
|
|
2946
|
+
if (has_prop(env, primitive, "unclippedDepth"))
|
|
2947
|
+
desc.primitive.unclippedDepth = get_bool_prop(env, primitive, "unclippedDepth") ? 1 : 0;
|
|
2948
|
+
}
|
|
2949
|
+
desc.depthStencil = NULL;
|
|
2950
|
+
if (has_prop(env, _args[1], "depthStencil") && prop_type(env, _args[1], "depthStencil") == napi_object) {
|
|
2951
|
+
napi_value depth_obj = get_prop(env, _args[1], "depthStencil");
|
|
2952
|
+
depth_stencil = (WGPURenderDepthStencilState*)calloc(1, sizeof(WGPURenderDepthStencilState));
|
|
2953
|
+
if (!depth_stencil) {
|
|
2954
|
+
free(vertex_buffers);
|
|
2955
|
+
free(vertex_attributes);
|
|
2956
|
+
free(vertex_entry);
|
|
2957
|
+
free(fragment_entry);
|
|
2958
|
+
NAPI_THROW(env, "createRenderPipeline: out of memory");
|
|
2959
|
+
}
|
|
2960
|
+
depth_stencil->nextInChain = NULL;
|
|
2961
|
+
depth_stencil->format = texture_format_from_string(env, get_prop(env, depth_obj, "format"));
|
|
2962
|
+
depth_stencil->depthWriteEnabled = has_prop(env, depth_obj, "depthWriteEnabled")
|
|
2963
|
+
? (get_bool_prop(env, depth_obj, "depthWriteEnabled") ? 1 : 0)
|
|
2964
|
+
: 0;
|
|
2965
|
+
depth_stencil->depthCompare = has_prop(env, depth_obj, "depthCompare")
|
|
2966
|
+
? compare_func_from_value(env, get_prop(env, depth_obj, "depthCompare"))
|
|
2967
|
+
: 0x00000008;
|
|
2968
|
+
depth_stencil->stencilReadMask = 0xFFFFFFFFu;
|
|
2969
|
+
depth_stencil->stencilWriteMask = 0xFFFFFFFFu;
|
|
2970
|
+
desc.depthStencil = depth_stencil;
|
|
2971
|
+
}
|
|
2972
|
+
desc.multisample.nextInChain = NULL;
|
|
2973
|
+
desc.multisample.count = 1;
|
|
2974
|
+
desc.multisample.mask = 0xFFFFffffu;
|
|
2975
|
+
desc.multisample.alphaToCoverageEnabled = 0;
|
|
2976
|
+
if (has_prop(env, _args[1], "multisample") && prop_type(env, _args[1], "multisample") == napi_object) {
|
|
2977
|
+
napi_value multisample = get_prop(env, _args[1], "multisample");
|
|
2978
|
+
if (has_prop(env, multisample, "count"))
|
|
2979
|
+
desc.multisample.count = get_uint32_prop(env, multisample, "count");
|
|
2980
|
+
if (has_prop(env, multisample, "mask"))
|
|
2981
|
+
desc.multisample.mask = get_uint32_prop(env, multisample, "mask");
|
|
2982
|
+
if (has_prop(env, multisample, "alphaToCoverageEnabled"))
|
|
2983
|
+
desc.multisample.alphaToCoverageEnabled = get_bool_prop(env, multisample, "alphaToCoverageEnabled") ? 1 : 0;
|
|
2984
|
+
}
|
|
2985
|
+
desc.fragment = &fragment_state;
|
|
2986
|
+
|
|
2987
|
+
WGPURenderPipeline rp = pfn_wgpuDeviceCreateRenderPipeline(device, &desc);
|
|
2988
|
+
free(depth_stencil);
|
|
2989
|
+
free(vertex_attributes);
|
|
2990
|
+
free(vertex_buffers);
|
|
2991
|
+
free(vertex_entry);
|
|
2992
|
+
free(fragment_entry);
|
|
1866
2993
|
if (!rp) NAPI_THROW(env, "createRenderPipeline failed");
|
|
1867
2994
|
return wrap_ptr(env, rp);
|
|
1868
2995
|
}
|
|
@@ -1876,7 +3003,7 @@ static napi_value doe_render_pipeline_release(napi_env env, napi_callback_info i
|
|
|
1876
3003
|
|
|
1877
3004
|
/* ================================================================
|
|
1878
3005
|
* Render Pass
|
|
1879
|
-
* beginRenderPass(encoder,
|
|
3006
|
+
* beginRenderPass(encoder, descriptor)
|
|
1880
3007
|
* ================================================================ */
|
|
1881
3008
|
|
|
1882
3009
|
static napi_value doe_begin_render_pass(napi_env env, napi_callback_info info) {
|
|
@@ -1885,16 +3012,23 @@ static napi_value doe_begin_render_pass(napi_env env, napi_callback_info info) {
|
|
|
1885
3012
|
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
1886
3013
|
if (!enc) NAPI_THROW(env, "Invalid encoder");
|
|
1887
3014
|
|
|
1888
|
-
|
|
3015
|
+
if (prop_type(env, _args[1], "colorAttachments") != napi_object) {
|
|
3016
|
+
NAPI_THROW(env, "beginRenderPass requires descriptor.colorAttachments");
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
napi_value color_attachments = get_prop(env, _args[1], "colorAttachments");
|
|
1889
3020
|
uint32_t att_count = 0;
|
|
1890
|
-
napi_get_array_length(env,
|
|
3021
|
+
napi_get_array_length(env, color_attachments, &att_count);
|
|
1891
3022
|
if (att_count == 0) NAPI_THROW(env, "beginRenderPass: need at least one color attachment");
|
|
1892
3023
|
|
|
1893
3024
|
WGPURenderPassColorAttachment* atts = (WGPURenderPassColorAttachment*)calloc(
|
|
1894
3025
|
att_count, sizeof(WGPURenderPassColorAttachment));
|
|
3026
|
+
WGPURenderPassDepthStencilAttachment depth_att;
|
|
3027
|
+
memset(&depth_att, 0, sizeof(depth_att));
|
|
3028
|
+
bool has_depth_att = false;
|
|
1895
3029
|
for (uint32_t i = 0; i < att_count; i++) {
|
|
1896
3030
|
napi_value elem;
|
|
1897
|
-
napi_get_element(env,
|
|
3031
|
+
napi_get_element(env, color_attachments, i, &elem);
|
|
1898
3032
|
atts[i].view = unwrap_ptr(env, get_prop(env, elem, "view"));
|
|
1899
3033
|
atts[i].loadOp = 1; /* clear */
|
|
1900
3034
|
atts[i].storeOp = 1; /* store */
|
|
@@ -1914,10 +3048,34 @@ static napi_value doe_begin_render_pass(napi_env env, napi_callback_info info) {
|
|
|
1914
3048
|
}
|
|
1915
3049
|
}
|
|
1916
3050
|
|
|
3051
|
+
if (has_prop(env, _args[1], "depthStencilAttachment") && prop_type(env, _args[1], "depthStencilAttachment") == napi_object) {
|
|
3052
|
+
napi_value depth_obj = get_prop(env, _args[1], "depthStencilAttachment");
|
|
3053
|
+
depth_att.nextInChain = NULL;
|
|
3054
|
+
depth_att.view = unwrap_ptr(env, get_prop(env, depth_obj, "view"));
|
|
3055
|
+
depth_att.depthLoadOp = 1;
|
|
3056
|
+
depth_att.depthStoreOp = 1;
|
|
3057
|
+
depth_att.depthClearValue = has_prop(env, depth_obj, "depthClearValue")
|
|
3058
|
+
? (float)get_double_prop(env, depth_obj, "depthClearValue")
|
|
3059
|
+
: 1.0f;
|
|
3060
|
+
depth_att.depthReadOnly = has_prop(env, depth_obj, "depthReadOnly")
|
|
3061
|
+
? (get_bool_prop(env, depth_obj, "depthReadOnly") ? 1 : 0)
|
|
3062
|
+
: 0;
|
|
3063
|
+
depth_att.stencilLoadOp = 1;
|
|
3064
|
+
depth_att.stencilStoreOp = 1;
|
|
3065
|
+
depth_att.stencilClearValue = has_prop(env, depth_obj, "stencilClearValue")
|
|
3066
|
+
? get_uint32_prop(env, depth_obj, "stencilClearValue")
|
|
3067
|
+
: 0;
|
|
3068
|
+
depth_att.stencilReadOnly = has_prop(env, depth_obj, "stencilReadOnly")
|
|
3069
|
+
? (get_bool_prop(env, depth_obj, "stencilReadOnly") ? 1 : 0)
|
|
3070
|
+
: 0;
|
|
3071
|
+
has_depth_att = true;
|
|
3072
|
+
}
|
|
3073
|
+
|
|
1917
3074
|
WGPURenderPassDescriptor desc;
|
|
1918
3075
|
memset(&desc, 0, sizeof(desc));
|
|
1919
3076
|
desc.colorAttachmentCount = att_count;
|
|
1920
3077
|
desc.colorAttachments = atts;
|
|
3078
|
+
desc.depthStencilAttachment = has_depth_att ? &depth_att : NULL;
|
|
1921
3079
|
|
|
1922
3080
|
WGPURenderPassEncoder pass = pfn_wgpuCommandEncoderBeginRenderPass(enc, &desc);
|
|
1923
3081
|
free(atts);
|
|
@@ -1932,6 +3090,43 @@ static napi_value doe_render_pass_set_pipeline(napi_env env, napi_callback_info
|
|
|
1932
3090
|
return NULL;
|
|
1933
3091
|
}
|
|
1934
3092
|
|
|
3093
|
+
static napi_value doe_render_pass_set_bind_group(napi_env env, napi_callback_info info) {
|
|
3094
|
+
NAPI_ASSERT_ARGC(env, info, 3);
|
|
3095
|
+
WGPURenderPassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
3096
|
+
uint32_t index = 0;
|
|
3097
|
+
napi_get_value_uint32(env, _args[1], &index);
|
|
3098
|
+
WGPUBindGroup bg = unwrap_ptr(env, _args[2]);
|
|
3099
|
+
pfn_wgpuRenderPassEncoderSetBindGroup(pass, index, bg, 0, NULL);
|
|
3100
|
+
return NULL;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
static napi_value doe_render_pass_set_vertex_buffer(napi_env env, napi_callback_info info) {
|
|
3104
|
+
NAPI_ASSERT_ARGC(env, info, 5);
|
|
3105
|
+
WGPURenderPassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
3106
|
+
uint32_t slot = 0;
|
|
3107
|
+
uint64_t offset = 0;
|
|
3108
|
+
uint64_t size = 0;
|
|
3109
|
+
napi_get_value_uint32(env, _args[1], &slot);
|
|
3110
|
+
WGPUBuffer buffer = unwrap_ptr(env, _args[2]);
|
|
3111
|
+
offset = (uint64_t)get_int64_value(env, _args[3]);
|
|
3112
|
+
size = (uint64_t)get_int64_value(env, _args[4]);
|
|
3113
|
+
pfn_wgpuRenderPassEncoderSetVertexBuffer(pass, slot, buffer, offset, size);
|
|
3114
|
+
return NULL;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
static napi_value doe_render_pass_set_index_buffer(napi_env env, napi_callback_info info) {
|
|
3118
|
+
NAPI_ASSERT_ARGC(env, info, 5);
|
|
3119
|
+
WGPURenderPassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
3120
|
+
WGPUBuffer buffer = unwrap_ptr(env, _args[1]);
|
|
3121
|
+
uint32_t format = index_format_from_value(env, _args[2]);
|
|
3122
|
+
uint64_t offset = 0;
|
|
3123
|
+
uint64_t size = 0;
|
|
3124
|
+
offset = (uint64_t)get_int64_value(env, _args[3]);
|
|
3125
|
+
size = (uint64_t)get_int64_value(env, _args[4]);
|
|
3126
|
+
pfn_wgpuRenderPassEncoderSetIndexBuffer(pass, buffer, format, offset, size);
|
|
3127
|
+
return NULL;
|
|
3128
|
+
}
|
|
3129
|
+
|
|
1935
3130
|
/* renderPassDraw(pass, vertexCount, instanceCount, firstVertex, firstInstance) */
|
|
1936
3131
|
static napi_value doe_render_pass_draw(napi_env env, napi_callback_info info) {
|
|
1937
3132
|
NAPI_ASSERT_ARGC(env, info, 5);
|
|
@@ -1945,6 +3140,23 @@ static napi_value doe_render_pass_draw(napi_env env, napi_callback_info info) {
|
|
|
1945
3140
|
return NULL;
|
|
1946
3141
|
}
|
|
1947
3142
|
|
|
3143
|
+
static napi_value doe_render_pass_draw_indexed(napi_env env, napi_callback_info info) {
|
|
3144
|
+
NAPI_ASSERT_ARGC(env, info, 6);
|
|
3145
|
+
WGPURenderPassEncoder pass = unwrap_ptr(env, _args[0]);
|
|
3146
|
+
uint32_t index_count = 0;
|
|
3147
|
+
uint32_t instance_count = 0;
|
|
3148
|
+
uint32_t first_index = 0;
|
|
3149
|
+
int32_t base_vertex = 0;
|
|
3150
|
+
uint32_t first_instance = 0;
|
|
3151
|
+
napi_get_value_uint32(env, _args[1], &index_count);
|
|
3152
|
+
napi_get_value_uint32(env, _args[2], &instance_count);
|
|
3153
|
+
napi_get_value_uint32(env, _args[3], &first_index);
|
|
3154
|
+
napi_get_value_int32(env, _args[4], &base_vertex);
|
|
3155
|
+
napi_get_value_uint32(env, _args[5], &first_instance);
|
|
3156
|
+
pfn_wgpuRenderPassEncoderDrawIndexed(pass, index_count, instance_count, first_index, base_vertex, first_instance);
|
|
3157
|
+
return NULL;
|
|
3158
|
+
}
|
|
3159
|
+
|
|
1948
3160
|
static napi_value doe_render_pass_end(napi_env env, napi_callback_info info) {
|
|
1949
3161
|
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1950
3162
|
pfn_wgpuRenderPassEncoderEnd(unwrap_ptr(env, _args[0]));
|
|
@@ -1962,21 +3174,12 @@ static napi_value doe_render_pass_release(napi_env env, napi_callback_info info)
|
|
|
1962
3174
|
* Device capabilities: limits, features
|
|
1963
3175
|
* ================================================================ */
|
|
1964
3176
|
|
|
1965
|
-
static napi_value
|
|
1966
|
-
NAPI_ASSERT_ARGC(env, info, 1);
|
|
1967
|
-
CHECK_LIB_LOADED(env);
|
|
1968
|
-
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
1969
|
-
if (!device) NAPI_THROW(env, "deviceGetLimits: null device");
|
|
1970
|
-
|
|
1971
|
-
WGPULimits limits;
|
|
1972
|
-
memset(&limits, 0, sizeof(limits));
|
|
1973
|
-
pfn_wgpuDeviceGetLimits(device, &limits);
|
|
1974
|
-
|
|
3177
|
+
static napi_value create_limits_object(napi_env env, const WGPULimits* limits) {
|
|
1975
3178
|
napi_value obj;
|
|
1976
3179
|
napi_create_object(env, &obj);
|
|
1977
3180
|
|
|
1978
|
-
#define SET_U32(name) do { napi_value v; napi_create_uint32(env, limits
|
|
1979
|
-
#define SET_U64(name) do { napi_value v; napi_create_double(env, (double)limits
|
|
3181
|
+
#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)
|
|
3182
|
+
#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)
|
|
1980
3183
|
|
|
1981
3184
|
SET_U32(maxTextureDimension1D);
|
|
1982
3185
|
SET_U32(maxTextureDimension2D);
|
|
@@ -2016,18 +3219,192 @@ static napi_value doe_device_get_limits(napi_env env, napi_callback_info info) {
|
|
|
2016
3219
|
return obj;
|
|
2017
3220
|
}
|
|
2018
3221
|
|
|
3222
|
+
static napi_value doe_device_get_limits(napi_env env, napi_callback_info info) {
|
|
3223
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
3224
|
+
CHECK_LIB_LOADED(env);
|
|
3225
|
+
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
3226
|
+
if (!device) NAPI_THROW(env, "deviceGetLimits: null device");
|
|
3227
|
+
uint32_t (*fn)(WGPUDevice, void*) = pfn_doeNativeDeviceGetLimits ? pfn_doeNativeDeviceGetLimits : pfn_wgpuDeviceGetLimits;
|
|
3228
|
+
if (!fn) {
|
|
3229
|
+
napi_value ret;
|
|
3230
|
+
napi_get_null(env, &ret);
|
|
3231
|
+
return ret;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
WGPULimits limits;
|
|
3235
|
+
memset(&limits, 0, sizeof(limits));
|
|
3236
|
+
uint32_t status = fn(device, &limits);
|
|
3237
|
+
if (status != WGPU_STATUS_SUCCESS) {
|
|
3238
|
+
napi_value ret;
|
|
3239
|
+
napi_get_null(env, &ret);
|
|
3240
|
+
return ret;
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
return create_limits_object(env, &limits);
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
static napi_value doe_adapter_get_limits(napi_env env, napi_callback_info info) {
|
|
3247
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
3248
|
+
CHECK_LIB_LOADED(env);
|
|
3249
|
+
WGPUAdapter adapter = unwrap_ptr(env, _args[0]);
|
|
3250
|
+
if (!adapter) NAPI_THROW(env, "adapterGetLimits: null adapter");
|
|
3251
|
+
uint32_t (*fn)(WGPUAdapter, void*) = pfn_doeNativeAdapterGetLimits ? pfn_doeNativeAdapterGetLimits : pfn_wgpuAdapterGetLimits;
|
|
3252
|
+
if (!fn) {
|
|
3253
|
+
napi_value ret;
|
|
3254
|
+
napi_get_null(env, &ret);
|
|
3255
|
+
return ret;
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
WGPULimits limits;
|
|
3259
|
+
memset(&limits, 0, sizeof(limits));
|
|
3260
|
+
uint32_t status = fn(adapter, &limits);
|
|
3261
|
+
if (status != WGPU_STATUS_SUCCESS) {
|
|
3262
|
+
napi_value ret;
|
|
3263
|
+
napi_get_null(env, &ret);
|
|
3264
|
+
return ret;
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
return create_limits_object(env, &limits);
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
static napi_value doe_adapter_has_feature(napi_env env, napi_callback_info info) {
|
|
3271
|
+
NAPI_ASSERT_ARGC(env, info, 2);
|
|
3272
|
+
CHECK_LIB_LOADED(env);
|
|
3273
|
+
WGPUAdapter adapter = unwrap_ptr(env, _args[0]);
|
|
3274
|
+
uint32_t (*fn)(WGPUAdapter, uint32_t) = pfn_doeNativeAdapterHasFeature ? pfn_doeNativeAdapterHasFeature : pfn_wgpuAdapterHasFeature;
|
|
3275
|
+
if (!fn) {
|
|
3276
|
+
napi_value ret;
|
|
3277
|
+
napi_get_boolean(env, false, &ret);
|
|
3278
|
+
return ret;
|
|
3279
|
+
}
|
|
3280
|
+
uint32_t feature;
|
|
3281
|
+
napi_get_value_uint32(env, _args[1], &feature);
|
|
3282
|
+
uint32_t result = fn(adapter, feature);
|
|
3283
|
+
napi_value ret;
|
|
3284
|
+
napi_get_boolean(env, result != 0, &ret);
|
|
3285
|
+
return ret;
|
|
3286
|
+
}
|
|
3287
|
+
|
|
2019
3288
|
static napi_value doe_device_has_feature(napi_env env, napi_callback_info info) {
|
|
2020
3289
|
NAPI_ASSERT_ARGC(env, info, 2);
|
|
2021
3290
|
CHECK_LIB_LOADED(env);
|
|
2022
3291
|
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
3292
|
+
uint32_t (*fn)(WGPUDevice, uint32_t) = pfn_doeNativeDeviceHasFeature ? pfn_doeNativeDeviceHasFeature : pfn_wgpuDeviceHasFeature;
|
|
3293
|
+
if (!fn) {
|
|
3294
|
+
napi_value ret;
|
|
3295
|
+
napi_get_boolean(env, false, &ret);
|
|
3296
|
+
return ret;
|
|
3297
|
+
}
|
|
2023
3298
|
uint32_t feature;
|
|
2024
3299
|
napi_get_value_uint32(env, _args[1], &feature);
|
|
2025
|
-
uint32_t result =
|
|
3300
|
+
uint32_t result = fn(device, feature);
|
|
2026
3301
|
napi_value ret;
|
|
2027
3302
|
napi_get_boolean(env, result != 0, &ret);
|
|
2028
3303
|
return ret;
|
|
2029
3304
|
}
|
|
2030
3305
|
|
|
3306
|
+
static napi_value doe_get_last_error_stage(napi_env env, napi_callback_info info) {
|
|
3307
|
+
(void)info;
|
|
3308
|
+
char buf[64];
|
|
3309
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorStage, buf, sizeof(buf));
|
|
3310
|
+
if (buf[0] == '\0') return NULL;
|
|
3311
|
+
napi_value result;
|
|
3312
|
+
napi_create_string_utf8(env, buf, NAPI_AUTO_LENGTH, &result);
|
|
3313
|
+
return result;
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
static napi_value doe_get_last_error_kind(napi_env env, napi_callback_info info) {
|
|
3317
|
+
(void)info;
|
|
3318
|
+
char buf[64];
|
|
3319
|
+
copy_library_error_meta(pfn_doeNativeCopyLastErrorKind, buf, sizeof(buf));
|
|
3320
|
+
if (buf[0] == '\0') return NULL;
|
|
3321
|
+
napi_value result;
|
|
3322
|
+
napi_create_string_utf8(env, buf, NAPI_AUTO_LENGTH, &result);
|
|
3323
|
+
return result;
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
static napi_value doe_get_last_error_line(napi_env env, napi_callback_info info) {
|
|
3327
|
+
(void)info;
|
|
3328
|
+
if (!pfn_doeNativeGetLastErrorLine) return NULL;
|
|
3329
|
+
uint32_t line = pfn_doeNativeGetLastErrorLine();
|
|
3330
|
+
napi_value result;
|
|
3331
|
+
napi_create_uint32(env, line, &result);
|
|
3332
|
+
return result;
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
static napi_value doe_get_last_error_column(napi_env env, napi_callback_info info) {
|
|
3336
|
+
(void)info;
|
|
3337
|
+
if (!pfn_doeNativeGetLastErrorColumn) return NULL;
|
|
3338
|
+
uint32_t col = pfn_doeNativeGetLastErrorColumn();
|
|
3339
|
+
napi_value result;
|
|
3340
|
+
napi_create_uint32(env, col, &result);
|
|
3341
|
+
return result;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
/* ================================================================
|
|
3345
|
+
* QuerySet (timestamp query)
|
|
3346
|
+
* ================================================================ */
|
|
3347
|
+
|
|
3348
|
+
static napi_value doe_create_query_set(napi_env env, napi_callback_info info) {
|
|
3349
|
+
NAPI_ASSERT_ARGC(env, info, 3);
|
|
3350
|
+
CHECK_LIB_LOADED(env);
|
|
3351
|
+
if (!pfn_doeNativeDeviceCreateQuerySet) NAPI_THROW(env, "doeNativeDeviceCreateQuerySet not available");
|
|
3352
|
+
WGPUDevice device = unwrap_ptr(env, _args[0]);
|
|
3353
|
+
if (!device) NAPI_THROW(env, "Invalid device");
|
|
3354
|
+
uint32_t query_type = 0;
|
|
3355
|
+
napi_get_value_uint32(env, _args[1], &query_type);
|
|
3356
|
+
uint32_t count = 0;
|
|
3357
|
+
napi_get_value_uint32(env, _args[2], &count);
|
|
3358
|
+
WGPUQuerySet qs = pfn_doeNativeDeviceCreateQuerySet(device, query_type, count);
|
|
3359
|
+
if (!qs) NAPI_THROW(env, "createQuerySet failed");
|
|
3360
|
+
return wrap_ptr(env, qs);
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
static napi_value doe_command_encoder_write_timestamp(napi_env env, napi_callback_info info) {
|
|
3364
|
+
NAPI_ASSERT_ARGC(env, info, 3);
|
|
3365
|
+
CHECK_LIB_LOADED(env);
|
|
3366
|
+
if (!pfn_doeNativeCommandEncoderWriteTimestamp) NAPI_THROW(env, "doeNativeCommandEncoderWriteTimestamp not available");
|
|
3367
|
+
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
3368
|
+
WGPUQuerySet qs = unwrap_ptr(env, _args[1]);
|
|
3369
|
+
uint32_t query_index = 0;
|
|
3370
|
+
napi_get_value_uint32(env, _args[2], &query_index);
|
|
3371
|
+
pfn_doeNativeCommandEncoderWriteTimestamp(enc, qs, query_index);
|
|
3372
|
+
return NULL;
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
static napi_value doe_command_encoder_resolve_query_set(napi_env env, napi_callback_info info) {
|
|
3376
|
+
NAPI_ASSERT_ARGC(env, info, 6);
|
|
3377
|
+
CHECK_LIB_LOADED(env);
|
|
3378
|
+
if (!pfn_doeNativeCommandEncoderResolveQuerySet) NAPI_THROW(env, "doeNativeCommandEncoderResolveQuerySet not available");
|
|
3379
|
+
WGPUCommandEncoder enc = unwrap_ptr(env, _args[0]);
|
|
3380
|
+
WGPUQuerySet qs = unwrap_ptr(env, _args[1]);
|
|
3381
|
+
uint32_t first_query = 0;
|
|
3382
|
+
napi_get_value_uint32(env, _args[2], &first_query);
|
|
3383
|
+
uint32_t query_count = 0;
|
|
3384
|
+
napi_get_value_uint32(env, _args[3], &query_count);
|
|
3385
|
+
WGPUBuffer dst = unwrap_ptr(env, _args[4]);
|
|
3386
|
+
int64_t dst_offset = 0;
|
|
3387
|
+
napi_get_value_int64(env, _args[5], &dst_offset);
|
|
3388
|
+
pfn_doeNativeCommandEncoderResolveQuerySet(enc, qs, first_query, query_count, dst, (uint64_t)dst_offset);
|
|
3389
|
+
return NULL;
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
static napi_value doe_query_set_destroy(napi_env env, napi_callback_info info) {
|
|
3393
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
3394
|
+
if (!pfn_doeNativeQuerySetDestroy) return NULL;
|
|
3395
|
+
WGPUQuerySet qs = unwrap_ptr(env, _args[0]);
|
|
3396
|
+
if (qs) pfn_doeNativeQuerySetDestroy(qs);
|
|
3397
|
+
return NULL;
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
static napi_value doe_set_timeout_ms(napi_env env, napi_callback_info info) {
|
|
3401
|
+
NAPI_ASSERT_ARGC(env, info, 1);
|
|
3402
|
+
uint32_t timeout_ms = 0;
|
|
3403
|
+
napi_get_value_uint32(env, _args[0], &timeout_ms);
|
|
3404
|
+
g_timeout_ns = (uint64_t)timeout_ms * 1000000ULL;
|
|
3405
|
+
return NULL;
|
|
3406
|
+
}
|
|
3407
|
+
|
|
2031
3408
|
/* ================================================================
|
|
2032
3409
|
* Module initialization
|
|
2033
3410
|
* ================================================================ */
|
|
@@ -2049,9 +3426,13 @@ static napi_value doe_module_init(napi_env env, napi_value exports) {
|
|
|
2049
3426
|
EXPORT_FN("bufferUnmap", doe_buffer_unmap),
|
|
2050
3427
|
EXPORT_FN("bufferMapSync", doe_buffer_map_sync),
|
|
2051
3428
|
EXPORT_FN("bufferGetMappedRange", doe_buffer_get_mapped_range),
|
|
3429
|
+
EXPORT_FN("bufferWriteMappedRange", doe_buffer_write_mapped_range),
|
|
3430
|
+
EXPORT_FN("bufferReadIndirectCounts", doe_buffer_read_indirect_counts),
|
|
2052
3431
|
EXPORT_FN("bufferAssertMappedPrefixF32", doe_buffer_assert_mapped_prefix_f32),
|
|
3432
|
+
EXPORT_FN("checkShaderSource", doe_check_shader_source),
|
|
2053
3433
|
EXPORT_FN("createShaderModule", doe_create_shader_module),
|
|
2054
3434
|
EXPORT_FN("shaderModuleRelease", doe_shader_module_release),
|
|
3435
|
+
EXPORT_FN("shaderModuleGetBindings", doe_shader_module_get_bindings),
|
|
2055
3436
|
EXPORT_FN("createComputePipeline", doe_create_compute_pipeline),
|
|
2056
3437
|
EXPORT_FN("computePipelineRelease", doe_compute_pipeline_release),
|
|
2057
3438
|
EXPORT_FN("computePipelineGetBindGroupLayout", doe_compute_pipeline_get_bind_group_layout),
|
|
@@ -2064,6 +3445,7 @@ static napi_value doe_module_init(napi_env env, napi_value exports) {
|
|
|
2064
3445
|
EXPORT_FN("createCommandEncoder", doe_create_command_encoder),
|
|
2065
3446
|
EXPORT_FN("commandEncoderRelease", doe_command_encoder_release),
|
|
2066
3447
|
EXPORT_FN("commandEncoderCopyBufferToBuffer", doe_command_encoder_copy_buffer_to_buffer),
|
|
3448
|
+
EXPORT_FN("commandEncoderCopyTextureToBuffer", doe_command_encoder_copy_texture_to_buffer),
|
|
2067
3449
|
EXPORT_FN("commandEncoderFinish", doe_command_encoder_finish),
|
|
2068
3450
|
EXPORT_FN("commandBufferRelease", doe_command_buffer_release),
|
|
2069
3451
|
EXPORT_FN("beginComputePass", doe_begin_compute_pass),
|
|
@@ -2090,11 +3472,26 @@ static napi_value doe_module_init(napi_env env, napi_value exports) {
|
|
|
2090
3472
|
EXPORT_FN("renderPipelineRelease", doe_render_pipeline_release),
|
|
2091
3473
|
EXPORT_FN("beginRenderPass", doe_begin_render_pass),
|
|
2092
3474
|
EXPORT_FN("renderPassSetPipeline", doe_render_pass_set_pipeline),
|
|
3475
|
+
EXPORT_FN("renderPassSetBindGroup", doe_render_pass_set_bind_group),
|
|
3476
|
+
EXPORT_FN("renderPassSetVertexBuffer", doe_render_pass_set_vertex_buffer),
|
|
3477
|
+
EXPORT_FN("renderPassSetIndexBuffer", doe_render_pass_set_index_buffer),
|
|
2093
3478
|
EXPORT_FN("renderPassDraw", doe_render_pass_draw),
|
|
3479
|
+
EXPORT_FN("renderPassDrawIndexed", doe_render_pass_draw_indexed),
|
|
2094
3480
|
EXPORT_FN("renderPassEnd", doe_render_pass_end),
|
|
2095
3481
|
EXPORT_FN("renderPassRelease", doe_render_pass_release),
|
|
3482
|
+
EXPORT_FN("adapterGetLimits", doe_adapter_get_limits),
|
|
3483
|
+
EXPORT_FN("adapterHasFeature", doe_adapter_has_feature),
|
|
2096
3484
|
EXPORT_FN("deviceGetLimits", doe_device_get_limits),
|
|
2097
3485
|
EXPORT_FN("deviceHasFeature", doe_device_has_feature),
|
|
3486
|
+
EXPORT_FN("createQuerySet", doe_create_query_set),
|
|
3487
|
+
EXPORT_FN("commandEncoderWriteTimestamp", doe_command_encoder_write_timestamp),
|
|
3488
|
+
EXPORT_FN("commandEncoderResolveQuerySet", doe_command_encoder_resolve_query_set),
|
|
3489
|
+
EXPORT_FN("querySetDestroy", doe_query_set_destroy),
|
|
3490
|
+
EXPORT_FN("setTimeoutMs", doe_set_timeout_ms),
|
|
3491
|
+
EXPORT_FN("getLastErrorStage", doe_get_last_error_stage),
|
|
3492
|
+
EXPORT_FN("getLastErrorKind", doe_get_last_error_kind),
|
|
3493
|
+
EXPORT_FN("getLastErrorLine", doe_get_last_error_line),
|
|
3494
|
+
EXPORT_FN("getLastErrorColumn", doe_get_last_error_column),
|
|
2098
3495
|
};
|
|
2099
3496
|
|
|
2100
3497
|
size_t count = sizeof(descriptors) / sizeof(descriptors[0]);
|