@next2d/builder 0.1.7 → 0.1.8
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/dist/index.js +62 -26
- package/package.json +3 -2
- package/templates/xbox/CMakeLists.txt +69 -0
- package/templates/xbox/README.md +16 -8
- package/templates/xbox/cmake/FetchDawn.cmake +47 -6
- package/templates/xbox/cmake/FindV8.cmake +15 -0
- package/templates/xbox/js/bootstrap.js +31 -28
- package/templates/xbox/js/selftest.js +740 -90
- package/templates/xbox/src/EventLoop.cpp +28 -1
- package/templates/xbox/src/EventLoop.h +12 -0
- package/templates/xbox/src/bindings/Audio.cpp +99 -15
- package/templates/xbox/src/bindings/Bindings.h +10 -0
- package/templates/xbox/src/bindings/Canvas.cpp +45 -0
- package/templates/xbox/src/bindings/Canvas2D.cpp +2 -5
- package/templates/xbox/src/bindings/DomShims.cpp +127 -0
- package/templates/xbox/src/bindings/EventTarget.cpp +2 -0
- package/templates/xbox/src/bindings/Fetch.cpp +2 -8
- package/templates/xbox/src/bindings/Image.cpp +212 -10
- package/templates/xbox/src/bindings/Polyfills.cpp +791 -0
- package/templates/xbox/src/bindings/Video.cpp +96 -7
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +815 -15
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +3 -8
- package/templates/xbox/src/gpu/DawnContext.cpp +90 -3
- package/templates/xbox/src/gpu/DawnContext.h +18 -0
- package/templates/xbox/src/main.cpp +88 -6
- package/templates/xbox/src/platform/AudioEngine.cpp +9 -3
- package/templates/xbox/src/v8/V8Runtime.cpp +69 -5
- package/templates/xbox/src/v8/V8Util.h +29 -0
- package/templates/xbox/src/v8/WeakHandle.h +45 -0
- package/templates/xbox/src/worker/WorkerRuntime.cpp +325 -41
- package/templates/xbox/src/worker/WorkerRuntime.h +20 -10
- package/templates/xbox/tests/check_local.sh +2 -1
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include "bindings/ImageSource.h"
|
|
10
10
|
|
|
11
11
|
#include <cstring>
|
|
12
|
+
#include <iostream>
|
|
12
13
|
#include <map>
|
|
13
14
|
#include <vector>
|
|
14
15
|
|
|
@@ -24,7 +25,8 @@ struct Templates {
|
|
|
24
25
|
v8::Global<v8::ObjectTemplate> adapter, device, queue, buffer, texture,
|
|
25
26
|
textureView, sampler, shaderModule, bindGroupLayout, bindGroup,
|
|
26
27
|
pipelineLayout, renderPipeline, commandEncoder, renderPass,
|
|
27
|
-
commandBuffer, canvasContext
|
|
28
|
+
commandBuffer, canvasContext, computePipeline, computePass,
|
|
29
|
+
querySet, renderBundle, renderBundleEncoder;
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
static std::map<v8::Isolate*, Templates> g_templates;
|
|
@@ -47,6 +49,9 @@ static v8::Local<v8::Object> WrapTexture(v8::Isolate*, wgpu::Texture);
|
|
|
47
49
|
static v8::Local<v8::Object> WrapTextureView(v8::Isolate*, wgpu::TextureView);
|
|
48
50
|
static v8::Local<v8::Object> WrapEncoder(v8::Isolate*, wgpu::CommandEncoder);
|
|
49
51
|
static v8::Local<v8::Object> WrapPipeline(v8::Isolate*, wgpu::RenderPipeline);
|
|
52
|
+
static v8::Local<v8::Object> WrapComputePipeline(v8::Isolate*, wgpu::ComputePipeline);
|
|
53
|
+
static v8::Local<v8::Object> WrapQuerySet(v8::Isolate*, wgpu::QuerySet);
|
|
54
|
+
static v8::Local<v8::Object> WrapRenderBundle(v8::Isolate*, wgpu::RenderBundle);
|
|
50
55
|
|
|
51
56
|
// ---------------------------------------------------------------------------
|
|
52
57
|
// GPUBuffer
|
|
@@ -63,15 +68,25 @@ static void Buffer_GetMappedRange(const v8::FunctionCallbackInfo<v8::Value>& arg
|
|
|
63
68
|
: (buffer.GetSize() - offset);
|
|
64
69
|
|
|
65
70
|
void* ptr = buffer.GetMappedRange(offset, static_cast<size_t>(size));
|
|
66
|
-
if (
|
|
71
|
+
if (ptr) {
|
|
72
|
+
// 書き込み可能マップ: マップ領域を指す非所有 ArrayBuffer (unmap まで有効)
|
|
73
|
+
std::unique_ptr<v8::BackingStore> store = v8::ArrayBuffer::NewBackingStore(
|
|
74
|
+
ptr, static_cast<size_t>(size),
|
|
75
|
+
[](void*, size_t, void*) {}, nullptr);
|
|
76
|
+
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, std::move(store)));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MapMode::Read でマップされたバッファは非 const 版が nullptr を返す仕様。
|
|
81
|
+
// GetConstMappedRange から所有コピーを返す (読み戻し copyTextureToBuffer 等の経路)。
|
|
82
|
+
const void* cptr = buffer.GetConstMappedRange(offset, static_cast<size_t>(size));
|
|
83
|
+
if (!cptr) {
|
|
67
84
|
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, 0));
|
|
68
85
|
return;
|
|
69
86
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
[](void*, size_t, void*) {}, nullptr);
|
|
74
|
-
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, std::move(store)));
|
|
87
|
+
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, static_cast<size_t>(size));
|
|
88
|
+
memcpy(ab->GetBackingStore()->Data(), cptr, static_cast<size_t>(size));
|
|
89
|
+
args.GetReturnValue().Set(ab);
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
static void Buffer_Unmap(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
@@ -219,6 +234,55 @@ static wgpu::Extent3D ParseExtent(v8::Isolate* isolate, v8::Local<v8::Value> val
|
|
|
219
234
|
return extent;
|
|
220
235
|
}
|
|
221
236
|
|
|
237
|
+
// GPUOrigin3D は {x,y,z} オブジェクト or [x,y,z] 配列。ParseExtent とは
|
|
238
|
+
// キー名が違う (width/height ではなく x/y/z、既定は 1 ではなく 0) ため専用に扱う。
|
|
239
|
+
static wgpu::Origin3D ParseOrigin(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
|
240
|
+
{
|
|
241
|
+
wgpu::Origin3D origin = {0, 0, 0};
|
|
242
|
+
if (value->IsArray()) {
|
|
243
|
+
auto arr = value.As<v8::Array>();
|
|
244
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
245
|
+
auto get = [&](uint32_t i) -> uint32_t {
|
|
246
|
+
v8::Local<v8::Value> v;
|
|
247
|
+
return (i < arr->Length() && arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
248
|
+
? static_cast<uint32_t>(v.As<v8::Number>()->Value()) : 0;
|
|
249
|
+
};
|
|
250
|
+
origin.x = get(0);
|
|
251
|
+
origin.y = get(1);
|
|
252
|
+
origin.z = get(2);
|
|
253
|
+
} else if (value->IsObject()) {
|
|
254
|
+
auto o = value.As<v8::Object>();
|
|
255
|
+
origin.x = U32(isolate, o, "x", 0);
|
|
256
|
+
origin.y = U32(isolate, o, "y", 0);
|
|
257
|
+
origin.z = U32(isolate, o, "z", 0);
|
|
258
|
+
}
|
|
259
|
+
return origin;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static wgpu::ErrorFilter ToErrorFilter(std::string_view s)
|
|
263
|
+
{
|
|
264
|
+
if (s == "out-of-memory") return wgpu::ErrorFilter::OutOfMemory;
|
|
265
|
+
if (s == "internal") return wgpu::ErrorFilter::Internal;
|
|
266
|
+
return wgpu::ErrorFilter::Validation;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static wgpu::QueryType ToQueryType(std::string_view s)
|
|
270
|
+
{
|
|
271
|
+
if (s == "timestamp") return wgpu::QueryType::Timestamp;
|
|
272
|
+
return wgpu::QueryType::Occlusion;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// wgpu::ErrorType -> WebGPU の GPUError 種別文字列
|
|
276
|
+
static const char* ErrorTypeName(wgpu::ErrorType t)
|
|
277
|
+
{
|
|
278
|
+
switch (t) {
|
|
279
|
+
case wgpu::ErrorType::Validation: return "validation";
|
|
280
|
+
case wgpu::ErrorType::OutOfMemory: return "out-of-memory";
|
|
281
|
+
case wgpu::ErrorType::Internal: return "internal";
|
|
282
|
+
default: return "unknown";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
222
286
|
static void Queue_WriteTexture(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
223
287
|
{
|
|
224
288
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -229,6 +293,11 @@ static void Queue_WriteTexture(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
229
293
|
wgpu::TexelCopyTextureInfo copy = {};
|
|
230
294
|
copy.texture = Unwrap<wgpu::Texture>(Prop(isolate, dest, "texture").As<v8::Object>());
|
|
231
295
|
copy.mipLevel = U32(isolate, dest, "mipLevel", 0);
|
|
296
|
+
// 宛先 origin (アトラスのセル位置など)。未指定なら (0,0,0)。
|
|
297
|
+
v8::Local<v8::Value> dst_origin = Prop(isolate, dest, "origin");
|
|
298
|
+
if (dst_origin->IsObject() || dst_origin->IsArray()) {
|
|
299
|
+
copy.origin = ParseOrigin(isolate, dst_origin);
|
|
300
|
+
}
|
|
232
301
|
|
|
233
302
|
const void* data = nullptr;
|
|
234
303
|
size_t length = 0;
|
|
@@ -313,6 +382,12 @@ static void Queue_Submit(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
313
382
|
}
|
|
314
383
|
}
|
|
315
384
|
}
|
|
385
|
+
static uint64_t count = 0;
|
|
386
|
+
++count;
|
|
387
|
+
if (count <= 10 || count % 300 == 0) {
|
|
388
|
+
std::cerr << "[GPU] queue.submit #" << count
|
|
389
|
+
<< " (" << buffers.size() << " cmd)" << std::endl;
|
|
390
|
+
}
|
|
316
391
|
queue.Submit(buffers.size(), buffers.data());
|
|
317
392
|
}
|
|
318
393
|
|
|
@@ -460,6 +535,58 @@ static void Pass_End(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
460
535
|
Unwrap<wgpu::RenderPassEncoder>(args.This()).End();
|
|
461
536
|
}
|
|
462
537
|
|
|
538
|
+
static void Pass_BeginOcclusionQuery(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
539
|
+
{
|
|
540
|
+
auto& pass = Unwrap<wgpu::RenderPassEncoder>(args.This());
|
|
541
|
+
uint32_t index = args.Length() > 0 && args[0]->IsNumber()
|
|
542
|
+
? static_cast<uint32_t>(args[0].As<v8::Number>()->Value()) : 0;
|
|
543
|
+
pass.BeginOcclusionQuery(index);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
static void Pass_EndOcclusionQuery(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
547
|
+
{
|
|
548
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).EndOcclusionQuery();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
static void Pass_ExecuteBundles(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
552
|
+
{
|
|
553
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
554
|
+
auto& pass = Unwrap<wgpu::RenderPassEncoder>(args.This());
|
|
555
|
+
std::vector<wgpu::RenderBundle> bundles;
|
|
556
|
+
if (args.Length() > 0 && args[0]->IsArray()) {
|
|
557
|
+
auto arr = args[0].As<v8::Array>();
|
|
558
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
559
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
560
|
+
v8::Local<v8::Value> v;
|
|
561
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsObject())
|
|
562
|
+
bundles.push_back(Unwrap<wgpu::RenderBundle>(v.As<v8::Object>()));
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
pass.ExecuteBundles(bundles.size(), bundles.data());
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// pushDebugGroup / popDebugGroup / insertDebugMarker (render pass)
|
|
569
|
+
static void Pass_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
570
|
+
{
|
|
571
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
572
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
573
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).PushDebugGroup(
|
|
574
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
static void Pass_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
578
|
+
{
|
|
579
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).PopDebugGroup();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
static void Pass_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
583
|
+
{
|
|
584
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
585
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
586
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).InsertDebugMarker(
|
|
587
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
588
|
+
}
|
|
589
|
+
|
|
463
590
|
static v8::Local<v8::Object> WrapRenderPass(v8::Isolate* isolate, wgpu::RenderPassEncoder pass)
|
|
464
591
|
{
|
|
465
592
|
v8::Local<v8::Object> obj = WrapWith(isolate, Tmpl(isolate).renderPass, std::move(pass));
|
|
@@ -474,10 +601,120 @@ static v8::Local<v8::Object> WrapRenderPass(v8::Isolate* isolate, wgpu::RenderPa
|
|
|
474
601
|
SetMethod(isolate, obj, "draw", Pass_Draw);
|
|
475
602
|
SetMethod(isolate, obj, "drawIndexed", Pass_DrawIndexed);
|
|
476
603
|
SetMethod(isolate, obj, "drawIndirect", Pass_DrawIndirect);
|
|
604
|
+
SetMethod(isolate, obj, "beginOcclusionQuery", Pass_BeginOcclusionQuery);
|
|
605
|
+
SetMethod(isolate, obj, "endOcclusionQuery", Pass_EndOcclusionQuery);
|
|
606
|
+
SetMethod(isolate, obj, "executeBundles", Pass_ExecuteBundles);
|
|
607
|
+
SetMethod(isolate, obj, "pushDebugGroup", Pass_PushDebugGroup);
|
|
608
|
+
SetMethod(isolate, obj, "popDebugGroup", Pass_PopDebugGroup);
|
|
609
|
+
SetMethod(isolate, obj, "insertDebugMarker", Pass_InsertDebugMarker);
|
|
477
610
|
SetMethod(isolate, obj, "end", Pass_End);
|
|
478
611
|
return obj;
|
|
479
612
|
}
|
|
480
613
|
|
|
614
|
+
// ---------------------------------------------------------------------------
|
|
615
|
+
// GPUComputePassEncoder
|
|
616
|
+
// compute シェーダ経路 (createComputePipeline / beginComputePass / dispatch)。
|
|
617
|
+
// Next2D の 2D ラスタライザは未使用だが、WebGPU の機能を特定用途に絞らず
|
|
618
|
+
// 全面的に利用可能にするため実装する。汎用 GPGPU / storage buffer 出力に対応。
|
|
619
|
+
// ---------------------------------------------------------------------------
|
|
620
|
+
static void CPass_SetPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
621
|
+
{
|
|
622
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).SetPipeline(
|
|
623
|
+
Unwrap<wgpu::ComputePipeline>(args[0].As<v8::Object>()));
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
static void CPass_SetBindGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
627
|
+
{
|
|
628
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
629
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
630
|
+
uint32_t index = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
631
|
+
if (args.Length() < 2 || !args[1]->IsObject()) {
|
|
632
|
+
pass.SetBindGroup(index, nullptr);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
auto& group = Unwrap<wgpu::BindGroup>(args[1].As<v8::Object>());
|
|
636
|
+
|
|
637
|
+
// dynamicOffsets (render pass と同じく Array<number> / Uint32Array)
|
|
638
|
+
std::vector<uint32_t> offsets;
|
|
639
|
+
if (args.Length() > 2 && !args[2]->IsNullOrUndefined()) {
|
|
640
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
641
|
+
if (args[2]->IsArray()) {
|
|
642
|
+
auto arr = args[2].As<v8::Array>();
|
|
643
|
+
offsets.reserve(arr->Length());
|
|
644
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
645
|
+
v8::Local<v8::Value> v;
|
|
646
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
647
|
+
offsets.push_back(static_cast<uint32_t>(v.As<v8::Number>()->Value()));
|
|
648
|
+
}
|
|
649
|
+
} else if (args[2]->IsUint32Array()) {
|
|
650
|
+
auto ta = args[2].As<v8::Uint32Array>();
|
|
651
|
+
offsets.resize(ta->Length());
|
|
652
|
+
ta->CopyContents(offsets.data(), offsets.size() * sizeof(uint32_t));
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
pass.SetBindGroup(index, group,
|
|
656
|
+
static_cast<uint32_t>(offsets.size()),
|
|
657
|
+
offsets.empty() ? nullptr : offsets.data());
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
static void CPass_DispatchWorkgroups(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
661
|
+
{
|
|
662
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
663
|
+
auto n = [&](int i, uint32_t fb) {
|
|
664
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
665
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
666
|
+
pass.DispatchWorkgroups(n(0, 1), n(1, 1), n(2, 1));
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
static void CPass_DispatchWorkgroupsIndirect(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
670
|
+
{
|
|
671
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
672
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
673
|
+
uint64_t offset = args.Length() > 1 && args[1]->IsNumber()
|
|
674
|
+
? static_cast<uint64_t>(args[1].As<v8::Number>()->Value()) : 0;
|
|
675
|
+
pass.DispatchWorkgroupsIndirect(buffer, offset);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
static void CPass_End(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
679
|
+
{
|
|
680
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).End();
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static void CPass_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
684
|
+
{
|
|
685
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
686
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
687
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).PushDebugGroup(
|
|
688
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
static void CPass_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
692
|
+
{
|
|
693
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).PopDebugGroup();
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
static void CPass_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
697
|
+
{
|
|
698
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
699
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
700
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).InsertDebugMarker(
|
|
701
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
static v8::Local<v8::Object> WrapComputePass(v8::Isolate* isolate, wgpu::ComputePassEncoder pass)
|
|
705
|
+
{
|
|
706
|
+
v8::Local<v8::Object> obj = WrapWith(isolate, Tmpl(isolate).computePass, std::move(pass));
|
|
707
|
+
SetMethod(isolate, obj, "setPipeline", CPass_SetPipeline);
|
|
708
|
+
SetMethod(isolate, obj, "setBindGroup", CPass_SetBindGroup);
|
|
709
|
+
SetMethod(isolate, obj, "dispatchWorkgroups", CPass_DispatchWorkgroups);
|
|
710
|
+
SetMethod(isolate, obj, "dispatchWorkgroupsIndirect", CPass_DispatchWorkgroupsIndirect);
|
|
711
|
+
SetMethod(isolate, obj, "pushDebugGroup", CPass_PushDebugGroup);
|
|
712
|
+
SetMethod(isolate, obj, "popDebugGroup", CPass_PopDebugGroup);
|
|
713
|
+
SetMethod(isolate, obj, "insertDebugMarker", CPass_InsertDebugMarker);
|
|
714
|
+
SetMethod(isolate, obj, "end", CPass_End);
|
|
715
|
+
return obj;
|
|
716
|
+
}
|
|
717
|
+
|
|
481
718
|
// ---------------------------------------------------------------------------
|
|
482
719
|
// GPUCommandEncoder
|
|
483
720
|
// ---------------------------------------------------------------------------
|
|
@@ -501,6 +738,13 @@ static void Encoder_BeginRenderPass(const v8::FunctionCallbackInfo<v8::Value>& a
|
|
|
501
738
|
att.loadOp = ToLoadOp(webgpu::Str(isolate, o, "loadOp"));
|
|
502
739
|
att.storeOp = ToStoreOp(webgpu::Str(isolate, o, "storeOp"));
|
|
503
740
|
att.depthSlice = wgpu::kDepthSliceUndefined;
|
|
741
|
+
// MSAA 解決先。player は全描画を MSAA テクスチャへ行い resolveTarget で
|
|
742
|
+
// 本体テクスチャに解決する。未対応だと描画結果がどこにも現れない (黒画面)。
|
|
743
|
+
v8::Local<v8::Value> rt = Prop(isolate, o, "resolveTarget");
|
|
744
|
+
if (rt->IsObject()) {
|
|
745
|
+
att.resolveTarget =
|
|
746
|
+
Unwrap<wgpu::TextureView>(rt.As<v8::Object>());
|
|
747
|
+
}
|
|
504
748
|
v8::Local<v8::Value> cv = Prop(isolate, o, "clearValue");
|
|
505
749
|
if (cv->IsArray()) {
|
|
506
750
|
auto c = cv.As<v8::Array>();
|
|
@@ -544,10 +788,38 @@ static void Encoder_BeginRenderPass(const v8::FunctionCallbackInfo<v8::Value>& a
|
|
|
544
788
|
pass_desc.depthStencilAttachment = &depth;
|
|
545
789
|
}
|
|
546
790
|
|
|
791
|
+
// occlusionQuerySet: beginOcclusionQuery/endOcclusionQuery で被覆サンプル数を計測する
|
|
792
|
+
v8::Local<v8::Value> oqs = Prop(isolate, desc, "occlusionQuerySet");
|
|
793
|
+
if (oqs->IsObject()) {
|
|
794
|
+
pass_desc.occlusionQuerySet = Unwrap<wgpu::QuerySet>(oqs.As<v8::Object>());
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// timestampWrites: { querySet, beginningOfPassWriteIndex?, endOfPassWriteIndex? }
|
|
798
|
+
// (timestamp-query フィーチャ有効時のみ有効。未有効なら player/検証側で未使用)
|
|
799
|
+
wgpu::PassTimestampWrites ts = {};
|
|
800
|
+
v8::Local<v8::Value> tsv = Prop(isolate, desc, "timestampWrites");
|
|
801
|
+
if (tsv->IsObject()) {
|
|
802
|
+
auto t = tsv.As<v8::Object>();
|
|
803
|
+
ts.querySet = Unwrap<wgpu::QuerySet>(Prop(isolate, t, "querySet").As<v8::Object>());
|
|
804
|
+
ts.beginningOfPassWriteIndex = U32(isolate, t, "beginningOfPassWriteIndex", wgpu::kQuerySetIndexUndefined);
|
|
805
|
+
ts.endOfPassWriteIndex = U32(isolate, t, "endOfPassWriteIndex", wgpu::kQuerySetIndexUndefined);
|
|
806
|
+
pass_desc.timestampWrites = &ts;
|
|
807
|
+
}
|
|
808
|
+
|
|
547
809
|
args.GetReturnValue().Set(
|
|
548
810
|
WrapRenderPass(isolate, encoder.BeginRenderPass(&pass_desc)));
|
|
549
811
|
}
|
|
550
812
|
|
|
813
|
+
static void Encoder_BeginComputePass(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
814
|
+
{
|
|
815
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
816
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
817
|
+
// descriptor は任意 (timestampWrites 等は未使用)。既定で開始する。
|
|
818
|
+
wgpu::ComputePassDescriptor desc = {};
|
|
819
|
+
args.GetReturnValue().Set(
|
|
820
|
+
WrapComputePass(isolate, encoder.BeginComputePass(&desc)));
|
|
821
|
+
}
|
|
822
|
+
|
|
551
823
|
static void Encoder_Finish(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
552
824
|
{
|
|
553
825
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -575,8 +847,7 @@ static wgpu::TexelCopyTextureInfo ParseTexelCopyTexture(v8::Isolate* isolate, v8
|
|
|
575
847
|
info.mipLevel = U32(isolate, o, "mipLevel", 0);
|
|
576
848
|
v8::Local<v8::Value> origin = Prop(isolate, o, "origin");
|
|
577
849
|
if (origin->IsObject() || origin->IsArray()) {
|
|
578
|
-
|
|
579
|
-
info.origin = { e.width, e.height, e.depthOrArrayLayers };
|
|
850
|
+
info.origin = ParseOrigin(isolate, origin);
|
|
580
851
|
}
|
|
581
852
|
return info;
|
|
582
853
|
}
|
|
@@ -608,6 +879,187 @@ static void Encoder_CopyTextureToBuffer(const v8::FunctionCallbackInfo<v8::Value
|
|
|
608
879
|
encoder.CopyTextureToBuffer(&src, &dst, &size);
|
|
609
880
|
}
|
|
610
881
|
|
|
882
|
+
static void Encoder_ResolveQuerySet(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
883
|
+
{
|
|
884
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
885
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
886
|
+
auto& qs = Unwrap<wgpu::QuerySet>(args[0].As<v8::Object>());
|
|
887
|
+
uint32_t first = static_cast<uint32_t>(args[1].As<v8::Number>()->Value());
|
|
888
|
+
uint32_t count = static_cast<uint32_t>(args[2].As<v8::Number>()->Value());
|
|
889
|
+
auto& dst = Unwrap<wgpu::Buffer>(args[3].As<v8::Object>());
|
|
890
|
+
uint64_t dst_off = args.Length() > 4 && args[4]->IsNumber()
|
|
891
|
+
? static_cast<uint64_t>(args[4].As<v8::Number>()->Value()) : 0;
|
|
892
|
+
(void) isolate;
|
|
893
|
+
encoder.ResolveQuerySet(qs, first, count, dst, dst_off);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
static void Encoder_WriteTimestamp(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
897
|
+
{
|
|
898
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
899
|
+
auto& qs = Unwrap<wgpu::QuerySet>(args[0].As<v8::Object>());
|
|
900
|
+
uint32_t index = static_cast<uint32_t>(args[1].As<v8::Number>()->Value());
|
|
901
|
+
encoder.WriteTimestamp(qs, index);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
static void Encoder_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
905
|
+
{
|
|
906
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
907
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
908
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).PushDebugGroup(
|
|
909
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
static void Encoder_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
913
|
+
{
|
|
914
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).PopDebugGroup();
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
static void Encoder_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
918
|
+
{
|
|
919
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
920
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
921
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).InsertDebugMarker(
|
|
922
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// ---------------------------------------------------------------------------
|
|
926
|
+
// GPURenderBundleEncoder (createRenderBundleEncoder -> finish -> GPURenderBundle)
|
|
927
|
+
// ---------------------------------------------------------------------------
|
|
928
|
+
static void RBEncoder_SetPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
929
|
+
{
|
|
930
|
+
Unwrap<wgpu::RenderBundleEncoder>(args.This()).SetPipeline(
|
|
931
|
+
Unwrap<wgpu::RenderPipeline>(args[0].As<v8::Object>()));
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
static void RBEncoder_SetBindGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
935
|
+
{
|
|
936
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
937
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
938
|
+
uint32_t index = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
939
|
+
if (args.Length() < 2 || !args[1]->IsObject()) {
|
|
940
|
+
enc.SetBindGroup(index, nullptr);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
auto& group = Unwrap<wgpu::BindGroup>(args[1].As<v8::Object>());
|
|
944
|
+
std::vector<uint32_t> offsets;
|
|
945
|
+
if (args.Length() > 2 && !args[2]->IsNullOrUndefined()) {
|
|
946
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
947
|
+
if (args[2]->IsArray()) {
|
|
948
|
+
auto arr = args[2].As<v8::Array>();
|
|
949
|
+
offsets.reserve(arr->Length());
|
|
950
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
951
|
+
v8::Local<v8::Value> v;
|
|
952
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
953
|
+
offsets.push_back(static_cast<uint32_t>(v.As<v8::Number>()->Value()));
|
|
954
|
+
}
|
|
955
|
+
} else if (args[2]->IsUint32Array()) {
|
|
956
|
+
auto ta = args[2].As<v8::Uint32Array>();
|
|
957
|
+
offsets.resize(ta->Length());
|
|
958
|
+
ta->CopyContents(offsets.data(), offsets.size() * sizeof(uint32_t));
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
enc.SetBindGroup(index, group, static_cast<uint32_t>(offsets.size()),
|
|
962
|
+
offsets.empty() ? nullptr : offsets.data());
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
static void RBEncoder_SetVertexBuffer(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
966
|
+
{
|
|
967
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
968
|
+
uint32_t slot = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
969
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[1].As<v8::Object>());
|
|
970
|
+
uint64_t offset = args.Length() > 2 && args[2]->IsNumber()
|
|
971
|
+
? static_cast<uint64_t>(args[2].As<v8::Number>()->Value()) : 0;
|
|
972
|
+
uint64_t size = args.Length() > 3 && args[3]->IsNumber()
|
|
973
|
+
? static_cast<uint64_t>(args[3].As<v8::Number>()->Value()) : wgpu::kWholeSize;
|
|
974
|
+
enc.SetVertexBuffer(slot, buffer, offset, size);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
static void RBEncoder_SetIndexBuffer(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
978
|
+
{
|
|
979
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
980
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
981
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
982
|
+
wgpu::IndexFormat format = ToIndexFormat(v8util::ToStdString(isolate, args[1]));
|
|
983
|
+
uint64_t offset = args.Length() > 2 && args[2]->IsNumber()
|
|
984
|
+
? static_cast<uint64_t>(args[2].As<v8::Number>()->Value()) : 0;
|
|
985
|
+
uint64_t size = args.Length() > 3 && args[3]->IsNumber()
|
|
986
|
+
? static_cast<uint64_t>(args[3].As<v8::Number>()->Value()) : wgpu::kWholeSize;
|
|
987
|
+
enc.SetIndexBuffer(buffer, format, offset, size);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
static void RBEncoder_Draw(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
991
|
+
{
|
|
992
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
993
|
+
auto n = [&](int i, uint32_t fb) {
|
|
994
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
995
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
996
|
+
enc.Draw(n(0, 0), n(1, 1), n(2, 0), n(3, 0));
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
static void RBEncoder_DrawIndexed(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1000
|
+
{
|
|
1001
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1002
|
+
auto n = [&](int i, uint32_t fb) {
|
|
1003
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
1004
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
1005
|
+
enc.DrawIndexed(n(0, 0), n(1, 1), n(2, 0), n(3, 0), n(4, 0));
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
static void RBEncoder_DrawIndirect(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1009
|
+
{
|
|
1010
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1011
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
1012
|
+
uint64_t offset = args.Length() > 1 && args[1]->IsNumber()
|
|
1013
|
+
? static_cast<uint64_t>(args[1].As<v8::Number>()->Value()) : 0;
|
|
1014
|
+
enc.DrawIndirect(buffer, offset);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
static void RBEncoder_Finish(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1018
|
+
{
|
|
1019
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1020
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1021
|
+
wgpu::RenderBundleDescriptor desc = {};
|
|
1022
|
+
args.GetReturnValue().Set(WrapRenderBundle(isolate, enc.Finish(&desc)));
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
static v8::Local<v8::Object> WrapRenderBundleEncoder(v8::Isolate* isolate, wgpu::RenderBundleEncoder enc)
|
|
1026
|
+
{
|
|
1027
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).renderBundleEncoder, std::move(enc));
|
|
1028
|
+
SetMethod(isolate, obj, "setPipeline", RBEncoder_SetPipeline);
|
|
1029
|
+
SetMethod(isolate, obj, "setBindGroup", RBEncoder_SetBindGroup);
|
|
1030
|
+
SetMethod(isolate, obj, "setVertexBuffer", RBEncoder_SetVertexBuffer);
|
|
1031
|
+
SetMethod(isolate, obj, "setIndexBuffer", RBEncoder_SetIndexBuffer);
|
|
1032
|
+
SetMethod(isolate, obj, "draw", RBEncoder_Draw);
|
|
1033
|
+
SetMethod(isolate, obj, "drawIndexed", RBEncoder_DrawIndexed);
|
|
1034
|
+
SetMethod(isolate, obj, "drawIndirect", RBEncoder_DrawIndirect);
|
|
1035
|
+
SetMethod(isolate, obj, "finish", RBEncoder_Finish);
|
|
1036
|
+
return obj;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
static v8::Local<v8::Object> WrapRenderBundle(v8::Isolate* isolate, wgpu::RenderBundle bundle)
|
|
1040
|
+
{
|
|
1041
|
+
return WrapWith(isolate, Tmpl(isolate).renderBundle, std::move(bundle));
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// ---------------------------------------------------------------------------
|
|
1045
|
+
// GPUQuerySet
|
|
1046
|
+
// ---------------------------------------------------------------------------
|
|
1047
|
+
static void QuerySet_Destroy(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1048
|
+
{
|
|
1049
|
+
Unwrap<wgpu::QuerySet>(args.This()).Destroy();
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
static v8::Local<v8::Object> WrapQuerySet(v8::Isolate* isolate, wgpu::QuerySet qs)
|
|
1053
|
+
{
|
|
1054
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).querySet, std::move(qs));
|
|
1055
|
+
auto& q = Unwrap<wgpu::QuerySet>(obj);
|
|
1056
|
+
SetValue(isolate, obj, "count", v8::Integer::NewFromUnsigned(isolate, q.GetCount()));
|
|
1057
|
+
SetValue(isolate, obj, "type",
|
|
1058
|
+
Str(isolate, q.GetType() == wgpu::QueryType::Timestamp ? "timestamp" : "occlusion"));
|
|
1059
|
+
SetMethod(isolate, obj, "destroy", QuerySet_Destroy);
|
|
1060
|
+
return obj;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
611
1063
|
// ---------------------------------------------------------------------------
|
|
612
1064
|
// GPUCanvasContext
|
|
613
1065
|
// ---------------------------------------------------------------------------
|
|
@@ -617,6 +1069,11 @@ static void Ctx_Configure(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
617
1069
|
DawnContext* gpu = HostContext::From(isolate)->gpu;
|
|
618
1070
|
// device は既に DawnContext が保持。フォーマット/サイズのみ反映する。
|
|
619
1071
|
if (args.Length() > 0 && args[0]->IsObject()) {
|
|
1072
|
+
static uint64_t count = 0;
|
|
1073
|
+
++count;
|
|
1074
|
+
if (count <= 10 || count % 300 == 0) {
|
|
1075
|
+
std::cerr << "[GPU] context.configure #" << count << std::endl;
|
|
1076
|
+
}
|
|
620
1077
|
// width/height は canvas サイズを使用 (configure の size は任意)
|
|
621
1078
|
gpu->Configure(gpu->width(), gpu->height());
|
|
622
1079
|
}
|
|
@@ -626,6 +1083,11 @@ static void Ctx_GetCurrentTexture(const v8::FunctionCallbackInfo<v8::Value>& arg
|
|
|
626
1083
|
{
|
|
627
1084
|
v8::Isolate* isolate = args.GetIsolate();
|
|
628
1085
|
DawnContext* gpu = HostContext::From(isolate)->gpu;
|
|
1086
|
+
static uint64_t count = 0;
|
|
1087
|
+
++count;
|
|
1088
|
+
if (count <= 10 || count % 300 == 0) {
|
|
1089
|
+
std::cerr << "[GPU] getCurrentTexture #" << count << std::endl;
|
|
1090
|
+
}
|
|
629
1091
|
args.GetReturnValue().Set(WrapTexture(isolate, gpu->GetCurrentTexture()));
|
|
630
1092
|
}
|
|
631
1093
|
|
|
@@ -881,17 +1343,62 @@ struct RenderPipelineScratch {
|
|
|
881
1343
|
std::vector<wgpu::ColorTargetState> targets;
|
|
882
1344
|
std::vector<wgpu::BlendState> blends;
|
|
883
1345
|
std::string vs_entry, fs_entry;
|
|
1346
|
+
// pipeline-overridable constants (WGSL の override 定数)。key 文字列は
|
|
1347
|
+
// ConstantEntry.key が指すため CreateRenderPipeline 完了まで生存させる。
|
|
1348
|
+
std::vector<std::string> vs_const_keys, fs_const_keys;
|
|
1349
|
+
std::vector<wgpu::ConstantEntry> vs_constants, fs_constants;
|
|
884
1350
|
};
|
|
885
1351
|
|
|
886
|
-
|
|
1352
|
+
// { "KEY": number|bool, ... } を wgpu::ConstantEntry 配列へ変換する。
|
|
1353
|
+
// player は WGSL の override(GRADIENT_TYPE / SPREAD_MODE / yFlipSign / フィルタ種別など)
|
|
1354
|
+
// を constants で指定してパイプラインを特殊化する。ここを読まないと全パイプラインが
|
|
1355
|
+
// WGSL の既定値でコンパイルされ、放射状グラデが線形に、spread が pad に、
|
|
1356
|
+
// フィルタ種別が既定分岐に潰れる (エラーは出ない)。
|
|
1357
|
+
static void ParsePipelineConstants(
|
|
1358
|
+
v8::Isolate* isolate, v8::Local<v8::Object> stage,
|
|
1359
|
+
std::vector<std::string>& keys, std::vector<wgpu::ConstantEntry>& entries)
|
|
887
1360
|
{
|
|
888
|
-
v8::Isolate* isolate = args.GetIsolate();
|
|
889
1361
|
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
890
|
-
|
|
891
|
-
|
|
1362
|
+
v8::Local<v8::Value> cv = Prop(isolate, stage, "constants");
|
|
1363
|
+
if (!cv->IsObject()) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
auto co = cv.As<v8::Object>();
|
|
1367
|
+
v8::Local<v8::Array> names;
|
|
1368
|
+
if (!co->GetOwnPropertyNames(ctx).ToLocal(&names)) {
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
// 再確保で ConstantEntry.key の指す c_str が無効化されないよう上限で確保する。
|
|
1372
|
+
keys.reserve(keys.size() + names->Length());
|
|
1373
|
+
entries.reserve(entries.size() + names->Length());
|
|
1374
|
+
for (uint32_t i = 0; i < names->Length(); ++i) {
|
|
1375
|
+
v8::Local<v8::Value> k, val;
|
|
1376
|
+
if (!names->Get(ctx, i).ToLocal(&k)) continue;
|
|
1377
|
+
if (!co->Get(ctx, k).ToLocal(&val)) continue;
|
|
1378
|
+
double num;
|
|
1379
|
+
if (val->IsBoolean()) {
|
|
1380
|
+
num = val.As<v8::Boolean>()->Value() ? 1.0 : 0.0;
|
|
1381
|
+
} else if (val->IsNumber()) {
|
|
1382
|
+
num = val.As<v8::Number>()->Value();
|
|
1383
|
+
} else {
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
v8::String::Utf8Value ks(isolate, k);
|
|
1387
|
+
if (!*ks) continue;
|
|
1388
|
+
keys.emplace_back(*ks, static_cast<size_t>(ks.length()));
|
|
1389
|
+
wgpu::ConstantEntry e = {};
|
|
1390
|
+
e.key = wgpu::StringView(keys.back().c_str(), keys.back().size());
|
|
1391
|
+
e.value = num;
|
|
1392
|
+
entries.push_back(e);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
892
1395
|
|
|
893
|
-
|
|
894
|
-
|
|
1396
|
+
// ディスクリプタ構築 (sync/async 双方から使う。desc/scratch は呼び出し側が保持し、
|
|
1397
|
+
// CreateRenderPipeline[Async] が同期コピーするまで生存させる)。
|
|
1398
|
+
static void FillRenderPipelineDescriptor(v8::Isolate* isolate, v8::Local<v8::Object> d,
|
|
1399
|
+
RenderPipelineScratch& scratch, wgpu::RenderPipelineDescriptor& desc)
|
|
1400
|
+
{
|
|
1401
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
895
1402
|
|
|
896
1403
|
// layout: 'auto' or GPUPipelineLayout
|
|
897
1404
|
v8::Local<v8::Value> layout = Prop(isolate, d, "layout");
|
|
@@ -944,6 +1451,13 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
944
1451
|
desc.vertex.buffers = scratch.vertex_buffers.data();
|
|
945
1452
|
}
|
|
946
1453
|
|
|
1454
|
+
// vertex.constants (override 定数)
|
|
1455
|
+
ParsePipelineConstants(isolate, vertex, scratch.vs_const_keys, scratch.vs_constants);
|
|
1456
|
+
if (!scratch.vs_constants.empty()) {
|
|
1457
|
+
desc.vertex.constantCount = scratch.vs_constants.size();
|
|
1458
|
+
desc.vertex.constants = scratch.vs_constants.data();
|
|
1459
|
+
}
|
|
1460
|
+
|
|
947
1461
|
// primitive
|
|
948
1462
|
v8::Local<v8::Value> prim = Prop(isolate, d, "primitive");
|
|
949
1463
|
if (prim->IsObject()) {
|
|
@@ -1008,6 +1522,13 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
1008
1522
|
if (ms->IsObject()) {
|
|
1009
1523
|
auto m = ms.As<v8::Object>();
|
|
1010
1524
|
desc.multisample.count = U32(isolate, m, "count", 1);
|
|
1525
|
+
// alphaToCoverageEnabled: フラグメント alpha を MSAA カバレッジへ変換する。
|
|
1526
|
+
// Next2D はベクタ図形の境界を塗り alpha に頼るため、これが無いと全図形の
|
|
1527
|
+
// アンチエイリアスが失われて縁がジャギる (静かな品質劣化)。
|
|
1528
|
+
desc.multisample.alphaToCoverageEnabled = Bool(isolate, m, "alphaToCoverageEnabled", false);
|
|
1529
|
+
if (HasProp(isolate, m, "mask")) {
|
|
1530
|
+
desc.multisample.mask = U32(isolate, m, "mask", 0xFFFFFFFF);
|
|
1531
|
+
}
|
|
1011
1532
|
}
|
|
1012
1533
|
|
|
1013
1534
|
// fragment
|
|
@@ -1053,12 +1574,223 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
1053
1574
|
fragment.targetCount = scratch.targets.size();
|
|
1054
1575
|
fragment.targets = scratch.targets.data();
|
|
1055
1576
|
}
|
|
1577
|
+
|
|
1578
|
+
// fragment.constants (override 定数: GRADIENT_TYPE/SPREAD_MODE/フィルタ種別など)
|
|
1579
|
+
ParsePipelineConstants(isolate, f, scratch.fs_const_keys, scratch.fs_constants);
|
|
1580
|
+
if (!scratch.fs_constants.empty()) {
|
|
1581
|
+
fragment.constantCount = scratch.fs_constants.size();
|
|
1582
|
+
fragment.constants = scratch.fs_constants.data();
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1056
1585
|
desc.fragment = &fragment;
|
|
1057
1586
|
}
|
|
1587
|
+
}
|
|
1058
1588
|
|
|
1589
|
+
static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1590
|
+
{
|
|
1591
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1592
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1593
|
+
RenderPipelineScratch scratch;
|
|
1594
|
+
wgpu::RenderPipelineDescriptor desc = {};
|
|
1595
|
+
FillRenderPipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1059
1596
|
args.GetReturnValue().Set(WrapPipeline(isolate, device.CreateRenderPipeline(&desc)));
|
|
1060
1597
|
}
|
|
1061
1598
|
|
|
1599
|
+
// ---------------------------------------------------------------------------
|
|
1600
|
+
// GPUDevice.createComputePipeline
|
|
1601
|
+
// { layout: 'auto'|GPUPipelineLayout, compute: {module, entryPoint?, constants?} }
|
|
1602
|
+
// ---------------------------------------------------------------------------
|
|
1603
|
+
// compute ディスクリプタ構築 (sync/async 共有)。entryPoint/constants の文字列寿命は
|
|
1604
|
+
// 呼び出し側が保持する keys/entry_strs で管理する。
|
|
1605
|
+
struct ComputePipelineScratch {
|
|
1606
|
+
std::string cs_entry;
|
|
1607
|
+
std::vector<std::string> cs_const_keys;
|
|
1608
|
+
std::vector<wgpu::ConstantEntry> cs_constants;
|
|
1609
|
+
};
|
|
1610
|
+
|
|
1611
|
+
static void FillComputePipelineDescriptor(v8::Isolate* isolate, v8::Local<v8::Object> d,
|
|
1612
|
+
ComputePipelineScratch& scratch, wgpu::ComputePipelineDescriptor& desc)
|
|
1613
|
+
{
|
|
1614
|
+
v8::Local<v8::Value> layout = Prop(isolate, d, "layout");
|
|
1615
|
+
if (layout->IsObject()) {
|
|
1616
|
+
desc.layout = Unwrap<wgpu::PipelineLayout>(layout.As<v8::Object>());
|
|
1617
|
+
}
|
|
1618
|
+
v8::Local<v8::Object> compute = Prop(isolate, d, "compute").As<v8::Object>();
|
|
1619
|
+
desc.compute.module = Unwrap<wgpu::ShaderModule>(Prop(isolate, compute, "module").As<v8::Object>());
|
|
1620
|
+
scratch.cs_entry = webgpu::Str(isolate, compute, "entryPoint");
|
|
1621
|
+
if (!scratch.cs_entry.empty()) {
|
|
1622
|
+
desc.compute.entryPoint = wgpu::StringView(scratch.cs_entry.c_str(), scratch.cs_entry.size());
|
|
1623
|
+
}
|
|
1624
|
+
ParsePipelineConstants(isolate, compute, scratch.cs_const_keys, scratch.cs_constants);
|
|
1625
|
+
if (!scratch.cs_constants.empty()) {
|
|
1626
|
+
desc.compute.constantCount = scratch.cs_constants.size();
|
|
1627
|
+
desc.compute.constants = scratch.cs_constants.data();
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
static void Device_CreateComputePipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1632
|
+
{
|
|
1633
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1634
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1635
|
+
ComputePipelineScratch scratch;
|
|
1636
|
+
wgpu::ComputePipelineDescriptor desc = {};
|
|
1637
|
+
FillComputePipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1638
|
+
args.GetReturnValue().Set(
|
|
1639
|
+
WrapComputePipeline(isolate, device.CreateComputePipeline(&desc)));
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// createRenderPipelineAsync / createComputePipelineAsync -> Promise<GPU*Pipeline>
|
|
1643
|
+
// Dawn C++ の Future 版 (CallbackMode::AllowProcessEvents で event loop が処理)。
|
|
1644
|
+
// ディスクリプタは呼び出し時に同期コピーされるため scratch はスタックで足りる。
|
|
1645
|
+
static void Device_CreateRenderPipelineAsync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1646
|
+
{
|
|
1647
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1648
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1649
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1650
|
+
RenderPipelineScratch scratch;
|
|
1651
|
+
wgpu::RenderPipelineDescriptor desc = {};
|
|
1652
|
+
FillRenderPipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1653
|
+
|
|
1654
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1655
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1656
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1657
|
+
|
|
1658
|
+
device.CreateRenderPipelineAsync(&desc, wgpu::CallbackMode::AllowProcessEvents,
|
|
1659
|
+
[isolate, persistent](wgpu::CreatePipelineAsyncStatus status,
|
|
1660
|
+
wgpu::RenderPipeline pipeline, wgpu::StringView) {
|
|
1661
|
+
v8::HandleScope scope(isolate);
|
|
1662
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1663
|
+
auto r = persistent->Get(isolate);
|
|
1664
|
+
if (status == wgpu::CreatePipelineAsyncStatus::Success) {
|
|
1665
|
+
r->Resolve(c, WrapPipeline(isolate, pipeline)).Check();
|
|
1666
|
+
} else {
|
|
1667
|
+
r->Reject(c, v8::Exception::Error(
|
|
1668
|
+
v8util::Str(isolate, "createRenderPipelineAsync failed"))).Check();
|
|
1669
|
+
}
|
|
1670
|
+
persistent->Reset(); delete persistent;
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
static void Device_CreateComputePipelineAsync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1675
|
+
{
|
|
1676
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1677
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1678
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1679
|
+
ComputePipelineScratch scratch;
|
|
1680
|
+
wgpu::ComputePipelineDescriptor desc = {};
|
|
1681
|
+
FillComputePipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1682
|
+
|
|
1683
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1684
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1685
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1686
|
+
|
|
1687
|
+
device.CreateComputePipelineAsync(&desc, wgpu::CallbackMode::AllowProcessEvents,
|
|
1688
|
+
[isolate, persistent](wgpu::CreatePipelineAsyncStatus status,
|
|
1689
|
+
wgpu::ComputePipeline pipeline, wgpu::StringView) {
|
|
1690
|
+
v8::HandleScope scope(isolate);
|
|
1691
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1692
|
+
auto r = persistent->Get(isolate);
|
|
1693
|
+
if (status == wgpu::CreatePipelineAsyncStatus::Success) {
|
|
1694
|
+
r->Resolve(c, WrapComputePipeline(isolate, pipeline)).Check();
|
|
1695
|
+
} else {
|
|
1696
|
+
r->Reject(c, v8::Exception::Error(
|
|
1697
|
+
v8util::Str(isolate, "createComputePipelineAsync failed"))).Check();
|
|
1698
|
+
}
|
|
1699
|
+
persistent->Reset(); delete persistent;
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// createQuerySet({ type: 'occlusion'|'timestamp', count })
|
|
1704
|
+
static void Device_CreateQuerySet(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1705
|
+
{
|
|
1706
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1707
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1708
|
+
v8::Local<v8::Object> d = args[0].As<v8::Object>();
|
|
1709
|
+
wgpu::QuerySetDescriptor desc = {};
|
|
1710
|
+
desc.type = ToQueryType(webgpu::Str(isolate, d, "type"));
|
|
1711
|
+
desc.count = U32(isolate, d, "count", 0);
|
|
1712
|
+
args.GetReturnValue().Set(WrapQuerySet(isolate, device.CreateQuerySet(&desc)));
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// createRenderBundleEncoder({ colorFormats[], depthStencilFormat?, sampleCount?, ... })
|
|
1716
|
+
static void Device_CreateRenderBundleEncoder(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1717
|
+
{
|
|
1718
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1719
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1720
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1721
|
+
v8::Local<v8::Object> d = args[0].As<v8::Object>();
|
|
1722
|
+
|
|
1723
|
+
std::vector<wgpu::TextureFormat> formats;
|
|
1724
|
+
v8::Local<v8::Value> cf = Prop(isolate, d, "colorFormats");
|
|
1725
|
+
if (cf->IsArray()) {
|
|
1726
|
+
auto arr = cf.As<v8::Array>();
|
|
1727
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
1728
|
+
v8::Local<v8::Value> v;
|
|
1729
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsString()) {
|
|
1730
|
+
formats.push_back(ToTextureFormat(v8util::ToStdString(isolate, v)));
|
|
1731
|
+
} else {
|
|
1732
|
+
formats.push_back(wgpu::TextureFormat::Undefined); // ギャップ (null)
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
wgpu::RenderBundleEncoderDescriptor desc = {};
|
|
1738
|
+
desc.colorFormatCount = formats.size();
|
|
1739
|
+
desc.colorFormats = formats.data();
|
|
1740
|
+
if (HasProp(isolate, d, "depthStencilFormat")) {
|
|
1741
|
+
desc.depthStencilFormat = ToTextureFormat(webgpu::Str(isolate, d, "depthStencilFormat"));
|
|
1742
|
+
}
|
|
1743
|
+
desc.sampleCount = U32(isolate, d, "sampleCount", 1);
|
|
1744
|
+
desc.depthReadOnly = Bool(isolate, d, "depthReadOnly", false);
|
|
1745
|
+
desc.stencilReadOnly = Bool(isolate, d, "stencilReadOnly", false);
|
|
1746
|
+
|
|
1747
|
+
args.GetReturnValue().Set(
|
|
1748
|
+
WrapRenderBundleEncoder(isolate, device.CreateRenderBundleEncoder(&desc)));
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
// pushErrorScope(filter) / popErrorScope() -> Promise<GPUError|null>
|
|
1752
|
+
static void Device_PushErrorScope(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1753
|
+
{
|
|
1754
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1755
|
+
wgpu::ErrorFilter filter = ToErrorFilter(
|
|
1756
|
+
args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "validation");
|
|
1757
|
+
Unwrap<wgpu::Device>(args.This()).PushErrorScope(filter);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
static void Device_PopErrorScope(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1761
|
+
{
|
|
1762
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1763
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1764
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1765
|
+
|
|
1766
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1767
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1768
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1769
|
+
|
|
1770
|
+
device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents,
|
|
1771
|
+
[isolate, persistent](wgpu::PopErrorScopeStatus, wgpu::ErrorType type, wgpu::StringView message) {
|
|
1772
|
+
v8::HandleScope scope(isolate);
|
|
1773
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1774
|
+
auto r = persistent->Get(isolate);
|
|
1775
|
+
if (type == wgpu::ErrorType::NoError) {
|
|
1776
|
+
r->Resolve(c, v8::Null(isolate)).Check();
|
|
1777
|
+
} else {
|
|
1778
|
+
// GPUError 相当のオブジェクト ({ message, __errorType })
|
|
1779
|
+
v8::Local<v8::Object> err = v8::Object::New(isolate);
|
|
1780
|
+
std::string msg(message.data ? message.data : "", message.length);
|
|
1781
|
+
SetValue(isolate, err, "message", v8util::Str(isolate, msg.c_str()));
|
|
1782
|
+
SetValue(isolate, err, "__errorType", v8util::Str(isolate, ErrorTypeName(type)));
|
|
1783
|
+
r->Resolve(c, err).Check();
|
|
1784
|
+
}
|
|
1785
|
+
persistent->Reset(); delete persistent;
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
static void Device_Destroy(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1790
|
+
{
|
|
1791
|
+
Unwrap<wgpu::Device>(args.This()).Destroy();
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1062
1794
|
static void Device_CreateCommandEncoder(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1063
1795
|
{
|
|
1064
1796
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -1106,10 +1838,16 @@ static v8::Local<v8::Object> WrapEncoder(v8::Isolate* isolate, wgpu::CommandEnco
|
|
|
1106
1838
|
{
|
|
1107
1839
|
auto obj = WrapWith(isolate, Tmpl(isolate).commandEncoder, std::move(encoder));
|
|
1108
1840
|
SetMethod(isolate, obj, "beginRenderPass", Encoder_BeginRenderPass);
|
|
1841
|
+
SetMethod(isolate, obj, "beginComputePass", Encoder_BeginComputePass);
|
|
1109
1842
|
SetMethod(isolate, obj, "finish", Encoder_Finish);
|
|
1110
1843
|
SetMethod(isolate, obj, "copyBufferToBuffer", Encoder_CopyBufferToBuffer);
|
|
1111
1844
|
SetMethod(isolate, obj, "copyTextureToTexture", Encoder_CopyTextureToTexture);
|
|
1112
1845
|
SetMethod(isolate, obj, "copyTextureToBuffer", Encoder_CopyTextureToBuffer);
|
|
1846
|
+
SetMethod(isolate, obj, "resolveQuerySet", Encoder_ResolveQuerySet);
|
|
1847
|
+
SetMethod(isolate, obj, "writeTimestamp", Encoder_WriteTimestamp);
|
|
1848
|
+
SetMethod(isolate, obj, "pushDebugGroup", Encoder_PushDebugGroup);
|
|
1849
|
+
SetMethod(isolate, obj, "popDebugGroup", Encoder_PopDebugGroup);
|
|
1850
|
+
SetMethod(isolate, obj, "insertDebugMarker", Encoder_InsertDebugMarker);
|
|
1113
1851
|
return obj;
|
|
1114
1852
|
}
|
|
1115
1853
|
|
|
@@ -1120,9 +1858,45 @@ static v8::Local<v8::Object> WrapPipeline(v8::Isolate* isolate, wgpu::RenderPipe
|
|
|
1120
1858
|
return obj;
|
|
1121
1859
|
}
|
|
1122
1860
|
|
|
1861
|
+
static void ComputePipeline_GetBindGroupLayout(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1862
|
+
{
|
|
1863
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1864
|
+
auto& pipeline = Unwrap<wgpu::ComputePipeline>(args.This());
|
|
1865
|
+
uint32_t index = args.Length() > 0 && args[0]->IsNumber()
|
|
1866
|
+
? static_cast<uint32_t>(args[0].As<v8::Number>()->Value()) : 0;
|
|
1867
|
+
args.GetReturnValue().Set(
|
|
1868
|
+
WrapWith(isolate, Tmpl(isolate).bindGroupLayout, pipeline.GetBindGroupLayout(index)));
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
static v8::Local<v8::Object> WrapComputePipeline(v8::Isolate* isolate, wgpu::ComputePipeline pipeline)
|
|
1872
|
+
{
|
|
1873
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).computePipeline, std::move(pipeline));
|
|
1874
|
+
SetMethod(isolate, obj, "getBindGroupLayout", ComputePipeline_GetBindGroupLayout);
|
|
1875
|
+
return obj;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1123
1878
|
// ---------------------------------------------------------------------------
|
|
1124
1879
|
// GPUDevice / GPUQueue / GPUAdapter のラップ
|
|
1125
1880
|
// ---------------------------------------------------------------------------
|
|
1881
|
+
static void Queue_OnSubmittedWorkDone(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1882
|
+
{
|
|
1883
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1884
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1885
|
+
auto& queue = Unwrap<wgpu::Queue>(args.This());
|
|
1886
|
+
|
|
1887
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1888
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1889
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1890
|
+
|
|
1891
|
+
queue.OnSubmittedWorkDone(wgpu::CallbackMode::AllowProcessEvents,
|
|
1892
|
+
[isolate, persistent](wgpu::QueueWorkDoneStatus, wgpu::StringView) {
|
|
1893
|
+
v8::HandleScope scope(isolate);
|
|
1894
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1895
|
+
persistent->Get(isolate)->Resolve(c, v8::Undefined(isolate)).Check();
|
|
1896
|
+
persistent->Reset(); delete persistent;
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1126
1900
|
static v8::Local<v8::Object> WrapQueue(v8::Isolate* isolate, wgpu::Queue queue)
|
|
1127
1901
|
{
|
|
1128
1902
|
auto obj = WrapWith(isolate, Tmpl(isolate).queue, std::move(queue));
|
|
@@ -1130,6 +1904,7 @@ static v8::Local<v8::Object> WrapQueue(v8::Isolate* isolate, wgpu::Queue queue)
|
|
|
1130
1904
|
SetMethod(isolate, obj, "writeBuffer", Queue_WriteBuffer);
|
|
1131
1905
|
SetMethod(isolate, obj, "writeTexture", Queue_WriteTexture);
|
|
1132
1906
|
SetMethod(isolate, obj, "copyExternalImageToTexture", Queue_CopyExternalImageToTexture);
|
|
1907
|
+
SetMethod(isolate, obj, "onSubmittedWorkDone", Queue_OnSubmittedWorkDone);
|
|
1133
1908
|
return obj;
|
|
1134
1909
|
}
|
|
1135
1910
|
|
|
@@ -1144,10 +1919,26 @@ static v8::Local<v8::Object> WrapDevice(v8::Isolate* isolate, wgpu::Device devic
|
|
|
1144
1919
|
SetMethod(isolate, obj, "createBindGroup", Device_CreateBindGroup);
|
|
1145
1920
|
SetMethod(isolate, obj, "createPipelineLayout", Device_CreatePipelineLayout);
|
|
1146
1921
|
SetMethod(isolate, obj, "createRenderPipeline", Device_CreateRenderPipeline);
|
|
1922
|
+
SetMethod(isolate, obj, "createComputePipeline", Device_CreateComputePipeline);
|
|
1923
|
+
SetMethod(isolate, obj, "createRenderPipelineAsync", Device_CreateRenderPipelineAsync);
|
|
1924
|
+
SetMethod(isolate, obj, "createComputePipelineAsync", Device_CreateComputePipelineAsync);
|
|
1147
1925
|
SetMethod(isolate, obj, "createCommandEncoder", Device_CreateCommandEncoder);
|
|
1926
|
+
SetMethod(isolate, obj, "createQuerySet", Device_CreateQuerySet);
|
|
1927
|
+
SetMethod(isolate, obj, "createRenderBundleEncoder", Device_CreateRenderBundleEncoder);
|
|
1928
|
+
SetMethod(isolate, obj, "pushErrorScope", Device_PushErrorScope);
|
|
1929
|
+
SetMethod(isolate, obj, "popErrorScope", Device_PopErrorScope);
|
|
1930
|
+
SetMethod(isolate, obj, "destroy", Device_Destroy);
|
|
1148
1931
|
SetValue(isolate, obj, "queue", WrapQueue(isolate, device.GetQueue()));
|
|
1149
1932
|
SetValue(isolate, obj, "features", v8::Object::New(isolate));
|
|
1150
1933
|
|
|
1934
|
+
// device.lost: Promise<GPUDeviceLostInfo>。デバイス生存中は pending (spec 準拠)。
|
|
1935
|
+
// 実際のロストは Dawn の deviceLost コールバック経路 (DawnContext 側) に委ねる。
|
|
1936
|
+
{
|
|
1937
|
+
v8::Local<v8::Context> lctx = isolate->GetCurrentContext();
|
|
1938
|
+
auto lost = v8::Promise::Resolver::New(lctx).ToLocalChecked();
|
|
1939
|
+
SetValue(isolate, obj, "lost", lost->GetPromise());
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1151
1942
|
// limits: player は maxTextureDimension2D で描画最大サイズを決めるため実値を返す。
|
|
1152
1943
|
// GetLimits の戻り値型は Dawn バージョン差があるため値でガードする(0 なら保証最小値)。
|
|
1153
1944
|
v8::Local<v8::Object> limits = v8::Object::New(isolate);
|
|
@@ -1224,6 +2015,8 @@ static void InitTemplates(v8::Isolate* isolate)
|
|
|
1224
2015
|
make(t.textureView); make(t.sampler); make(t.shaderModule); make(t.bindGroupLayout);
|
|
1225
2016
|
make(t.bindGroup); make(t.pipelineLayout); make(t.renderPipeline); make(t.commandEncoder);
|
|
1226
2017
|
make(t.renderPass); make(t.commandBuffer); make(t.canvasContext);
|
|
2018
|
+
make(t.computePipeline); make(t.computePass);
|
|
2019
|
+
make(t.querySet); make(t.renderBundle); make(t.renderBundleEncoder);
|
|
1227
2020
|
}
|
|
1228
2021
|
|
|
1229
2022
|
static void SetFlag(v8::Isolate* isolate, v8::Local<v8::Object> obj, const char* k, uint32_t v)
|
|
@@ -1234,6 +2027,13 @@ static void SetFlag(v8::Isolate* isolate, v8::Local<v8::Object> obj, const char*
|
|
|
1234
2027
|
} // namespace webgpu
|
|
1235
2028
|
|
|
1236
2029
|
// Bindings.h から呼ばれる公開関数
|
|
2030
|
+
// V8 破棄前に呼ぶ。テンプレートの v8::Global (static map) を解放する。
|
|
2031
|
+
// (放置すると static デストラクタが V8 破棄後に走りアクセス違反になる)
|
|
2032
|
+
void ShutdownWebGPU()
|
|
2033
|
+
{
|
|
2034
|
+
webgpu::g_templates.clear();
|
|
2035
|
+
}
|
|
2036
|
+
|
|
1237
2037
|
void InstallWebGPU(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* host)
|
|
1238
2038
|
{
|
|
1239
2039
|
using namespace next2d::webgpu;
|