@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
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#include <v8.h>
|
|
16
16
|
|
|
17
17
|
#include "v8/V8Util.h"
|
|
18
|
+
#include "v8/WeakHandle.h"
|
|
18
19
|
|
|
19
20
|
#include <memory>
|
|
20
21
|
#include <string>
|
|
@@ -27,13 +28,8 @@ struct Holder {
|
|
|
27
28
|
T handle;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
template <typename T>
|
|
31
|
-
void ReleaseHolder(const v8::WeakCallbackInfo<Holder<T>>& info)
|
|
32
|
-
{
|
|
33
|
-
delete info.GetParameter();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
// wgpu ハンドル T を、指定 ObjectTemplate から生成したオブジェクトにラップする。
|
|
32
|
+
// GC 時の解放は AttachWeak (第一パスで Global を Reset する規約に準拠) に委ねる。
|
|
37
33
|
template <typename T>
|
|
38
34
|
v8::Local<v8::Object> Wrap(v8::Isolate* isolate,
|
|
39
35
|
v8::Local<v8::ObjectTemplate> tmpl,
|
|
@@ -43,8 +39,7 @@ v8::Local<v8::Object> Wrap(v8::Isolate* isolate,
|
|
|
43
39
|
v8::Local<v8::Object> obj = tmpl->NewInstance(ctx).ToLocalChecked();
|
|
44
40
|
auto* holder = new Holder<T>{std::move(handle)};
|
|
45
41
|
obj->SetInternalField(0, v8::External::New(isolate, holder));
|
|
46
|
-
|
|
47
|
-
global->SetWeak(holder, ReleaseHolder<T>, v8::WeakCallbackType::kParameter);
|
|
42
|
+
v8util::AttachWeak(isolate, obj, holder);
|
|
48
43
|
return obj;
|
|
49
44
|
}
|
|
50
45
|
|
|
@@ -66,12 +61,15 @@ inline v8::Local<v8::ObjectTemplate> HandleTemplate(v8::Isolate* isolate)
|
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
// --- JS オブジェクト読み取りヘルパー ------------------------------------
|
|
64
|
+
// プロパティ名はキャッシュ済み internalized string (v8util::PropName) を使う。
|
|
65
|
+
// ここは全ディスクリプタ解析の合流点で毎フレーム数千回通るため、名前 v8::String の
|
|
66
|
+
// 毎回生成 (ヒープ確保 + ハッシュ) を排除する効果が大きい。
|
|
69
67
|
inline v8::Local<v8::Value> Prop(v8::Isolate* isolate, v8::Local<v8::Object> obj,
|
|
70
68
|
const char* key)
|
|
71
69
|
{
|
|
72
70
|
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
73
71
|
v8::Local<v8::Value> v;
|
|
74
|
-
if (obj->Get(ctx, v8util::
|
|
72
|
+
if (obj->Get(ctx, v8util::PropName(isolate, key)).ToLocal(&v)) {
|
|
75
73
|
return v;
|
|
76
74
|
}
|
|
77
75
|
return v8::Undefined(isolate);
|
|
@@ -17,22 +17,54 @@ inline wgpu::TextureFormat ToTextureFormat(std::string_view s)
|
|
|
17
17
|
if (s == "bgra8unorm") return F::BGRA8Unorm;
|
|
18
18
|
if (s == "bgra8unorm-srgb") return F::BGRA8UnormSrgb;
|
|
19
19
|
if (s == "rgba8snorm") return F::RGBA8Snorm;
|
|
20
|
+
if (s == "rgba8uint") return F::RGBA8Uint;
|
|
21
|
+
if (s == "rgba8sint") return F::RGBA8Sint;
|
|
20
22
|
if (s == "r8unorm") return F::R8Unorm;
|
|
23
|
+
if (s == "r8snorm") return F::R8Snorm;
|
|
24
|
+
if (s == "r8uint") return F::R8Uint;
|
|
25
|
+
if (s == "r8sint") return F::R8Sint;
|
|
21
26
|
if (s == "rg8unorm") return F::RG8Unorm;
|
|
27
|
+
if (s == "rg8snorm") return F::RG8Snorm;
|
|
28
|
+
if (s == "rg8uint") return F::RG8Uint;
|
|
29
|
+
if (s == "rg8sint") return F::RG8Sint;
|
|
30
|
+
if (s == "r16uint") return F::R16Uint;
|
|
31
|
+
if (s == "r16sint") return F::R16Sint;
|
|
22
32
|
if (s == "r16float") return F::R16Float;
|
|
33
|
+
if (s == "rg16uint") return F::RG16Uint;
|
|
34
|
+
if (s == "rg16sint") return F::RG16Sint;
|
|
23
35
|
if (s == "rg16float") return F::RG16Float;
|
|
36
|
+
if (s == "rgba16uint") return F::RGBA16Uint;
|
|
37
|
+
if (s == "rgba16sint") return F::RGBA16Sint;
|
|
24
38
|
if (s == "rgba16float") return F::RGBA16Float;
|
|
39
|
+
if (s == "r32uint") return F::R32Uint;
|
|
40
|
+
if (s == "r32sint") return F::R32Sint;
|
|
25
41
|
if (s == "r32float") return F::R32Float;
|
|
42
|
+
if (s == "rg32uint") return F::RG32Uint;
|
|
43
|
+
if (s == "rg32sint") return F::RG32Sint;
|
|
26
44
|
if (s == "rg32float") return F::RG32Float;
|
|
45
|
+
if (s == "rgba32uint") return F::RGBA32Uint;
|
|
46
|
+
if (s == "rgba32sint") return F::RGBA32Sint;
|
|
27
47
|
if (s == "rgba32float") return F::RGBA32Float;
|
|
48
|
+
if (s == "rgb10a2unorm") return F::RGB10A2Unorm;
|
|
49
|
+
if (s == "rg11b10ufloat") return F::RG11B10Ufloat;
|
|
28
50
|
if (s == "depth16unorm") return F::Depth16Unorm;
|
|
29
51
|
if (s == "depth24plus") return F::Depth24Plus;
|
|
30
52
|
if (s == "depth24plus-stencil8") return F::Depth24PlusStencil8;
|
|
31
53
|
if (s == "depth32float") return F::Depth32Float;
|
|
54
|
+
if (s == "depth32float-stencil8") return F::Depth32FloatStencil8;
|
|
32
55
|
if (s == "stencil8") return F::Stencil8;
|
|
33
56
|
return F::RGBA8Unorm;
|
|
34
57
|
}
|
|
35
58
|
|
|
59
|
+
inline wgpu::StorageTextureAccess ToStorageTextureAccess(std::string_view s)
|
|
60
|
+
{
|
|
61
|
+
using A = wgpu::StorageTextureAccess;
|
|
62
|
+
if (s == "write-only") return A::WriteOnly;
|
|
63
|
+
if (s == "read-only") return A::ReadOnly;
|
|
64
|
+
if (s == "read-write") return A::ReadWrite;
|
|
65
|
+
return A::WriteOnly;
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
inline wgpu::VertexFormat ToVertexFormat(std::string_view s)
|
|
37
69
|
{
|
|
38
70
|
using V = wgpu::VertexFormat;
|
|
@@ -1,23 +1,160 @@
|
|
|
1
1
|
#include "DawnContext.h"
|
|
2
2
|
|
|
3
3
|
#include <Windows.h>
|
|
4
|
-
#include <
|
|
4
|
+
#include <chrono>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <cstdio>
|
|
7
|
+
#include <cstdlib>
|
|
8
|
+
#include <filesystem>
|
|
9
|
+
#include <fstream>
|
|
5
10
|
#include <iostream>
|
|
11
|
+
#include <string>
|
|
6
12
|
|
|
7
13
|
namespace next2d {
|
|
8
14
|
|
|
9
15
|
namespace {
|
|
10
16
|
|
|
17
|
+
// GUI 実行では stderr が見えないため、GPU の致命的エラー/検証エラーを
|
|
18
|
+
// next2d-error.log にも残す。描画が黒くなる/表示されない等の原因(検証エラー・
|
|
19
|
+
// device lost・リソース枯渇)を掴む唯一の手段。氾濫防止に総数を制限する。
|
|
20
|
+
void AppendGpuLog(const std::string& line)
|
|
21
|
+
{
|
|
22
|
+
static int count = 0;
|
|
23
|
+
if (count >= 60) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
++count;
|
|
27
|
+
std::ofstream ofs("next2d-error.log", std::ios::app);
|
|
28
|
+
if (ofs) {
|
|
29
|
+
ofs << line << std::endl;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
11
33
|
void HandleDeviceLost(const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView message)
|
|
12
34
|
{
|
|
13
|
-
std::
|
|
14
|
-
|
|
35
|
+
const std::string line = "[Dawn] Device lost (" + std::to_string(static_cast<int>(reason))
|
|
36
|
+
+ "): " + std::string(message.data, message.length);
|
|
37
|
+
std::cerr << line << std::endl;
|
|
38
|
+
AppendGpuLog(line);
|
|
15
39
|
}
|
|
16
40
|
|
|
17
41
|
void HandleUncapturedError(const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView message)
|
|
18
42
|
{
|
|
19
|
-
std::
|
|
20
|
-
|
|
43
|
+
const std::string line = "[Dawn] Uncaptured error (" + std::to_string(static_cast<int>(type))
|
|
44
|
+
+ "): " + std::string(message.data, message.length);
|
|
45
|
+
std::cerr << line << std::endl;
|
|
46
|
+
AppendGpuLog(line);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- GPU Blob キャッシュ (シェーダ/パイプラインのコンパイル結果) -------------
|
|
50
|
+
// D3D12 の HLSL コンパイル (FXC) はパイプライン初回生成時に走り、起動直後や
|
|
51
|
+
// 新しいエフェクト初出時のフレームヒッチの原因になる。Dawn の BlobCache を
|
|
52
|
+
// %LOCALAPPDATA%\Next2D\gpucache に永続化し、2 回目以降の起動で再利用する
|
|
53
|
+
// (V8 バイトコードキャッシュの GPU 版)。
|
|
54
|
+
// 呼び出し規約 (dawn/native/BlobCache.cpp LoadInternal で検証済み):
|
|
55
|
+
// load は 2 段階 — まず value=nullptr でサイズ問い合わせ (戻り値 0 = miss)、
|
|
56
|
+
// 次に確保済みバッファへの読み込み (戻り値がサイズと不一致なら miss 扱い)。
|
|
57
|
+
// キーには Dawn がアダプタ/ドライバ情報を織り込むため、環境が変われば自然に
|
|
58
|
+
// 別エントリになる。あらゆる失敗は 0 / 何もしない (graceful degrade)。
|
|
59
|
+
|
|
60
|
+
uint64_t Fnv1a(const void* data, size_t size, uint64_t hash = 1469598103934665603ull)
|
|
61
|
+
{
|
|
62
|
+
const auto* p = static_cast<const unsigned char*>(data);
|
|
63
|
+
for (size_t i = 0; i < size; ++i) {
|
|
64
|
+
hash ^= p[i];
|
|
65
|
+
hash *= 1099511628211ull;
|
|
66
|
+
}
|
|
67
|
+
return hash;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const std::filesystem::path& GpuCacheDir()
|
|
71
|
+
{
|
|
72
|
+
static const std::filesystem::path dir = []() -> std::filesystem::path {
|
|
73
|
+
const char* base = std::getenv("LOCALAPPDATA");
|
|
74
|
+
if (!base || !*base) {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
std::error_code ec;
|
|
78
|
+
std::filesystem::path d = std::filesystem::path(base) / "Next2D" / "gpucache";
|
|
79
|
+
std::filesystem::create_directories(d, ec);
|
|
80
|
+
if (ec) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
// ドライバ/Dawn 更新でキーが変わると旧 blob は孤児になる。
|
|
84
|
+
// 30 日アクセスの無い .blob を掃除する (load ヒット時に touch する LRU)。
|
|
85
|
+
const auto now = std::filesystem::file_time_type::clock::now();
|
|
86
|
+
std::error_code iter_ec;
|
|
87
|
+
for (const auto& entry : std::filesystem::directory_iterator(d, iter_ec)) {
|
|
88
|
+
std::error_code e2;
|
|
89
|
+
if (entry.path().extension() != ".blob") {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const auto t = std::filesystem::last_write_time(entry.path(), e2);
|
|
93
|
+
if (!e2 && now - t > std::chrono::hours(24 * 30)) {
|
|
94
|
+
std::filesystem::remove(entry.path(), e2);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return d;
|
|
98
|
+
}();
|
|
99
|
+
return dir;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
std::filesystem::path GpuCacheFileFor(const void* key, size_t key_size)
|
|
103
|
+
{
|
|
104
|
+
const std::filesystem::path& dir = GpuCacheDir();
|
|
105
|
+
if (dir.empty()) {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
char buf[17] = {};
|
|
109
|
+
std::snprintf(buf, sizeof(buf), "%016llx",
|
|
110
|
+
static_cast<unsigned long long>(Fnv1a(key, key_size)));
|
|
111
|
+
return dir / (std::string(buf) + ".blob");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
size_t LoadGpuCacheData(const void* key, size_t key_size,
|
|
115
|
+
void* value, size_t value_size, void*)
|
|
116
|
+
{
|
|
117
|
+
const std::filesystem::path file = GpuCacheFileFor(key, key_size);
|
|
118
|
+
if (file.empty()) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
std::error_code ec;
|
|
122
|
+
const auto size = std::filesystem::file_size(file, ec);
|
|
123
|
+
if (ec || size == 0) {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
if (value == nullptr) {
|
|
127
|
+
// 1 段階目: サイズ問い合わせ
|
|
128
|
+
return static_cast<size_t>(size);
|
|
129
|
+
}
|
|
130
|
+
if (value_size < size) {
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
std::ifstream ifs(file, std::ios::binary);
|
|
134
|
+
if (!ifs || !ifs.read(static_cast<char*>(value), static_cast<std::streamsize>(size))) {
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
// 使用時に touch して 30 日掃除を LRU として機能させる
|
|
138
|
+
std::filesystem::last_write_time(
|
|
139
|
+
file, std::filesystem::file_time_type::clock::now(), ec);
|
|
140
|
+
return static_cast<size_t>(size);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void StoreGpuCacheData(const void* key, size_t key_size,
|
|
144
|
+
const void* value, size_t value_size, void*)
|
|
145
|
+
{
|
|
146
|
+
if (!value || value_size == 0) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const std::filesystem::path file = GpuCacheFileFor(key, key_size);
|
|
150
|
+
if (file.empty()) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
std::ofstream ofs(file, std::ios::binary | std::ios::trunc);
|
|
154
|
+
if (ofs) {
|
|
155
|
+
ofs.write(static_cast<const char*>(value),
|
|
156
|
+
static_cast<std::streamsize>(value_size));
|
|
157
|
+
}
|
|
21
158
|
}
|
|
22
159
|
|
|
23
160
|
} // namespace
|
|
@@ -96,6 +233,28 @@ bool DawnContext::AcquireDevice()
|
|
|
96
233
|
device_desc.SetDeviceLostCallback(wgpu::CallbackMode::AllowProcessEvents, HandleDeviceLost);
|
|
97
234
|
device_desc.SetUncapturedErrorCallback(HandleUncapturedError);
|
|
98
235
|
|
|
236
|
+
// GPU Blob キャッシュを接続する (シェーダコンパイル結果の永続化)。
|
|
237
|
+
// 関数ポインタは Dawn が device 生成時に BlobCache へコピーするため、
|
|
238
|
+
// この記述子自体は RequestDevice 完了までの生存で足りる。
|
|
239
|
+
wgpu::DawnCacheDeviceDescriptor cache_desc = {};
|
|
240
|
+
cache_desc.loadDataFunction = LoadGpuCacheData;
|
|
241
|
+
cache_desc.storeDataFunction = StoreGpuCacheData;
|
|
242
|
+
device_desc.nextInChain = &cache_desc;
|
|
243
|
+
|
|
244
|
+
#ifdef NDEBUG
|
|
245
|
+
// Release では Dawn の API 検証 (skip_validation) と robustness (OOB クランプ) を
|
|
246
|
+
// 無効化する。両方とも全描画コマンドのエンコードで毎フレーム CPU を消費する
|
|
247
|
+
// 安全網で、検証済みタイトルの出荷ビルドでは Chrome も同様に外す定番最適化。
|
|
248
|
+
// Debug ビルドでは有効のままにして検証エラーを検出できるようにする
|
|
249
|
+
// (エラーは HandleUncapturedError -> next2d-error.log へ出る)。
|
|
250
|
+
// toggle 名は Dawn 本体 src/dawn/native/Toggles.cpp 定義 (いずれも ToggleStage::Device)。
|
|
251
|
+
static const char* kReleaseToggles[] = {"skip_validation", "disable_robustness"};
|
|
252
|
+
wgpu::DawnTogglesDescriptor device_toggles = {};
|
|
253
|
+
device_toggles.enabledToggles = kReleaseToggles;
|
|
254
|
+
device_toggles.enabledToggleCount = 2;
|
|
255
|
+
cache_desc.nextInChain = &device_toggles; // device -> cache -> toggles
|
|
256
|
+
#endif
|
|
257
|
+
|
|
99
258
|
wgpu::Future device_future = adapter_.RequestDevice(
|
|
100
259
|
&device_desc,
|
|
101
260
|
wgpu::CallbackMode::AllowProcessEvents,
|
|
@@ -114,12 +273,13 @@ bool DawnContext::AcquireDevice()
|
|
|
114
273
|
return false;
|
|
115
274
|
}
|
|
116
275
|
|
|
117
|
-
// surface
|
|
276
|
+
// surface の優先フォーマットと CopySrc 可否 (デバッグ読み戻し用) を取得
|
|
118
277
|
wgpu::SurfaceCapabilities caps = {};
|
|
119
278
|
surface_.GetCapabilities(adapter_, &caps);
|
|
120
279
|
if (caps.formatCount > 0) {
|
|
121
280
|
format_ = caps.formats[0];
|
|
122
281
|
}
|
|
282
|
+
can_copy_src_ = (caps.usages & wgpu::TextureUsage::CopySrc) == wgpu::TextureUsage::CopySrc;
|
|
123
283
|
|
|
124
284
|
Configure(width_, height_);
|
|
125
285
|
return true;
|
|
@@ -137,6 +297,9 @@ void DawnContext::Configure(uint32_t width, uint32_t height)
|
|
|
137
297
|
wgpu::SurfaceConfiguration config = {};
|
|
138
298
|
config.device = device_;
|
|
139
299
|
config.format = format_;
|
|
300
|
+
// RenderAttachment のみ。CopySrc を足すと swapchain の flip 提示最適化が無効化され
|
|
301
|
+
// 提示ごとにコピーが挟まって重くなるため、描画確認が済んだ今は付けない
|
|
302
|
+
// (以前は DebugProbeSurface の黒画面調査用に付けていた)。
|
|
140
303
|
config.usage = wgpu::TextureUsage::RenderAttachment;
|
|
141
304
|
config.width = width_;
|
|
142
305
|
config.height = height_;
|
|
@@ -144,20 +307,95 @@ void DawnContext::Configure(uint32_t width, uint32_t height)
|
|
|
144
307
|
config.alphaMode = wgpu::CompositeAlphaMode::Opaque;
|
|
145
308
|
|
|
146
309
|
surface_.Configure(&config);
|
|
310
|
+
configured_ = true;
|
|
147
311
|
}
|
|
148
312
|
|
|
149
313
|
wgpu::Texture DawnContext::GetCurrentTexture()
|
|
150
314
|
{
|
|
315
|
+
if (!configured_) {
|
|
316
|
+
return nullptr;
|
|
317
|
+
}
|
|
151
318
|
wgpu::SurfaceTexture surface_texture = {};
|
|
152
319
|
surface_.GetCurrentTexture(&surface_texture);
|
|
320
|
+
frame_texture_acquired_ = true;
|
|
321
|
+
current_texture_ = surface_texture.texture;
|
|
153
322
|
return surface_texture.texture;
|
|
154
323
|
}
|
|
155
324
|
|
|
325
|
+
// 提示直前の surface 中央行を読み戻し、非黒ピクセル数をログする (黒画面調査用)。
|
|
326
|
+
// CI では目視できないため、これが「画面に何が出ているか」の唯一の証拠になる。
|
|
327
|
+
void DawnContext::DebugProbeSurface()
|
|
328
|
+
{
|
|
329
|
+
if (!can_copy_src_ || !current_texture_ || width_ == 0) {
|
|
330
|
+
std::cerr << "[GPU] surface probe unavailable (CopySrc="
|
|
331
|
+
<< (can_copy_src_ ? "yes" : "no") << ")" << std::endl;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const uint32_t row_bytes = width_ * 4;
|
|
336
|
+
wgpu::BufferDescriptor buf_desc = {};
|
|
337
|
+
buf_desc.size = (row_bytes + 3) & ~3u;
|
|
338
|
+
buf_desc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
|
|
339
|
+
wgpu::Buffer buffer = device_.CreateBuffer(&buf_desc);
|
|
340
|
+
|
|
341
|
+
wgpu::TexelCopyTextureInfo src = {};
|
|
342
|
+
src.texture = current_texture_;
|
|
343
|
+
src.origin = { 0, height_ / 2, 0 };
|
|
344
|
+
|
|
345
|
+
wgpu::TexelCopyBufferInfo dst = {};
|
|
346
|
+
dst.buffer = buffer;
|
|
347
|
+
dst.layout.offset = 0;
|
|
348
|
+
dst.layout.bytesPerRow = wgpu::kCopyStrideUndefined; // 1 行コピーでは不要
|
|
349
|
+
|
|
350
|
+
wgpu::Extent3D extent = { width_, 1, 1 };
|
|
351
|
+
|
|
352
|
+
wgpu::CommandEncoder encoder = device_.CreateCommandEncoder();
|
|
353
|
+
encoder.CopyTextureToBuffer(&src, &dst, &extent);
|
|
354
|
+
wgpu::CommandBuffer commands = encoder.Finish();
|
|
355
|
+
device_.GetQueue().Submit(1, &commands);
|
|
356
|
+
|
|
357
|
+
bool done = false;
|
|
358
|
+
wgpu::Future future = buffer.MapAsync(wgpu::MapMode::Read, 0, buf_desc.size,
|
|
359
|
+
wgpu::CallbackMode::AllowProcessEvents,
|
|
360
|
+
[&done](wgpu::MapAsyncStatus, wgpu::StringView) { done = true; });
|
|
361
|
+
// GPU 完了待ちは TimedWaitAny で行う (ProcessEvents の空スピンでは
|
|
362
|
+
// GPU がフレーム描画中のとき完了前にループ上限へ達する)
|
|
363
|
+
instance_.WaitAny(future, 2'000'000'000); // 2s
|
|
364
|
+
if (!done) {
|
|
365
|
+
std::cerr << "[GPU] surface probe: map timeout" << std::endl;
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const auto* px = static_cast<const uint8_t*>(buffer.GetConstMappedRange(0, buf_desc.size));
|
|
370
|
+
uint32_t non_black = 0;
|
|
371
|
+
for (uint32_t x = 0; px && x < width_; ++x) {
|
|
372
|
+
const uint8_t* p = px + static_cast<size_t>(x) * 4;
|
|
373
|
+
if (p[0] || p[1] || p[2]) {
|
|
374
|
+
++non_black;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
std::cerr << "[GPU] surface probe (present #" << present_count_
|
|
378
|
+
<< "): non-black " << non_black << "/" << width_ << " px";
|
|
379
|
+
if (px && width_ > 1) {
|
|
380
|
+
const uint8_t* c = px + static_cast<size_t>(width_ / 2) * 4;
|
|
381
|
+
std::cerr << ", center=(" << +c[0] << "," << +c[1] << "," << +c[2] << "," << +c[3] << ")";
|
|
382
|
+
}
|
|
383
|
+
std::cerr << std::endl;
|
|
384
|
+
buffer.Unmap();
|
|
385
|
+
}
|
|
386
|
+
|
|
156
387
|
void DawnContext::Present()
|
|
157
388
|
{
|
|
158
|
-
|
|
389
|
+
// 提示するのは「未構成でない」かつ「今フレーム GetCurrentTexture 済み」のときのみ。
|
|
390
|
+
// 取得なしで Present すると Dawn の検証エラーになる (描画しないフレームは提示しない)。
|
|
391
|
+
if (surface_ && configured_ && frame_texture_acquired_) {
|
|
392
|
+
++present_count_;
|
|
159
393
|
surface_.Present();
|
|
394
|
+
} else {
|
|
395
|
+
++present_skipped_;
|
|
160
396
|
}
|
|
397
|
+
frame_texture_acquired_ = false;
|
|
398
|
+
current_texture_ = nullptr;
|
|
161
399
|
}
|
|
162
400
|
|
|
163
401
|
void DawnContext::Tick()
|
|
@@ -36,6 +36,9 @@ public:
|
|
|
36
36
|
// 提示する。
|
|
37
37
|
void Present();
|
|
38
38
|
|
|
39
|
+
// 提示直前の surface 中央行を読み戻して非黒ピクセル数をログする (黒画面調査用)。
|
|
40
|
+
void DebugProbeSurface();
|
|
41
|
+
|
|
39
42
|
// Dawn の非同期イベント(コールバック)を進める。毎フレーム呼ぶ。
|
|
40
43
|
void Tick();
|
|
41
44
|
|
|
@@ -59,6 +62,21 @@ private:
|
|
|
59
62
|
HWND hwnd_ = nullptr;
|
|
60
63
|
uint32_t width_ = 0;
|
|
61
64
|
uint32_t height_ = 0;
|
|
65
|
+
|
|
66
|
+
// surface が Configure 済みか。未構成のまま Present すると Dawn の
|
|
67
|
+
// 検証エラーが毎フレーム出るため、Present/GetCurrentTexture をゲートする。
|
|
68
|
+
bool configured_ = false;
|
|
69
|
+
|
|
70
|
+
// 今フレーム GetCurrentTexture が呼ばれたか。呼ばれていないフレームで
|
|
71
|
+
// Present すると Dawn の検証エラーになるため、Present をゲートする
|
|
72
|
+
// (アプリが描画しないフレームは提示しない)。
|
|
73
|
+
bool frame_texture_acquired_ = false;
|
|
74
|
+
|
|
75
|
+
// デバッグ用: surface の CopySrc 可否 / 今フレームのテクスチャ / 提示統計
|
|
76
|
+
bool can_copy_src_ = false;
|
|
77
|
+
wgpu::Texture current_texture_ = nullptr;
|
|
78
|
+
uint64_t present_count_ = 0;
|
|
79
|
+
uint64_t present_skipped_ = 0;
|
|
62
80
|
};
|
|
63
81
|
|
|
64
82
|
} // namespace next2d
|