@next2d/builder 0.1.7 → 0.1.10
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/cli.d.ts +59 -0
- package/dist/cli.js +141 -0
- package/dist/constants.d.ts +53 -0
- package/dist/constants.js +64 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.js +19 -0
- package/dist/electron.d.ts +10 -0
- package/dist/electron.js +142 -0
- package/dist/index.js +18 -754
- package/dist/native.d.ts +27 -0
- package/dist/native.js +123 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +40 -0
- package/dist/web.d.ts +18 -0
- package/dist/web.js +70 -0
- package/dist/xbox.d.ts +62 -0
- package/dist/xbox.js +426 -0
- package/package.json +12 -9
- package/templates/xbox/CMakeLists.txt +116 -11
- package/templates/xbox/README.md +34 -8
- package/templates/xbox/cmake/FetchDawn.cmake +47 -6
- package/templates/xbox/cmake/FindV8.cmake +15 -0
- package/templates/xbox/js/bootstrap.js +151 -28
- package/templates/xbox/js/selftest.js +740 -90
- package/templates/xbox/src/AssetLoader.cpp +115 -12
- package/templates/xbox/src/AssetLoader.h +4 -0
- package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
- package/templates/xbox/src/EmbeddedAssets.h +60 -0
- package/templates/xbox/src/EventLoop.cpp +13 -1
- package/templates/xbox/src/EventLoop.h +12 -0
- package/templates/xbox/src/bindings/Audio.cpp +211 -31
- package/templates/xbox/src/bindings/Bindings.h +10 -0
- package/templates/xbox/src/bindings/Canvas.cpp +77 -2
- package/templates/xbox/src/bindings/Canvas2D.cpp +496 -43
- package/templates/xbox/src/bindings/Console.cpp +6 -1
- package/templates/xbox/src/bindings/DomShims.cpp +143 -0
- package/templates/xbox/src/bindings/EventTarget.cpp +11 -0
- package/templates/xbox/src/bindings/Fetch.cpp +2 -8
- package/templates/xbox/src/bindings/Image.cpp +243 -15
- package/templates/xbox/src/bindings/Polyfills.cpp +1226 -0
- package/templates/xbox/src/bindings/RasterCore.h +105 -1
- package/templates/xbox/src/bindings/Video.cpp +153 -10
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +844 -18
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +7 -9
- package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
- package/templates/xbox/src/gpu/DawnContext.cpp +245 -7
- package/templates/xbox/src/gpu/DawnContext.h +18 -0
- package/templates/xbox/src/main.cpp +459 -8
- package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
- package/templates/xbox/src/platform/AudioDecoder.h +18 -0
- package/templates/xbox/src/platform/AudioEngine.cpp +37 -6
- package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
- package/templates/xbox/src/platform/DecodeQueue.h +27 -0
- package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
- package/templates/xbox/src/platform/ImageDecoder.h +18 -0
- package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
- package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
- package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
- package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
- package/templates/xbox/src/v8/CodeCache.h +223 -0
- package/templates/xbox/src/v8/V8Runtime.cpp +76 -11
- package/templates/xbox/src/v8/V8Util.h +79 -0
- package/templates/xbox/src/v8/WeakHandle.h +45 -0
- package/templates/xbox/src/worker/WorkerRuntime.cpp +432 -48
- package/templates/xbox/src/worker/WorkerRuntime.h +43 -13
- package/templates/xbox/tests/check_local.sh +7 -2
- package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
- package/templates/xbox/tests/raster_test.cpp +50 -0
- package/templates/xbox/tests/windows_platform_test.cpp +75 -3
- package/templates/xbox/third_party/LICENSES.md +14 -0
- package/templates/xbox/third_party/dr_mp3.h +5412 -0
- package/templates/xbox/third_party/dr_wav.h +9131 -0
- package/templates/xbox/third_party/stb_image.h +7988 -0
- package/templates/xbox/third_party/stb_truetype.h +5079 -0
- package/templates/xbox/third_party/stb_vorbis.c +5584 -0
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
#include "gpu/DawnContext.h"
|
|
9
9
|
#include "bindings/ImageSource.h"
|
|
10
10
|
|
|
11
|
+
#include "v8/V8Util.h"
|
|
12
|
+
|
|
11
13
|
#include <cstring>
|
|
14
|
+
#include <iostream>
|
|
12
15
|
#include <map>
|
|
13
16
|
#include <vector>
|
|
14
17
|
|
|
@@ -24,7 +27,8 @@ struct Templates {
|
|
|
24
27
|
v8::Global<v8::ObjectTemplate> adapter, device, queue, buffer, texture,
|
|
25
28
|
textureView, sampler, shaderModule, bindGroupLayout, bindGroup,
|
|
26
29
|
pipelineLayout, renderPipeline, commandEncoder, renderPass,
|
|
27
|
-
commandBuffer, canvasContext
|
|
30
|
+
commandBuffer, canvasContext, computePipeline, computePass,
|
|
31
|
+
querySet, renderBundle, renderBundleEncoder;
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
static std::map<v8::Isolate*, Templates> g_templates;
|
|
@@ -47,6 +51,9 @@ static v8::Local<v8::Object> WrapTexture(v8::Isolate*, wgpu::Texture);
|
|
|
47
51
|
static v8::Local<v8::Object> WrapTextureView(v8::Isolate*, wgpu::TextureView);
|
|
48
52
|
static v8::Local<v8::Object> WrapEncoder(v8::Isolate*, wgpu::CommandEncoder);
|
|
49
53
|
static v8::Local<v8::Object> WrapPipeline(v8::Isolate*, wgpu::RenderPipeline);
|
|
54
|
+
static v8::Local<v8::Object> WrapComputePipeline(v8::Isolate*, wgpu::ComputePipeline);
|
|
55
|
+
static v8::Local<v8::Object> WrapQuerySet(v8::Isolate*, wgpu::QuerySet);
|
|
56
|
+
static v8::Local<v8::Object> WrapRenderBundle(v8::Isolate*, wgpu::RenderBundle);
|
|
50
57
|
|
|
51
58
|
// ---------------------------------------------------------------------------
|
|
52
59
|
// GPUBuffer
|
|
@@ -63,15 +70,25 @@ static void Buffer_GetMappedRange(const v8::FunctionCallbackInfo<v8::Value>& arg
|
|
|
63
70
|
: (buffer.GetSize() - offset);
|
|
64
71
|
|
|
65
72
|
void* ptr = buffer.GetMappedRange(offset, static_cast<size_t>(size));
|
|
66
|
-
if (
|
|
73
|
+
if (ptr) {
|
|
74
|
+
// 書き込み可能マップ: マップ領域を指す非所有 ArrayBuffer (unmap まで有効)
|
|
75
|
+
std::unique_ptr<v8::BackingStore> store = v8::ArrayBuffer::NewBackingStore(
|
|
76
|
+
ptr, static_cast<size_t>(size),
|
|
77
|
+
[](void*, size_t, void*) {}, nullptr);
|
|
78
|
+
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, std::move(store)));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// MapMode::Read でマップされたバッファは非 const 版が nullptr を返す仕様。
|
|
83
|
+
// GetConstMappedRange から所有コピーを返す (読み戻し copyTextureToBuffer 等の経路)。
|
|
84
|
+
const void* cptr = buffer.GetConstMappedRange(offset, static_cast<size_t>(size));
|
|
85
|
+
if (!cptr) {
|
|
67
86
|
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, 0));
|
|
68
87
|
return;
|
|
69
88
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
[](void*, size_t, void*) {}, nullptr);
|
|
74
|
-
args.GetReturnValue().Set(v8::ArrayBuffer::New(isolate, std::move(store)));
|
|
89
|
+
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, static_cast<size_t>(size));
|
|
90
|
+
memcpy(ab->GetBackingStore()->Data(), cptr, static_cast<size_t>(size));
|
|
91
|
+
args.GetReturnValue().Set(ab);
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
static void Buffer_Unmap(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
@@ -219,6 +236,55 @@ static wgpu::Extent3D ParseExtent(v8::Isolate* isolate, v8::Local<v8::Value> val
|
|
|
219
236
|
return extent;
|
|
220
237
|
}
|
|
221
238
|
|
|
239
|
+
// GPUOrigin3D は {x,y,z} オブジェクト or [x,y,z] 配列。ParseExtent とは
|
|
240
|
+
// キー名が違う (width/height ではなく x/y/z、既定は 1 ではなく 0) ため専用に扱う。
|
|
241
|
+
static wgpu::Origin3D ParseOrigin(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
|
242
|
+
{
|
|
243
|
+
wgpu::Origin3D origin = {0, 0, 0};
|
|
244
|
+
if (value->IsArray()) {
|
|
245
|
+
auto arr = value.As<v8::Array>();
|
|
246
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
247
|
+
auto get = [&](uint32_t i) -> uint32_t {
|
|
248
|
+
v8::Local<v8::Value> v;
|
|
249
|
+
return (i < arr->Length() && arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
250
|
+
? static_cast<uint32_t>(v.As<v8::Number>()->Value()) : 0;
|
|
251
|
+
};
|
|
252
|
+
origin.x = get(0);
|
|
253
|
+
origin.y = get(1);
|
|
254
|
+
origin.z = get(2);
|
|
255
|
+
} else if (value->IsObject()) {
|
|
256
|
+
auto o = value.As<v8::Object>();
|
|
257
|
+
origin.x = U32(isolate, o, "x", 0);
|
|
258
|
+
origin.y = U32(isolate, o, "y", 0);
|
|
259
|
+
origin.z = U32(isolate, o, "z", 0);
|
|
260
|
+
}
|
|
261
|
+
return origin;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static wgpu::ErrorFilter ToErrorFilter(std::string_view s)
|
|
265
|
+
{
|
|
266
|
+
if (s == "out-of-memory") return wgpu::ErrorFilter::OutOfMemory;
|
|
267
|
+
if (s == "internal") return wgpu::ErrorFilter::Internal;
|
|
268
|
+
return wgpu::ErrorFilter::Validation;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static wgpu::QueryType ToQueryType(std::string_view s)
|
|
272
|
+
{
|
|
273
|
+
if (s == "timestamp") return wgpu::QueryType::Timestamp;
|
|
274
|
+
return wgpu::QueryType::Occlusion;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// wgpu::ErrorType -> WebGPU の GPUError 種別文字列
|
|
278
|
+
static const char* ErrorTypeName(wgpu::ErrorType t)
|
|
279
|
+
{
|
|
280
|
+
switch (t) {
|
|
281
|
+
case wgpu::ErrorType::Validation: return "validation";
|
|
282
|
+
case wgpu::ErrorType::OutOfMemory: return "out-of-memory";
|
|
283
|
+
case wgpu::ErrorType::Internal: return "internal";
|
|
284
|
+
default: return "unknown";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
222
288
|
static void Queue_WriteTexture(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
223
289
|
{
|
|
224
290
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -229,6 +295,11 @@ static void Queue_WriteTexture(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
229
295
|
wgpu::TexelCopyTextureInfo copy = {};
|
|
230
296
|
copy.texture = Unwrap<wgpu::Texture>(Prop(isolate, dest, "texture").As<v8::Object>());
|
|
231
297
|
copy.mipLevel = U32(isolate, dest, "mipLevel", 0);
|
|
298
|
+
// 宛先 origin (アトラスのセル位置など)。未指定なら (0,0,0)。
|
|
299
|
+
v8::Local<v8::Value> dst_origin = Prop(isolate, dest, "origin");
|
|
300
|
+
if (dst_origin->IsObject() || dst_origin->IsArray()) {
|
|
301
|
+
copy.origin = ParseOrigin(isolate, dst_origin);
|
|
302
|
+
}
|
|
232
303
|
|
|
233
304
|
const void* data = nullptr;
|
|
234
305
|
size_t length = 0;
|
|
@@ -313,6 +384,12 @@ static void Queue_Submit(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
313
384
|
}
|
|
314
385
|
}
|
|
315
386
|
}
|
|
387
|
+
static uint64_t count = 0;
|
|
388
|
+
++count;
|
|
389
|
+
if (count <= 10 || count % 300 == 0) {
|
|
390
|
+
std::cerr << "[GPU] queue.submit #" << count
|
|
391
|
+
<< " (" << buffers.size() << " cmd)" << std::endl;
|
|
392
|
+
}
|
|
316
393
|
queue.Submit(buffers.size(), buffers.data());
|
|
317
394
|
}
|
|
318
395
|
|
|
@@ -460,6 +537,58 @@ static void Pass_End(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
460
537
|
Unwrap<wgpu::RenderPassEncoder>(args.This()).End();
|
|
461
538
|
}
|
|
462
539
|
|
|
540
|
+
static void Pass_BeginOcclusionQuery(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
541
|
+
{
|
|
542
|
+
auto& pass = Unwrap<wgpu::RenderPassEncoder>(args.This());
|
|
543
|
+
uint32_t index = args.Length() > 0 && args[0]->IsNumber()
|
|
544
|
+
? static_cast<uint32_t>(args[0].As<v8::Number>()->Value()) : 0;
|
|
545
|
+
pass.BeginOcclusionQuery(index);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
static void Pass_EndOcclusionQuery(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
549
|
+
{
|
|
550
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).EndOcclusionQuery();
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
static void Pass_ExecuteBundles(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
554
|
+
{
|
|
555
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
556
|
+
auto& pass = Unwrap<wgpu::RenderPassEncoder>(args.This());
|
|
557
|
+
std::vector<wgpu::RenderBundle> bundles;
|
|
558
|
+
if (args.Length() > 0 && args[0]->IsArray()) {
|
|
559
|
+
auto arr = args[0].As<v8::Array>();
|
|
560
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
561
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
562
|
+
v8::Local<v8::Value> v;
|
|
563
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsObject())
|
|
564
|
+
bundles.push_back(Unwrap<wgpu::RenderBundle>(v.As<v8::Object>()));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
pass.ExecuteBundles(bundles.size(), bundles.data());
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// pushDebugGroup / popDebugGroup / insertDebugMarker (render pass)
|
|
571
|
+
static void Pass_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
572
|
+
{
|
|
573
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
574
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
575
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).PushDebugGroup(
|
|
576
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
static void Pass_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
580
|
+
{
|
|
581
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).PopDebugGroup();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
static void Pass_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
585
|
+
{
|
|
586
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
587
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
588
|
+
Unwrap<wgpu::RenderPassEncoder>(args.This()).InsertDebugMarker(
|
|
589
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
590
|
+
}
|
|
591
|
+
|
|
463
592
|
static v8::Local<v8::Object> WrapRenderPass(v8::Isolate* isolate, wgpu::RenderPassEncoder pass)
|
|
464
593
|
{
|
|
465
594
|
v8::Local<v8::Object> obj = WrapWith(isolate, Tmpl(isolate).renderPass, std::move(pass));
|
|
@@ -474,10 +603,120 @@ static v8::Local<v8::Object> WrapRenderPass(v8::Isolate* isolate, wgpu::RenderPa
|
|
|
474
603
|
SetMethod(isolate, obj, "draw", Pass_Draw);
|
|
475
604
|
SetMethod(isolate, obj, "drawIndexed", Pass_DrawIndexed);
|
|
476
605
|
SetMethod(isolate, obj, "drawIndirect", Pass_DrawIndirect);
|
|
606
|
+
SetMethod(isolate, obj, "beginOcclusionQuery", Pass_BeginOcclusionQuery);
|
|
607
|
+
SetMethod(isolate, obj, "endOcclusionQuery", Pass_EndOcclusionQuery);
|
|
608
|
+
SetMethod(isolate, obj, "executeBundles", Pass_ExecuteBundles);
|
|
609
|
+
SetMethod(isolate, obj, "pushDebugGroup", Pass_PushDebugGroup);
|
|
610
|
+
SetMethod(isolate, obj, "popDebugGroup", Pass_PopDebugGroup);
|
|
611
|
+
SetMethod(isolate, obj, "insertDebugMarker", Pass_InsertDebugMarker);
|
|
477
612
|
SetMethod(isolate, obj, "end", Pass_End);
|
|
478
613
|
return obj;
|
|
479
614
|
}
|
|
480
615
|
|
|
616
|
+
// ---------------------------------------------------------------------------
|
|
617
|
+
// GPUComputePassEncoder
|
|
618
|
+
// compute シェーダ経路 (createComputePipeline / beginComputePass / dispatch)。
|
|
619
|
+
// Next2D の 2D ラスタライザは未使用だが、WebGPU の機能を特定用途に絞らず
|
|
620
|
+
// 全面的に利用可能にするため実装する。汎用 GPGPU / storage buffer 出力に対応。
|
|
621
|
+
// ---------------------------------------------------------------------------
|
|
622
|
+
static void CPass_SetPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
623
|
+
{
|
|
624
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).SetPipeline(
|
|
625
|
+
Unwrap<wgpu::ComputePipeline>(args[0].As<v8::Object>()));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
static void CPass_SetBindGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
629
|
+
{
|
|
630
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
631
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
632
|
+
uint32_t index = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
633
|
+
if (args.Length() < 2 || !args[1]->IsObject()) {
|
|
634
|
+
pass.SetBindGroup(index, nullptr);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
auto& group = Unwrap<wgpu::BindGroup>(args[1].As<v8::Object>());
|
|
638
|
+
|
|
639
|
+
// dynamicOffsets (render pass と同じく Array<number> / Uint32Array)
|
|
640
|
+
std::vector<uint32_t> offsets;
|
|
641
|
+
if (args.Length() > 2 && !args[2]->IsNullOrUndefined()) {
|
|
642
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
643
|
+
if (args[2]->IsArray()) {
|
|
644
|
+
auto arr = args[2].As<v8::Array>();
|
|
645
|
+
offsets.reserve(arr->Length());
|
|
646
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
647
|
+
v8::Local<v8::Value> v;
|
|
648
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
649
|
+
offsets.push_back(static_cast<uint32_t>(v.As<v8::Number>()->Value()));
|
|
650
|
+
}
|
|
651
|
+
} else if (args[2]->IsUint32Array()) {
|
|
652
|
+
auto ta = args[2].As<v8::Uint32Array>();
|
|
653
|
+
offsets.resize(ta->Length());
|
|
654
|
+
ta->CopyContents(offsets.data(), offsets.size() * sizeof(uint32_t));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
pass.SetBindGroup(index, group,
|
|
658
|
+
static_cast<uint32_t>(offsets.size()),
|
|
659
|
+
offsets.empty() ? nullptr : offsets.data());
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
static void CPass_DispatchWorkgroups(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
663
|
+
{
|
|
664
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
665
|
+
auto n = [&](int i, uint32_t fb) {
|
|
666
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
667
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
668
|
+
pass.DispatchWorkgroups(n(0, 1), n(1, 1), n(2, 1));
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
static void CPass_DispatchWorkgroupsIndirect(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
672
|
+
{
|
|
673
|
+
auto& pass = Unwrap<wgpu::ComputePassEncoder>(args.This());
|
|
674
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
675
|
+
uint64_t offset = args.Length() > 1 && args[1]->IsNumber()
|
|
676
|
+
? static_cast<uint64_t>(args[1].As<v8::Number>()->Value()) : 0;
|
|
677
|
+
pass.DispatchWorkgroupsIndirect(buffer, offset);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
static void CPass_End(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
681
|
+
{
|
|
682
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).End();
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
static void CPass_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
686
|
+
{
|
|
687
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
688
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
689
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).PushDebugGroup(
|
|
690
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
static void CPass_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
694
|
+
{
|
|
695
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).PopDebugGroup();
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
static void CPass_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
699
|
+
{
|
|
700
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
701
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
702
|
+
Unwrap<wgpu::ComputePassEncoder>(args.This()).InsertDebugMarker(
|
|
703
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
static v8::Local<v8::Object> WrapComputePass(v8::Isolate* isolate, wgpu::ComputePassEncoder pass)
|
|
707
|
+
{
|
|
708
|
+
v8::Local<v8::Object> obj = WrapWith(isolate, Tmpl(isolate).computePass, std::move(pass));
|
|
709
|
+
SetMethod(isolate, obj, "setPipeline", CPass_SetPipeline);
|
|
710
|
+
SetMethod(isolate, obj, "setBindGroup", CPass_SetBindGroup);
|
|
711
|
+
SetMethod(isolate, obj, "dispatchWorkgroups", CPass_DispatchWorkgroups);
|
|
712
|
+
SetMethod(isolate, obj, "dispatchWorkgroupsIndirect", CPass_DispatchWorkgroupsIndirect);
|
|
713
|
+
SetMethod(isolate, obj, "pushDebugGroup", CPass_PushDebugGroup);
|
|
714
|
+
SetMethod(isolate, obj, "popDebugGroup", CPass_PopDebugGroup);
|
|
715
|
+
SetMethod(isolate, obj, "insertDebugMarker", CPass_InsertDebugMarker);
|
|
716
|
+
SetMethod(isolate, obj, "end", CPass_End);
|
|
717
|
+
return obj;
|
|
718
|
+
}
|
|
719
|
+
|
|
481
720
|
// ---------------------------------------------------------------------------
|
|
482
721
|
// GPUCommandEncoder
|
|
483
722
|
// ---------------------------------------------------------------------------
|
|
@@ -501,6 +740,13 @@ static void Encoder_BeginRenderPass(const v8::FunctionCallbackInfo<v8::Value>& a
|
|
|
501
740
|
att.loadOp = ToLoadOp(webgpu::Str(isolate, o, "loadOp"));
|
|
502
741
|
att.storeOp = ToStoreOp(webgpu::Str(isolate, o, "storeOp"));
|
|
503
742
|
att.depthSlice = wgpu::kDepthSliceUndefined;
|
|
743
|
+
// MSAA 解決先。player は全描画を MSAA テクスチャへ行い resolveTarget で
|
|
744
|
+
// 本体テクスチャに解決する。未対応だと描画結果がどこにも現れない (黒画面)。
|
|
745
|
+
v8::Local<v8::Value> rt = Prop(isolate, o, "resolveTarget");
|
|
746
|
+
if (rt->IsObject()) {
|
|
747
|
+
att.resolveTarget =
|
|
748
|
+
Unwrap<wgpu::TextureView>(rt.As<v8::Object>());
|
|
749
|
+
}
|
|
504
750
|
v8::Local<v8::Value> cv = Prop(isolate, o, "clearValue");
|
|
505
751
|
if (cv->IsArray()) {
|
|
506
752
|
auto c = cv.As<v8::Array>();
|
|
@@ -544,10 +790,38 @@ static void Encoder_BeginRenderPass(const v8::FunctionCallbackInfo<v8::Value>& a
|
|
|
544
790
|
pass_desc.depthStencilAttachment = &depth;
|
|
545
791
|
}
|
|
546
792
|
|
|
793
|
+
// occlusionQuerySet: beginOcclusionQuery/endOcclusionQuery で被覆サンプル数を計測する
|
|
794
|
+
v8::Local<v8::Value> oqs = Prop(isolate, desc, "occlusionQuerySet");
|
|
795
|
+
if (oqs->IsObject()) {
|
|
796
|
+
pass_desc.occlusionQuerySet = Unwrap<wgpu::QuerySet>(oqs.As<v8::Object>());
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// timestampWrites: { querySet, beginningOfPassWriteIndex?, endOfPassWriteIndex? }
|
|
800
|
+
// (timestamp-query フィーチャ有効時のみ有効。未有効なら player/検証側で未使用)
|
|
801
|
+
wgpu::PassTimestampWrites ts = {};
|
|
802
|
+
v8::Local<v8::Value> tsv = Prop(isolate, desc, "timestampWrites");
|
|
803
|
+
if (tsv->IsObject()) {
|
|
804
|
+
auto t = tsv.As<v8::Object>();
|
|
805
|
+
ts.querySet = Unwrap<wgpu::QuerySet>(Prop(isolate, t, "querySet").As<v8::Object>());
|
|
806
|
+
ts.beginningOfPassWriteIndex = U32(isolate, t, "beginningOfPassWriteIndex", wgpu::kQuerySetIndexUndefined);
|
|
807
|
+
ts.endOfPassWriteIndex = U32(isolate, t, "endOfPassWriteIndex", wgpu::kQuerySetIndexUndefined);
|
|
808
|
+
pass_desc.timestampWrites = &ts;
|
|
809
|
+
}
|
|
810
|
+
|
|
547
811
|
args.GetReturnValue().Set(
|
|
548
812
|
WrapRenderPass(isolate, encoder.BeginRenderPass(&pass_desc)));
|
|
549
813
|
}
|
|
550
814
|
|
|
815
|
+
static void Encoder_BeginComputePass(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
816
|
+
{
|
|
817
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
818
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
819
|
+
// descriptor は任意 (timestampWrites 等は未使用)。既定で開始する。
|
|
820
|
+
wgpu::ComputePassDescriptor desc = {};
|
|
821
|
+
args.GetReturnValue().Set(
|
|
822
|
+
WrapComputePass(isolate, encoder.BeginComputePass(&desc)));
|
|
823
|
+
}
|
|
824
|
+
|
|
551
825
|
static void Encoder_Finish(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
552
826
|
{
|
|
553
827
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -575,8 +849,7 @@ static wgpu::TexelCopyTextureInfo ParseTexelCopyTexture(v8::Isolate* isolate, v8
|
|
|
575
849
|
info.mipLevel = U32(isolate, o, "mipLevel", 0);
|
|
576
850
|
v8::Local<v8::Value> origin = Prop(isolate, o, "origin");
|
|
577
851
|
if (origin->IsObject() || origin->IsArray()) {
|
|
578
|
-
|
|
579
|
-
info.origin = { e.width, e.height, e.depthOrArrayLayers };
|
|
852
|
+
info.origin = ParseOrigin(isolate, origin);
|
|
580
853
|
}
|
|
581
854
|
return info;
|
|
582
855
|
}
|
|
@@ -608,6 +881,187 @@ static void Encoder_CopyTextureToBuffer(const v8::FunctionCallbackInfo<v8::Value
|
|
|
608
881
|
encoder.CopyTextureToBuffer(&src, &dst, &size);
|
|
609
882
|
}
|
|
610
883
|
|
|
884
|
+
static void Encoder_ResolveQuerySet(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
885
|
+
{
|
|
886
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
887
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
888
|
+
auto& qs = Unwrap<wgpu::QuerySet>(args[0].As<v8::Object>());
|
|
889
|
+
uint32_t first = static_cast<uint32_t>(args[1].As<v8::Number>()->Value());
|
|
890
|
+
uint32_t count = static_cast<uint32_t>(args[2].As<v8::Number>()->Value());
|
|
891
|
+
auto& dst = Unwrap<wgpu::Buffer>(args[3].As<v8::Object>());
|
|
892
|
+
uint64_t dst_off = args.Length() > 4 && args[4]->IsNumber()
|
|
893
|
+
? static_cast<uint64_t>(args[4].As<v8::Number>()->Value()) : 0;
|
|
894
|
+
(void) isolate;
|
|
895
|
+
encoder.ResolveQuerySet(qs, first, count, dst, dst_off);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
static void Encoder_WriteTimestamp(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
899
|
+
{
|
|
900
|
+
auto& encoder = Unwrap<wgpu::CommandEncoder>(args.This());
|
|
901
|
+
auto& qs = Unwrap<wgpu::QuerySet>(args[0].As<v8::Object>());
|
|
902
|
+
uint32_t index = static_cast<uint32_t>(args[1].As<v8::Number>()->Value());
|
|
903
|
+
encoder.WriteTimestamp(qs, index);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
static void Encoder_PushDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
907
|
+
{
|
|
908
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
909
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
910
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).PushDebugGroup(
|
|
911
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
static void Encoder_PopDebugGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
915
|
+
{
|
|
916
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).PopDebugGroup();
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
static void Encoder_InsertDebugMarker(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
920
|
+
{
|
|
921
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
922
|
+
std::string label = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
|
|
923
|
+
Unwrap<wgpu::CommandEncoder>(args.This()).InsertDebugMarker(
|
|
924
|
+
wgpu::StringView(label.c_str(), label.size()));
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// ---------------------------------------------------------------------------
|
|
928
|
+
// GPURenderBundleEncoder (createRenderBundleEncoder -> finish -> GPURenderBundle)
|
|
929
|
+
// ---------------------------------------------------------------------------
|
|
930
|
+
static void RBEncoder_SetPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
931
|
+
{
|
|
932
|
+
Unwrap<wgpu::RenderBundleEncoder>(args.This()).SetPipeline(
|
|
933
|
+
Unwrap<wgpu::RenderPipeline>(args[0].As<v8::Object>()));
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
static void RBEncoder_SetBindGroup(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
937
|
+
{
|
|
938
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
939
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
940
|
+
uint32_t index = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
941
|
+
if (args.Length() < 2 || !args[1]->IsObject()) {
|
|
942
|
+
enc.SetBindGroup(index, nullptr);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
auto& group = Unwrap<wgpu::BindGroup>(args[1].As<v8::Object>());
|
|
946
|
+
std::vector<uint32_t> offsets;
|
|
947
|
+
if (args.Length() > 2 && !args[2]->IsNullOrUndefined()) {
|
|
948
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
949
|
+
if (args[2]->IsArray()) {
|
|
950
|
+
auto arr = args[2].As<v8::Array>();
|
|
951
|
+
offsets.reserve(arr->Length());
|
|
952
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
953
|
+
v8::Local<v8::Value> v;
|
|
954
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsNumber())
|
|
955
|
+
offsets.push_back(static_cast<uint32_t>(v.As<v8::Number>()->Value()));
|
|
956
|
+
}
|
|
957
|
+
} else if (args[2]->IsUint32Array()) {
|
|
958
|
+
auto ta = args[2].As<v8::Uint32Array>();
|
|
959
|
+
offsets.resize(ta->Length());
|
|
960
|
+
ta->CopyContents(offsets.data(), offsets.size() * sizeof(uint32_t));
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
enc.SetBindGroup(index, group, static_cast<uint32_t>(offsets.size()),
|
|
964
|
+
offsets.empty() ? nullptr : offsets.data());
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
static void RBEncoder_SetVertexBuffer(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
968
|
+
{
|
|
969
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
970
|
+
uint32_t slot = static_cast<uint32_t>(args[0].As<v8::Number>()->Value());
|
|
971
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[1].As<v8::Object>());
|
|
972
|
+
uint64_t offset = args.Length() > 2 && args[2]->IsNumber()
|
|
973
|
+
? static_cast<uint64_t>(args[2].As<v8::Number>()->Value()) : 0;
|
|
974
|
+
uint64_t size = args.Length() > 3 && args[3]->IsNumber()
|
|
975
|
+
? static_cast<uint64_t>(args[3].As<v8::Number>()->Value()) : wgpu::kWholeSize;
|
|
976
|
+
enc.SetVertexBuffer(slot, buffer, offset, size);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
static void RBEncoder_SetIndexBuffer(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
980
|
+
{
|
|
981
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
982
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
983
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
984
|
+
wgpu::IndexFormat format = ToIndexFormat(v8util::ToStdString(isolate, args[1]));
|
|
985
|
+
uint64_t offset = args.Length() > 2 && args[2]->IsNumber()
|
|
986
|
+
? static_cast<uint64_t>(args[2].As<v8::Number>()->Value()) : 0;
|
|
987
|
+
uint64_t size = args.Length() > 3 && args[3]->IsNumber()
|
|
988
|
+
? static_cast<uint64_t>(args[3].As<v8::Number>()->Value()) : wgpu::kWholeSize;
|
|
989
|
+
enc.SetIndexBuffer(buffer, format, offset, size);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
static void RBEncoder_Draw(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
993
|
+
{
|
|
994
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
995
|
+
auto n = [&](int i, uint32_t fb) {
|
|
996
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
997
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
998
|
+
enc.Draw(n(0, 0), n(1, 1), n(2, 0), n(3, 0));
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
static void RBEncoder_DrawIndexed(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1002
|
+
{
|
|
1003
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1004
|
+
auto n = [&](int i, uint32_t fb) {
|
|
1005
|
+
return (i < args.Length() && args[i]->IsNumber())
|
|
1006
|
+
? static_cast<uint32_t>(args[i].As<v8::Number>()->Value()) : fb; };
|
|
1007
|
+
enc.DrawIndexed(n(0, 0), n(1, 1), n(2, 0), n(3, 0), n(4, 0));
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
static void RBEncoder_DrawIndirect(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1011
|
+
{
|
|
1012
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1013
|
+
auto& buffer = Unwrap<wgpu::Buffer>(args[0].As<v8::Object>());
|
|
1014
|
+
uint64_t offset = args.Length() > 1 && args[1]->IsNumber()
|
|
1015
|
+
? static_cast<uint64_t>(args[1].As<v8::Number>()->Value()) : 0;
|
|
1016
|
+
enc.DrawIndirect(buffer, offset);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
static void RBEncoder_Finish(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1020
|
+
{
|
|
1021
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1022
|
+
auto& enc = Unwrap<wgpu::RenderBundleEncoder>(args.This());
|
|
1023
|
+
wgpu::RenderBundleDescriptor desc = {};
|
|
1024
|
+
args.GetReturnValue().Set(WrapRenderBundle(isolate, enc.Finish(&desc)));
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
static v8::Local<v8::Object> WrapRenderBundleEncoder(v8::Isolate* isolate, wgpu::RenderBundleEncoder enc)
|
|
1028
|
+
{
|
|
1029
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).renderBundleEncoder, std::move(enc));
|
|
1030
|
+
SetMethod(isolate, obj, "setPipeline", RBEncoder_SetPipeline);
|
|
1031
|
+
SetMethod(isolate, obj, "setBindGroup", RBEncoder_SetBindGroup);
|
|
1032
|
+
SetMethod(isolate, obj, "setVertexBuffer", RBEncoder_SetVertexBuffer);
|
|
1033
|
+
SetMethod(isolate, obj, "setIndexBuffer", RBEncoder_SetIndexBuffer);
|
|
1034
|
+
SetMethod(isolate, obj, "draw", RBEncoder_Draw);
|
|
1035
|
+
SetMethod(isolate, obj, "drawIndexed", RBEncoder_DrawIndexed);
|
|
1036
|
+
SetMethod(isolate, obj, "drawIndirect", RBEncoder_DrawIndirect);
|
|
1037
|
+
SetMethod(isolate, obj, "finish", RBEncoder_Finish);
|
|
1038
|
+
return obj;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
static v8::Local<v8::Object> WrapRenderBundle(v8::Isolate* isolate, wgpu::RenderBundle bundle)
|
|
1042
|
+
{
|
|
1043
|
+
return WrapWith(isolate, Tmpl(isolate).renderBundle, std::move(bundle));
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// ---------------------------------------------------------------------------
|
|
1047
|
+
// GPUQuerySet
|
|
1048
|
+
// ---------------------------------------------------------------------------
|
|
1049
|
+
static void QuerySet_Destroy(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1050
|
+
{
|
|
1051
|
+
Unwrap<wgpu::QuerySet>(args.This()).Destroy();
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
static v8::Local<v8::Object> WrapQuerySet(v8::Isolate* isolate, wgpu::QuerySet qs)
|
|
1055
|
+
{
|
|
1056
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).querySet, std::move(qs));
|
|
1057
|
+
auto& q = Unwrap<wgpu::QuerySet>(obj);
|
|
1058
|
+
SetValue(isolate, obj, "count", v8::Integer::NewFromUnsigned(isolate, q.GetCount()));
|
|
1059
|
+
SetValue(isolate, obj, "type",
|
|
1060
|
+
Str(isolate, q.GetType() == wgpu::QueryType::Timestamp ? "timestamp" : "occlusion"));
|
|
1061
|
+
SetMethod(isolate, obj, "destroy", QuerySet_Destroy);
|
|
1062
|
+
return obj;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
611
1065
|
// ---------------------------------------------------------------------------
|
|
612
1066
|
// GPUCanvasContext
|
|
613
1067
|
// ---------------------------------------------------------------------------
|
|
@@ -617,6 +1071,11 @@ static void Ctx_Configure(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
617
1071
|
DawnContext* gpu = HostContext::From(isolate)->gpu;
|
|
618
1072
|
// device は既に DawnContext が保持。フォーマット/サイズのみ反映する。
|
|
619
1073
|
if (args.Length() > 0 && args[0]->IsObject()) {
|
|
1074
|
+
static uint64_t count = 0;
|
|
1075
|
+
++count;
|
|
1076
|
+
if (count <= 10 || count % 300 == 0) {
|
|
1077
|
+
std::cerr << "[GPU] context.configure #" << count << std::endl;
|
|
1078
|
+
}
|
|
620
1079
|
// width/height は canvas サイズを使用 (configure の size は任意)
|
|
621
1080
|
gpu->Configure(gpu->width(), gpu->height());
|
|
622
1081
|
}
|
|
@@ -626,6 +1085,11 @@ static void Ctx_GetCurrentTexture(const v8::FunctionCallbackInfo<v8::Value>& arg
|
|
|
626
1085
|
{
|
|
627
1086
|
v8::Isolate* isolate = args.GetIsolate();
|
|
628
1087
|
DawnContext* gpu = HostContext::From(isolate)->gpu;
|
|
1088
|
+
static uint64_t count = 0;
|
|
1089
|
+
++count;
|
|
1090
|
+
if (count <= 10 || count % 300 == 0) {
|
|
1091
|
+
std::cerr << "[GPU] getCurrentTexture #" << count << std::endl;
|
|
1092
|
+
}
|
|
629
1093
|
args.GetReturnValue().Set(WrapTexture(isolate, gpu->GetCurrentTexture()));
|
|
630
1094
|
}
|
|
631
1095
|
|
|
@@ -749,9 +1213,13 @@ static void Device_CreateBindGroupLayout(const v8::FunctionCallbackInfo<v8::Valu
|
|
|
749
1213
|
v8::Local<v8::Object> d = args[0].As<v8::Object>();
|
|
750
1214
|
|
|
751
1215
|
std::vector<wgpu::BindGroupLayoutEntry> entries;
|
|
1216
|
+
// externalTexture の nextInChain 構造体は CreateBindGroupLayout 完了まで生存が必要。
|
|
1217
|
+
// reserve でベクタ再割当を防ぎ、back() のアドレスを安定させる。
|
|
1218
|
+
std::vector<wgpu::ExternalTextureBindingLayout> ext_layouts;
|
|
752
1219
|
v8::Local<v8::Value> ev = Prop(isolate, d, "entries");
|
|
753
1220
|
if (ev->IsArray()) {
|
|
754
1221
|
auto arr = ev.As<v8::Array>();
|
|
1222
|
+
ext_layouts.reserve(arr->Length());
|
|
755
1223
|
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
756
1224
|
v8::Local<v8::Value> v;
|
|
757
1225
|
if (!arr->Get(ctx, i).ToLocal(&v) || !v->IsObject()) continue;
|
|
@@ -775,8 +1243,21 @@ static void Device_CreateBindGroupLayout(const v8::FunctionCallbackInfo<v8::Valu
|
|
|
775
1243
|
? ToTextureViewDimension(webgpu::Str(isolate, t, "viewDimension"))
|
|
776
1244
|
: wgpu::TextureViewDimension::e2D;
|
|
777
1245
|
entry.texture.multisampled = Bool(isolate, t, "multisampled", false);
|
|
1246
|
+
} else if (HasProp(isolate, o, "storageTexture")) {
|
|
1247
|
+
auto st = Prop(isolate, o, "storageTexture").As<v8::Object>();
|
|
1248
|
+
entry.storageTexture.access = HasProp(isolate, st, "access")
|
|
1249
|
+
? ToStorageTextureAccess(webgpu::Str(isolate, st, "access"))
|
|
1250
|
+
: wgpu::StorageTextureAccess::WriteOnly;
|
|
1251
|
+
entry.storageTexture.format = ToTextureFormat(webgpu::Str(isolate, st, "format"));
|
|
1252
|
+
entry.storageTexture.viewDimension = HasProp(isolate, st, "viewDimension")
|
|
1253
|
+
? ToTextureViewDimension(webgpu::Str(isolate, st, "viewDimension"))
|
|
1254
|
+
: wgpu::TextureViewDimension::e2D;
|
|
1255
|
+
} else if (HasProp(isolate, o, "externalTexture")) {
|
|
1256
|
+
// GPUExternalTextureBindingLayout は空 (メンバ無し)。sType は
|
|
1257
|
+
// Dawn の C++ ラッパが既定で設定するため emplace してチェーンするだけでよい。
|
|
1258
|
+
ext_layouts.emplace_back();
|
|
1259
|
+
entry.nextInChain = &ext_layouts.back();
|
|
778
1260
|
}
|
|
779
|
-
// «EXTEND» storageTexture / externalTexture は必要に応じて追加
|
|
780
1261
|
entries.push_back(entry);
|
|
781
1262
|
}
|
|
782
1263
|
}
|
|
@@ -881,17 +1362,67 @@ struct RenderPipelineScratch {
|
|
|
881
1362
|
std::vector<wgpu::ColorTargetState> targets;
|
|
882
1363
|
std::vector<wgpu::BlendState> blends;
|
|
883
1364
|
std::string vs_entry, fs_entry;
|
|
1365
|
+
// pipeline-overridable constants (WGSL の override 定数)。key 文字列は
|
|
1366
|
+
// ConstantEntry.key が指すため CreateRenderPipeline 完了まで生存させる。
|
|
1367
|
+
std::vector<std::string> vs_const_keys, fs_const_keys;
|
|
1368
|
+
std::vector<wgpu::ConstantEntry> vs_constants, fs_constants;
|
|
1369
|
+
// desc.depthStencil / desc.fragment はこれらのアドレスを指す。ディスクリプタ構築を
|
|
1370
|
+
// ヘルパに切り出したため、ローカルだとヘルパ return でダングリング化する。scratch に
|
|
1371
|
+
// 保持して CreateRenderPipeline[Async] が同期コピーするまで生存させる。
|
|
1372
|
+
wgpu::DepthStencilState depth = {};
|
|
1373
|
+
wgpu::FragmentState fragment = {};
|
|
884
1374
|
};
|
|
885
1375
|
|
|
886
|
-
|
|
1376
|
+
// { "KEY": number|bool, ... } を wgpu::ConstantEntry 配列へ変換する。
|
|
1377
|
+
// player は WGSL の override(GRADIENT_TYPE / SPREAD_MODE / yFlipSign / フィルタ種別など)
|
|
1378
|
+
// を constants で指定してパイプラインを特殊化する。ここを読まないと全パイプラインが
|
|
1379
|
+
// WGSL の既定値でコンパイルされ、放射状グラデが線形に、spread が pad に、
|
|
1380
|
+
// フィルタ種別が既定分岐に潰れる (エラーは出ない)。
|
|
1381
|
+
static void ParsePipelineConstants(
|
|
1382
|
+
v8::Isolate* isolate, v8::Local<v8::Object> stage,
|
|
1383
|
+
std::vector<std::string>& keys, std::vector<wgpu::ConstantEntry>& entries)
|
|
887
1384
|
{
|
|
888
|
-
v8::Isolate* isolate = args.GetIsolate();
|
|
889
1385
|
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
890
|
-
|
|
891
|
-
|
|
1386
|
+
v8::Local<v8::Value> cv = Prop(isolate, stage, "constants");
|
|
1387
|
+
if (!cv->IsObject()) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
auto co = cv.As<v8::Object>();
|
|
1391
|
+
v8::Local<v8::Array> names;
|
|
1392
|
+
if (!co->GetOwnPropertyNames(ctx).ToLocal(&names)) {
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
// 再確保で ConstantEntry.key の指す c_str が無効化されないよう上限で確保する。
|
|
1396
|
+
keys.reserve(keys.size() + names->Length());
|
|
1397
|
+
entries.reserve(entries.size() + names->Length());
|
|
1398
|
+
for (uint32_t i = 0; i < names->Length(); ++i) {
|
|
1399
|
+
v8::Local<v8::Value> k, val;
|
|
1400
|
+
if (!names->Get(ctx, i).ToLocal(&k)) continue;
|
|
1401
|
+
if (!co->Get(ctx, k).ToLocal(&val)) continue;
|
|
1402
|
+
double num;
|
|
1403
|
+
if (val->IsBoolean()) {
|
|
1404
|
+
num = val.As<v8::Boolean>()->Value() ? 1.0 : 0.0;
|
|
1405
|
+
} else if (val->IsNumber()) {
|
|
1406
|
+
num = val.As<v8::Number>()->Value();
|
|
1407
|
+
} else {
|
|
1408
|
+
continue;
|
|
1409
|
+
}
|
|
1410
|
+
v8::String::Utf8Value ks(isolate, k);
|
|
1411
|
+
if (!*ks) continue;
|
|
1412
|
+
keys.emplace_back(*ks, static_cast<size_t>(ks.length()));
|
|
1413
|
+
wgpu::ConstantEntry e = {};
|
|
1414
|
+
e.key = wgpu::StringView(keys.back().c_str(), keys.back().size());
|
|
1415
|
+
e.value = num;
|
|
1416
|
+
entries.push_back(e);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
892
1419
|
|
|
893
|
-
|
|
894
|
-
|
|
1420
|
+
// ディスクリプタ構築 (sync/async 双方から使う。desc/scratch は呼び出し側が保持し、
|
|
1421
|
+
// CreateRenderPipeline[Async] が同期コピーするまで生存させる)。
|
|
1422
|
+
static void FillRenderPipelineDescriptor(v8::Isolate* isolate, v8::Local<v8::Object> d,
|
|
1423
|
+
RenderPipelineScratch& scratch, wgpu::RenderPipelineDescriptor& desc)
|
|
1424
|
+
{
|
|
1425
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
895
1426
|
|
|
896
1427
|
// layout: 'auto' or GPUPipelineLayout
|
|
897
1428
|
v8::Local<v8::Value> layout = Prop(isolate, d, "layout");
|
|
@@ -944,6 +1475,13 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
944
1475
|
desc.vertex.buffers = scratch.vertex_buffers.data();
|
|
945
1476
|
}
|
|
946
1477
|
|
|
1478
|
+
// vertex.constants (override 定数)
|
|
1479
|
+
ParsePipelineConstants(isolate, vertex, scratch.vs_const_keys, scratch.vs_constants);
|
|
1480
|
+
if (!scratch.vs_constants.empty()) {
|
|
1481
|
+
desc.vertex.constantCount = scratch.vs_constants.size();
|
|
1482
|
+
desc.vertex.constants = scratch.vs_constants.data();
|
|
1483
|
+
}
|
|
1484
|
+
|
|
947
1485
|
// primitive
|
|
948
1486
|
v8::Local<v8::Value> prim = Prop(isolate, d, "primitive");
|
|
949
1487
|
if (prim->IsObject()) {
|
|
@@ -958,7 +1496,8 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
958
1496
|
}
|
|
959
1497
|
|
|
960
1498
|
// depthStencil (マスク処理は stencil8 + stencilFront/Back を使う)
|
|
961
|
-
|
|
1499
|
+
// scratch.depth を参照 (アドレスを desc.depthStencil に格納するため寿命を延ばす)。
|
|
1500
|
+
wgpu::DepthStencilState& depth = scratch.depth;
|
|
962
1501
|
v8::Local<v8::Value> dsv = Prop(isolate, d, "depthStencil");
|
|
963
1502
|
if (dsv->IsObject()) {
|
|
964
1503
|
auto ds = dsv.As<v8::Object>();
|
|
@@ -1008,10 +1547,18 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
1008
1547
|
if (ms->IsObject()) {
|
|
1009
1548
|
auto m = ms.As<v8::Object>();
|
|
1010
1549
|
desc.multisample.count = U32(isolate, m, "count", 1);
|
|
1550
|
+
// alphaToCoverageEnabled: フラグメント alpha を MSAA カバレッジへ変換する。
|
|
1551
|
+
// Next2D はベクタ図形の境界を塗り alpha に頼るため、これが無いと全図形の
|
|
1552
|
+
// アンチエイリアスが失われて縁がジャギる (静かな品質劣化)。
|
|
1553
|
+
desc.multisample.alphaToCoverageEnabled = Bool(isolate, m, "alphaToCoverageEnabled", false);
|
|
1554
|
+
if (HasProp(isolate, m, "mask")) {
|
|
1555
|
+
desc.multisample.mask = U32(isolate, m, "mask", 0xFFFFFFFF);
|
|
1556
|
+
}
|
|
1011
1557
|
}
|
|
1012
1558
|
|
|
1013
1559
|
// fragment
|
|
1014
|
-
|
|
1560
|
+
// scratch.fragment を参照 (アドレスを desc.fragment に格納するため寿命を延ばす)。
|
|
1561
|
+
wgpu::FragmentState& fragment = scratch.fragment;
|
|
1015
1562
|
v8::Local<v8::Value> fv = Prop(isolate, d, "fragment");
|
|
1016
1563
|
if (fv->IsObject()) {
|
|
1017
1564
|
auto f = fv.As<v8::Object>();
|
|
@@ -1053,12 +1600,223 @@ static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value
|
|
|
1053
1600
|
fragment.targetCount = scratch.targets.size();
|
|
1054
1601
|
fragment.targets = scratch.targets.data();
|
|
1055
1602
|
}
|
|
1603
|
+
|
|
1604
|
+
// fragment.constants (override 定数: GRADIENT_TYPE/SPREAD_MODE/フィルタ種別など)
|
|
1605
|
+
ParsePipelineConstants(isolate, f, scratch.fs_const_keys, scratch.fs_constants);
|
|
1606
|
+
if (!scratch.fs_constants.empty()) {
|
|
1607
|
+
fragment.constantCount = scratch.fs_constants.size();
|
|
1608
|
+
fragment.constants = scratch.fs_constants.data();
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1056
1611
|
desc.fragment = &fragment;
|
|
1057
1612
|
}
|
|
1613
|
+
}
|
|
1058
1614
|
|
|
1615
|
+
static void Device_CreateRenderPipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1616
|
+
{
|
|
1617
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1618
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1619
|
+
RenderPipelineScratch scratch;
|
|
1620
|
+
wgpu::RenderPipelineDescriptor desc = {};
|
|
1621
|
+
FillRenderPipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1059
1622
|
args.GetReturnValue().Set(WrapPipeline(isolate, device.CreateRenderPipeline(&desc)));
|
|
1060
1623
|
}
|
|
1061
1624
|
|
|
1625
|
+
// ---------------------------------------------------------------------------
|
|
1626
|
+
// GPUDevice.createComputePipeline
|
|
1627
|
+
// { layout: 'auto'|GPUPipelineLayout, compute: {module, entryPoint?, constants?} }
|
|
1628
|
+
// ---------------------------------------------------------------------------
|
|
1629
|
+
// compute ディスクリプタ構築 (sync/async 共有)。entryPoint/constants の文字列寿命は
|
|
1630
|
+
// 呼び出し側が保持する keys/entry_strs で管理する。
|
|
1631
|
+
struct ComputePipelineScratch {
|
|
1632
|
+
std::string cs_entry;
|
|
1633
|
+
std::vector<std::string> cs_const_keys;
|
|
1634
|
+
std::vector<wgpu::ConstantEntry> cs_constants;
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1637
|
+
static void FillComputePipelineDescriptor(v8::Isolate* isolate, v8::Local<v8::Object> d,
|
|
1638
|
+
ComputePipelineScratch& scratch, wgpu::ComputePipelineDescriptor& desc)
|
|
1639
|
+
{
|
|
1640
|
+
v8::Local<v8::Value> layout = Prop(isolate, d, "layout");
|
|
1641
|
+
if (layout->IsObject()) {
|
|
1642
|
+
desc.layout = Unwrap<wgpu::PipelineLayout>(layout.As<v8::Object>());
|
|
1643
|
+
}
|
|
1644
|
+
v8::Local<v8::Object> compute = Prop(isolate, d, "compute").As<v8::Object>();
|
|
1645
|
+
desc.compute.module = Unwrap<wgpu::ShaderModule>(Prop(isolate, compute, "module").As<v8::Object>());
|
|
1646
|
+
scratch.cs_entry = webgpu::Str(isolate, compute, "entryPoint");
|
|
1647
|
+
if (!scratch.cs_entry.empty()) {
|
|
1648
|
+
desc.compute.entryPoint = wgpu::StringView(scratch.cs_entry.c_str(), scratch.cs_entry.size());
|
|
1649
|
+
}
|
|
1650
|
+
ParsePipelineConstants(isolate, compute, scratch.cs_const_keys, scratch.cs_constants);
|
|
1651
|
+
if (!scratch.cs_constants.empty()) {
|
|
1652
|
+
desc.compute.constantCount = scratch.cs_constants.size();
|
|
1653
|
+
desc.compute.constants = scratch.cs_constants.data();
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
static void Device_CreateComputePipeline(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1658
|
+
{
|
|
1659
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1660
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1661
|
+
ComputePipelineScratch scratch;
|
|
1662
|
+
wgpu::ComputePipelineDescriptor desc = {};
|
|
1663
|
+
FillComputePipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1664
|
+
args.GetReturnValue().Set(
|
|
1665
|
+
WrapComputePipeline(isolate, device.CreateComputePipeline(&desc)));
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
// createRenderPipelineAsync / createComputePipelineAsync -> Promise<GPU*Pipeline>
|
|
1669
|
+
// Dawn C++ の Future 版 (CallbackMode::AllowProcessEvents で event loop が処理)。
|
|
1670
|
+
// ディスクリプタは呼び出し時に同期コピーされるため scratch はスタックで足りる。
|
|
1671
|
+
static void Device_CreateRenderPipelineAsync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1672
|
+
{
|
|
1673
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1674
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1675
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1676
|
+
RenderPipelineScratch scratch;
|
|
1677
|
+
wgpu::RenderPipelineDescriptor desc = {};
|
|
1678
|
+
FillRenderPipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1679
|
+
|
|
1680
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1681
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1682
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1683
|
+
|
|
1684
|
+
device.CreateRenderPipelineAsync(&desc, wgpu::CallbackMode::AllowProcessEvents,
|
|
1685
|
+
[isolate, persistent](wgpu::CreatePipelineAsyncStatus status,
|
|
1686
|
+
wgpu::RenderPipeline pipeline, wgpu::StringView) {
|
|
1687
|
+
v8::HandleScope scope(isolate);
|
|
1688
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1689
|
+
auto r = persistent->Get(isolate);
|
|
1690
|
+
if (status == wgpu::CreatePipelineAsyncStatus::Success) {
|
|
1691
|
+
r->Resolve(c, WrapPipeline(isolate, pipeline)).Check();
|
|
1692
|
+
} else {
|
|
1693
|
+
r->Reject(c, v8::Exception::Error(
|
|
1694
|
+
v8util::Str(isolate, "createRenderPipelineAsync failed"))).Check();
|
|
1695
|
+
}
|
|
1696
|
+
persistent->Reset(); delete persistent;
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
static void Device_CreateComputePipelineAsync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1701
|
+
{
|
|
1702
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1703
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1704
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1705
|
+
ComputePipelineScratch scratch;
|
|
1706
|
+
wgpu::ComputePipelineDescriptor desc = {};
|
|
1707
|
+
FillComputePipelineDescriptor(isolate, args[0].As<v8::Object>(), scratch, desc);
|
|
1708
|
+
|
|
1709
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1710
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1711
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1712
|
+
|
|
1713
|
+
device.CreateComputePipelineAsync(&desc, wgpu::CallbackMode::AllowProcessEvents,
|
|
1714
|
+
[isolate, persistent](wgpu::CreatePipelineAsyncStatus status,
|
|
1715
|
+
wgpu::ComputePipeline pipeline, wgpu::StringView) {
|
|
1716
|
+
v8::HandleScope scope(isolate);
|
|
1717
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1718
|
+
auto r = persistent->Get(isolate);
|
|
1719
|
+
if (status == wgpu::CreatePipelineAsyncStatus::Success) {
|
|
1720
|
+
r->Resolve(c, WrapComputePipeline(isolate, pipeline)).Check();
|
|
1721
|
+
} else {
|
|
1722
|
+
r->Reject(c, v8::Exception::Error(
|
|
1723
|
+
v8util::Str(isolate, "createComputePipelineAsync failed"))).Check();
|
|
1724
|
+
}
|
|
1725
|
+
persistent->Reset(); delete persistent;
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// createQuerySet({ type: 'occlusion'|'timestamp', count })
|
|
1730
|
+
static void Device_CreateQuerySet(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1731
|
+
{
|
|
1732
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1733
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1734
|
+
v8::Local<v8::Object> d = args[0].As<v8::Object>();
|
|
1735
|
+
wgpu::QuerySetDescriptor desc = {};
|
|
1736
|
+
desc.type = ToQueryType(webgpu::Str(isolate, d, "type"));
|
|
1737
|
+
desc.count = U32(isolate, d, "count", 0);
|
|
1738
|
+
args.GetReturnValue().Set(WrapQuerySet(isolate, device.CreateQuerySet(&desc)));
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
// createRenderBundleEncoder({ colorFormats[], depthStencilFormat?, sampleCount?, ... })
|
|
1742
|
+
static void Device_CreateRenderBundleEncoder(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1743
|
+
{
|
|
1744
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1745
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1746
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1747
|
+
v8::Local<v8::Object> d = args[0].As<v8::Object>();
|
|
1748
|
+
|
|
1749
|
+
std::vector<wgpu::TextureFormat> formats;
|
|
1750
|
+
v8::Local<v8::Value> cf = Prop(isolate, d, "colorFormats");
|
|
1751
|
+
if (cf->IsArray()) {
|
|
1752
|
+
auto arr = cf.As<v8::Array>();
|
|
1753
|
+
for (uint32_t i = 0; i < arr->Length(); ++i) {
|
|
1754
|
+
v8::Local<v8::Value> v;
|
|
1755
|
+
if (arr->Get(ctx, i).ToLocal(&v) && v->IsString()) {
|
|
1756
|
+
formats.push_back(ToTextureFormat(v8util::ToStdString(isolate, v)));
|
|
1757
|
+
} else {
|
|
1758
|
+
formats.push_back(wgpu::TextureFormat::Undefined); // ギャップ (null)
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
wgpu::RenderBundleEncoderDescriptor desc = {};
|
|
1764
|
+
desc.colorFormatCount = formats.size();
|
|
1765
|
+
desc.colorFormats = formats.data();
|
|
1766
|
+
if (HasProp(isolate, d, "depthStencilFormat")) {
|
|
1767
|
+
desc.depthStencilFormat = ToTextureFormat(webgpu::Str(isolate, d, "depthStencilFormat"));
|
|
1768
|
+
}
|
|
1769
|
+
desc.sampleCount = U32(isolate, d, "sampleCount", 1);
|
|
1770
|
+
desc.depthReadOnly = Bool(isolate, d, "depthReadOnly", false);
|
|
1771
|
+
desc.stencilReadOnly = Bool(isolate, d, "stencilReadOnly", false);
|
|
1772
|
+
|
|
1773
|
+
args.GetReturnValue().Set(
|
|
1774
|
+
WrapRenderBundleEncoder(isolate, device.CreateRenderBundleEncoder(&desc)));
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
// pushErrorScope(filter) / popErrorScope() -> Promise<GPUError|null>
|
|
1778
|
+
static void Device_PushErrorScope(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1779
|
+
{
|
|
1780
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1781
|
+
wgpu::ErrorFilter filter = ToErrorFilter(
|
|
1782
|
+
args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "validation");
|
|
1783
|
+
Unwrap<wgpu::Device>(args.This()).PushErrorScope(filter);
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
static void Device_PopErrorScope(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1787
|
+
{
|
|
1788
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1789
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1790
|
+
auto& device = Unwrap<wgpu::Device>(args.This());
|
|
1791
|
+
|
|
1792
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1793
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1794
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1795
|
+
|
|
1796
|
+
device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents,
|
|
1797
|
+
[isolate, persistent](wgpu::PopErrorScopeStatus, wgpu::ErrorType type, wgpu::StringView message) {
|
|
1798
|
+
v8::HandleScope scope(isolate);
|
|
1799
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1800
|
+
auto r = persistent->Get(isolate);
|
|
1801
|
+
if (type == wgpu::ErrorType::NoError) {
|
|
1802
|
+
r->Resolve(c, v8::Null(isolate)).Check();
|
|
1803
|
+
} else {
|
|
1804
|
+
// GPUError 相当のオブジェクト ({ message, __errorType })
|
|
1805
|
+
v8::Local<v8::Object> err = v8::Object::New(isolate);
|
|
1806
|
+
std::string msg(message.data ? message.data : "", message.length);
|
|
1807
|
+
SetValue(isolate, err, "message", v8util::Str(isolate, msg.c_str()));
|
|
1808
|
+
SetValue(isolate, err, "__errorType", v8util::Str(isolate, ErrorTypeName(type)));
|
|
1809
|
+
r->Resolve(c, err).Check();
|
|
1810
|
+
}
|
|
1811
|
+
persistent->Reset(); delete persistent;
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
static void Device_Destroy(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1816
|
+
{
|
|
1817
|
+
Unwrap<wgpu::Device>(args.This()).Destroy();
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1062
1820
|
static void Device_CreateCommandEncoder(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1063
1821
|
{
|
|
1064
1822
|
v8::Isolate* isolate = args.GetIsolate();
|
|
@@ -1106,10 +1864,16 @@ static v8::Local<v8::Object> WrapEncoder(v8::Isolate* isolate, wgpu::CommandEnco
|
|
|
1106
1864
|
{
|
|
1107
1865
|
auto obj = WrapWith(isolate, Tmpl(isolate).commandEncoder, std::move(encoder));
|
|
1108
1866
|
SetMethod(isolate, obj, "beginRenderPass", Encoder_BeginRenderPass);
|
|
1867
|
+
SetMethod(isolate, obj, "beginComputePass", Encoder_BeginComputePass);
|
|
1109
1868
|
SetMethod(isolate, obj, "finish", Encoder_Finish);
|
|
1110
1869
|
SetMethod(isolate, obj, "copyBufferToBuffer", Encoder_CopyBufferToBuffer);
|
|
1111
1870
|
SetMethod(isolate, obj, "copyTextureToTexture", Encoder_CopyTextureToTexture);
|
|
1112
1871
|
SetMethod(isolate, obj, "copyTextureToBuffer", Encoder_CopyTextureToBuffer);
|
|
1872
|
+
SetMethod(isolate, obj, "resolveQuerySet", Encoder_ResolveQuerySet);
|
|
1873
|
+
SetMethod(isolate, obj, "writeTimestamp", Encoder_WriteTimestamp);
|
|
1874
|
+
SetMethod(isolate, obj, "pushDebugGroup", Encoder_PushDebugGroup);
|
|
1875
|
+
SetMethod(isolate, obj, "popDebugGroup", Encoder_PopDebugGroup);
|
|
1876
|
+
SetMethod(isolate, obj, "insertDebugMarker", Encoder_InsertDebugMarker);
|
|
1113
1877
|
return obj;
|
|
1114
1878
|
}
|
|
1115
1879
|
|
|
@@ -1120,9 +1884,45 @@ static v8::Local<v8::Object> WrapPipeline(v8::Isolate* isolate, wgpu::RenderPipe
|
|
|
1120
1884
|
return obj;
|
|
1121
1885
|
}
|
|
1122
1886
|
|
|
1887
|
+
static void ComputePipeline_GetBindGroupLayout(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1888
|
+
{
|
|
1889
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1890
|
+
auto& pipeline = Unwrap<wgpu::ComputePipeline>(args.This());
|
|
1891
|
+
uint32_t index = args.Length() > 0 && args[0]->IsNumber()
|
|
1892
|
+
? static_cast<uint32_t>(args[0].As<v8::Number>()->Value()) : 0;
|
|
1893
|
+
args.GetReturnValue().Set(
|
|
1894
|
+
WrapWith(isolate, Tmpl(isolate).bindGroupLayout, pipeline.GetBindGroupLayout(index)));
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
static v8::Local<v8::Object> WrapComputePipeline(v8::Isolate* isolate, wgpu::ComputePipeline pipeline)
|
|
1898
|
+
{
|
|
1899
|
+
auto obj = WrapWith(isolate, Tmpl(isolate).computePipeline, std::move(pipeline));
|
|
1900
|
+
SetMethod(isolate, obj, "getBindGroupLayout", ComputePipeline_GetBindGroupLayout);
|
|
1901
|
+
return obj;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1123
1904
|
// ---------------------------------------------------------------------------
|
|
1124
1905
|
// GPUDevice / GPUQueue / GPUAdapter のラップ
|
|
1125
1906
|
// ---------------------------------------------------------------------------
|
|
1907
|
+
static void Queue_OnSubmittedWorkDone(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
1908
|
+
{
|
|
1909
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
1910
|
+
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
1911
|
+
auto& queue = Unwrap<wgpu::Queue>(args.This());
|
|
1912
|
+
|
|
1913
|
+
auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
|
|
1914
|
+
auto* persistent = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
|
|
1915
|
+
args.GetReturnValue().Set(resolver->GetPromise());
|
|
1916
|
+
|
|
1917
|
+
queue.OnSubmittedWorkDone(wgpu::CallbackMode::AllowProcessEvents,
|
|
1918
|
+
[isolate, persistent](wgpu::QueueWorkDoneStatus, wgpu::StringView) {
|
|
1919
|
+
v8::HandleScope scope(isolate);
|
|
1920
|
+
v8::Local<v8::Context> c = isolate->GetCurrentContext();
|
|
1921
|
+
persistent->Get(isolate)->Resolve(c, v8::Undefined(isolate)).Check();
|
|
1922
|
+
persistent->Reset(); delete persistent;
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1126
1926
|
static v8::Local<v8::Object> WrapQueue(v8::Isolate* isolate, wgpu::Queue queue)
|
|
1127
1927
|
{
|
|
1128
1928
|
auto obj = WrapWith(isolate, Tmpl(isolate).queue, std::move(queue));
|
|
@@ -1130,6 +1930,7 @@ static v8::Local<v8::Object> WrapQueue(v8::Isolate* isolate, wgpu::Queue queue)
|
|
|
1130
1930
|
SetMethod(isolate, obj, "writeBuffer", Queue_WriteBuffer);
|
|
1131
1931
|
SetMethod(isolate, obj, "writeTexture", Queue_WriteTexture);
|
|
1132
1932
|
SetMethod(isolate, obj, "copyExternalImageToTexture", Queue_CopyExternalImageToTexture);
|
|
1933
|
+
SetMethod(isolate, obj, "onSubmittedWorkDone", Queue_OnSubmittedWorkDone);
|
|
1133
1934
|
return obj;
|
|
1134
1935
|
}
|
|
1135
1936
|
|
|
@@ -1144,10 +1945,26 @@ static v8::Local<v8::Object> WrapDevice(v8::Isolate* isolate, wgpu::Device devic
|
|
|
1144
1945
|
SetMethod(isolate, obj, "createBindGroup", Device_CreateBindGroup);
|
|
1145
1946
|
SetMethod(isolate, obj, "createPipelineLayout", Device_CreatePipelineLayout);
|
|
1146
1947
|
SetMethod(isolate, obj, "createRenderPipeline", Device_CreateRenderPipeline);
|
|
1948
|
+
SetMethod(isolate, obj, "createComputePipeline", Device_CreateComputePipeline);
|
|
1949
|
+
SetMethod(isolate, obj, "createRenderPipelineAsync", Device_CreateRenderPipelineAsync);
|
|
1950
|
+
SetMethod(isolate, obj, "createComputePipelineAsync", Device_CreateComputePipelineAsync);
|
|
1147
1951
|
SetMethod(isolate, obj, "createCommandEncoder", Device_CreateCommandEncoder);
|
|
1952
|
+
SetMethod(isolate, obj, "createQuerySet", Device_CreateQuerySet);
|
|
1953
|
+
SetMethod(isolate, obj, "createRenderBundleEncoder", Device_CreateRenderBundleEncoder);
|
|
1954
|
+
SetMethod(isolate, obj, "pushErrorScope", Device_PushErrorScope);
|
|
1955
|
+
SetMethod(isolate, obj, "popErrorScope", Device_PopErrorScope);
|
|
1956
|
+
SetMethod(isolate, obj, "destroy", Device_Destroy);
|
|
1148
1957
|
SetValue(isolate, obj, "queue", WrapQueue(isolate, device.GetQueue()));
|
|
1149
1958
|
SetValue(isolate, obj, "features", v8::Object::New(isolate));
|
|
1150
1959
|
|
|
1960
|
+
// device.lost: Promise<GPUDeviceLostInfo>。デバイス生存中は pending (spec 準拠)。
|
|
1961
|
+
// 実際のロストは Dawn の deviceLost コールバック経路 (DawnContext 側) に委ねる。
|
|
1962
|
+
{
|
|
1963
|
+
v8::Local<v8::Context> lctx = isolate->GetCurrentContext();
|
|
1964
|
+
auto lost = v8::Promise::Resolver::New(lctx).ToLocalChecked();
|
|
1965
|
+
SetValue(isolate, obj, "lost", lost->GetPromise());
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1151
1968
|
// limits: player は maxTextureDimension2D で描画最大サイズを決めるため実値を返す。
|
|
1152
1969
|
// GetLimits の戻り値型は Dawn バージョン差があるため値でガードする(0 なら保証最小値)。
|
|
1153
1970
|
v8::Local<v8::Object> limits = v8::Object::New(isolate);
|
|
@@ -1224,6 +2041,8 @@ static void InitTemplates(v8::Isolate* isolate)
|
|
|
1224
2041
|
make(t.textureView); make(t.sampler); make(t.shaderModule); make(t.bindGroupLayout);
|
|
1225
2042
|
make(t.bindGroup); make(t.pipelineLayout); make(t.renderPipeline); make(t.commandEncoder);
|
|
1226
2043
|
make(t.renderPass); make(t.commandBuffer); make(t.canvasContext);
|
|
2044
|
+
make(t.computePipeline); make(t.computePass);
|
|
2045
|
+
make(t.querySet); make(t.renderBundle); make(t.renderBundleEncoder);
|
|
1227
2046
|
}
|
|
1228
2047
|
|
|
1229
2048
|
static void SetFlag(v8::Isolate* isolate, v8::Local<v8::Object> obj, const char* k, uint32_t v)
|
|
@@ -1234,6 +2053,13 @@ static void SetFlag(v8::Isolate* isolate, v8::Local<v8::Object> obj, const char*
|
|
|
1234
2053
|
} // namespace webgpu
|
|
1235
2054
|
|
|
1236
2055
|
// Bindings.h から呼ばれる公開関数
|
|
2056
|
+
// V8 破棄前に呼ぶ。テンプレートの v8::Global (static map) を解放する。
|
|
2057
|
+
// (放置すると static デストラクタが V8 破棄後に走りアクセス違反になる)
|
|
2058
|
+
void ShutdownWebGPU()
|
|
2059
|
+
{
|
|
2060
|
+
webgpu::g_templates.clear();
|
|
2061
|
+
}
|
|
2062
|
+
|
|
1237
2063
|
void InstallWebGPU(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* host)
|
|
1238
2064
|
{
|
|
1239
2065
|
using namespace next2d::webgpu;
|