plusui-native-core 0.1.104 → 0.1.106
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/Core/.claude/settings.local.json +7 -0
- package/Core/CMakeLists.txt +1 -1
- package/Core/Features/API/Connect_API.ts +20 -52
- package/Core/Features/API/app-api.ts +28 -28
- package/Core/Features/API/browser-api.ts +38 -38
- package/Core/Features/API/clipboard-api.ts +21 -21
- package/Core/Features/API/display-api.ts +33 -33
- package/Core/Features/API/keyboard-api.ts +33 -33
- package/Core/Features/API/menu-api.ts +39 -39
- package/Core/Features/API/router-api.ts +23 -23
- package/Core/Features/API/tray-api.ts +22 -22
- package/Core/Features/API/webgpu-api.ts +55 -55
- package/Core/Features/App/app.cpp +128 -102
- package/Core/Features/Browser/browser.cpp +227 -227
- package/Core/Features/Browser/browser.ts +161 -161
- package/Core/Features/Clipboard/clipboard.cpp +235 -235
- package/Core/Features/Display/display.cpp +212 -212
- package/Core/Features/FileDrop/filedrop.cpp +448 -324
- package/Core/Features/FileDrop/filedrop.css +421 -421
- package/Core/Features/FileDrop/filedrop.ts +5 -9
- package/Core/Features/Keyboard/keyboard_linux.cpp +4 -0
- package/Core/Features/Router/router.cpp +62 -62
- package/Core/Features/Router/router.ts +113 -113
- package/Core/Features/Tray/tray.cpp +328 -324
- package/Core/Features/WebGPU/webgpu.cpp +948 -948
- package/Core/Features/Window/webview.cpp +1026 -1014
- package/Core/Features/Window/webview.ts +516 -516
- package/Core/Features/Window/window.cpp +2265 -1988
- package/Core/include/plusui/api.hpp +237 -237
- package/Core/include/plusui/app.hpp +33 -33
- package/Core/include/plusui/browser.hpp +67 -67
- package/Core/include/plusui/clipboard.hpp +41 -41
- package/Core/include/plusui/connect.hpp +340 -340
- package/Core/include/plusui/connection.hpp +3 -3
- package/Core/include/plusui/display.hpp +90 -90
- package/Core/include/plusui/filedrop.hpp +92 -77
- package/Core/include/plusui/keyboard.hpp +112 -112
- package/Core/include/plusui/menu.hpp +153 -153
- package/Core/include/plusui/plusui +18 -18
- package/Core/include/plusui/router.hpp +42 -42
- package/Core/include/plusui/tray.hpp +94 -94
- package/Core/include/plusui/webgpu.hpp +434 -434
- package/Core/include/plusui/window.hpp +180 -177
- package/Core/scripts/generate-umbrella-header.mjs +77 -77
- package/Core/vendor/WebView2EnvironmentOptions.h +406 -406
- package/Core/vendor/webview.h +487 -487
- package/Core/vendor/webview2.h +52079 -52079
- package/README.md +19 -19
- package/package.json +1 -1
|
@@ -1,948 +1,948 @@
|
|
|
1
|
-
#include <plusui/webgpu.hpp>
|
|
2
|
-
|
|
3
|
-
#ifdef _WIN32
|
|
4
|
-
#pragma warning(push)
|
|
5
|
-
#pragma warning(disable: 4100) // Suppress unreferenced parameter warnings - placeholder implementations
|
|
6
|
-
#endif
|
|
7
|
-
|
|
8
|
-
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
9
|
-
#include <dawn/webgpu_cpp.h>
|
|
10
|
-
#include <dawn_native/DawnNative.h>
|
|
11
|
-
#include <dawn_proc/dawn_proc.h>
|
|
12
|
-
#include <nlohmann/json.hpp>
|
|
13
|
-
#endif
|
|
14
|
-
|
|
15
|
-
#include <memory>
|
|
16
|
-
#include <sstream>
|
|
17
|
-
#include <iostream>
|
|
18
|
-
#include <iomanip>
|
|
19
|
-
|
|
20
|
-
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
21
|
-
using json = nlohmann::json;
|
|
22
|
-
#endif
|
|
23
|
-
|
|
24
|
-
namespace plusui {
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @brief Implementation details for WebGPU using Pimpl idiom
|
|
28
|
-
*/
|
|
29
|
-
struct WebGPU::Impl {
|
|
30
|
-
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
31
|
-
wgpu::Instance instance;
|
|
32
|
-
std::unordered_map<std::string, wgpu::Adapter> adapters;
|
|
33
|
-
std::unordered_map<std::string, wgpu::Device> devices;
|
|
34
|
-
std::unordered_map<std::string, wgpu::Buffer> buffers;
|
|
35
|
-
std::unordered_map<std::string, wgpu::Texture> textures;
|
|
36
|
-
std::unordered_map<std::string, wgpu::TextureView> textureViews;
|
|
37
|
-
std::unordered_map<std::string, wgpu::Sampler> samplers;
|
|
38
|
-
std::unordered_map<std::string, wgpu::ShaderModule> shaderModules;
|
|
39
|
-
std::unordered_map<std::string, wgpu::RenderPipeline> renderPipelines;
|
|
40
|
-
std::unordered_map<std::string, wgpu::ComputePipeline> computePipelines;
|
|
41
|
-
std::unordered_map<std::string, wgpu::BindGroupLayout> bindGroupLayouts;
|
|
42
|
-
std::unordered_map<std::string, wgpu::BindGroup> bindGroups;
|
|
43
|
-
std::unordered_map<std::string, wgpu::CommandEncoder> commandEncoders;
|
|
44
|
-
std::unordered_map<std::string, wgpu::RenderPassEncoder> renderPasses;
|
|
45
|
-
std::unordered_map<std::string, wgpu::CommandBuffer> commandBuffers;
|
|
46
|
-
std::unordered_map<std::string, wgpu::Surface> surfaces;
|
|
47
|
-
std::unordered_map<std::string, wgpu::SwapChain> swapChains;
|
|
48
|
-
|
|
49
|
-
// Resource counter for generating unique IDs
|
|
50
|
-
uint64_t resourceCounter = 0;
|
|
51
|
-
#endif
|
|
52
|
-
|
|
53
|
-
WebGPUConfig config;
|
|
54
|
-
bool initialized = false;
|
|
55
|
-
|
|
56
|
-
#ifdef _WIN32
|
|
57
|
-
// Windows-specific members can be added here
|
|
58
|
-
#elif defined(__APPLE__)
|
|
59
|
-
// macOS-specific members can be added here
|
|
60
|
-
#else
|
|
61
|
-
// Linux-specific members can be added here
|
|
62
|
-
#endif
|
|
63
|
-
|
|
64
|
-
Impl() = default;
|
|
65
|
-
~Impl() = default;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// ============================================================================
|
|
69
|
-
// WebGPU Implementation
|
|
70
|
-
// ============================================================================
|
|
71
|
-
|
|
72
|
-
WebGPU::WebGPU() : pImpl(std::make_shared<Impl>()) {}
|
|
73
|
-
|
|
74
|
-
WebGPU::~WebGPU() {
|
|
75
|
-
if (pImpl && pImpl->initialized) {
|
|
76
|
-
destroy();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
WebGPU::WebGPU(WebGPU&&) noexcept = default;
|
|
81
|
-
WebGPU& WebGPU::operator=(WebGPU&&) noexcept = default;
|
|
82
|
-
|
|
83
|
-
WebGPU WebGPU::create(const WebGPUConfig& config) {
|
|
84
|
-
WebGPU instance;
|
|
85
|
-
instance.pImpl->config = config;
|
|
86
|
-
return instance;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
bool WebGPU::initialize() {
|
|
90
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
91
|
-
if (pImpl->config.verbose) {
|
|
92
|
-
std::cerr << "WebGPU: Support not compiled (PLUSUI_WEBGPU_ENABLED not defined)\n";
|
|
93
|
-
}
|
|
94
|
-
return false;
|
|
95
|
-
#else
|
|
96
|
-
if (pImpl->initialized) {
|
|
97
|
-
if (pImpl->config.verbose) {
|
|
98
|
-
std::cout << "WebGPU: Already initialized\n";
|
|
99
|
-
}
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!pImpl->config.enabled) {
|
|
104
|
-
if (pImpl->config.verbose) {
|
|
105
|
-
std::cout << "WebGPU: Disabled in configuration\n";
|
|
106
|
-
}
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
// Initialize the Dawn proc table
|
|
112
|
-
dawnProcSetProcs(dawn_native::GetProcs());
|
|
113
|
-
|
|
114
|
-
// Create the instance
|
|
115
|
-
WGPUInstanceDescriptor instanceDesc{};
|
|
116
|
-
pImpl->instance = wgpu::Instance(wgpuCreateInstance(&instanceDesc));
|
|
117
|
-
|
|
118
|
-
if (!pImpl->instance) {
|
|
119
|
-
std::cerr << "WebGPU: Failed to create instance\n";
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
pImpl->initialized = true;
|
|
124
|
-
|
|
125
|
-
if (pImpl->config.verbose) {
|
|
126
|
-
std::cout << "WebGPU: Initialization successful\n";
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return true;
|
|
130
|
-
} catch (const std::exception& e) {
|
|
131
|
-
std::cerr << "WebGPU: Initialization error: " << e.what() << "\n";
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
#endif
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
void WebGPU::destroy() {
|
|
138
|
-
if (!pImpl->initialized) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
143
|
-
// Destroy all resources in reverse order of dependency
|
|
144
|
-
pImpl->renderPasses.clear();
|
|
145
|
-
pImpl->commandEncoders.clear();
|
|
146
|
-
pImpl->commandBuffers.clear();
|
|
147
|
-
pImpl->renderPipelines.clear();
|
|
148
|
-
pImpl->computePipelines.clear();
|
|
149
|
-
pImpl->bindGroups.clear();
|
|
150
|
-
pImpl->bindGroupLayouts.clear();
|
|
151
|
-
pImpl->shaderModules.clear();
|
|
152
|
-
pImpl->samplers.clear();
|
|
153
|
-
pImpl->textureViews.clear();
|
|
154
|
-
pImpl->textures.clear();
|
|
155
|
-
pImpl->buffers.clear();
|
|
156
|
-
pImpl->swapChains.clear();
|
|
157
|
-
pImpl->surfaces.clear();
|
|
158
|
-
pImpl->devices.clear();
|
|
159
|
-
pImpl->adapters.clear();
|
|
160
|
-
pImpl->instance = nullptr;
|
|
161
|
-
#endif
|
|
162
|
-
|
|
163
|
-
pImpl->initialized = false;
|
|
164
|
-
|
|
165
|
-
if (pImpl->config.verbose) {
|
|
166
|
-
std::cout << "WebGPU: Shutdown complete\n";
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
bool WebGPU::isAvailable() const {
|
|
171
|
-
return pImpl->initialized;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ============================================================================
|
|
175
|
-
// Utility Functions
|
|
176
|
-
// ============================================================================
|
|
177
|
-
|
|
178
|
-
namespace {
|
|
179
|
-
std::string generateHandle(const std::string& prefix, uint64_t& counter) {
|
|
180
|
-
std::ostringstream oss;
|
|
181
|
-
oss << prefix << "_" << std::hex << ++counter;
|
|
182
|
-
return oss.str();
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ============================================================================
|
|
187
|
-
// Adapter API
|
|
188
|
-
// ============================================================================
|
|
189
|
-
|
|
190
|
-
std::string WebGPU::requestAdapter(const std::string& options) {
|
|
191
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
192
|
-
return "";
|
|
193
|
-
#else
|
|
194
|
-
if (!pImpl->initialized) {
|
|
195
|
-
if (pImpl->config.verbose) {
|
|
196
|
-
std::cerr << "WebGPU: Not initialized\n";
|
|
197
|
-
}
|
|
198
|
-
return "";
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
WGPURequestAdapterOptions wgpuOptions{};
|
|
203
|
-
|
|
204
|
-
// Parse options from JSON if provided
|
|
205
|
-
if (!options.empty() && options != "{}") {
|
|
206
|
-
try {
|
|
207
|
-
json opts = json::parse(options);
|
|
208
|
-
// Parse power preference if provided
|
|
209
|
-
if (opts.contains("powerPreference")) {
|
|
210
|
-
std::string powerPref = opts["powerPreference"];
|
|
211
|
-
if (powerPref == "low-power") {
|
|
212
|
-
wgpuOptions.powerPreference = WGPUPowerPreference_LowPower;
|
|
213
|
-
} else if (powerPref == "high-performance") {
|
|
214
|
-
wgpuOptions.powerPreference = WGPUPowerPreference_HighPerformance;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
} catch (const std::exception& e) {
|
|
218
|
-
std::cerr << "WebGPU: Failed to parse options: " << e.what() << "\n";
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
WGPUAdapter wgpuAdapter = wgpuInstanceRequestAdapter(pImpl->instance.Get(), &wgpuOptions);
|
|
223
|
-
|
|
224
|
-
if (!wgpuAdapter) {
|
|
225
|
-
if (pImpl->config.verbose) {
|
|
226
|
-
std::cerr << "WebGPU: No suitable adapter found\n";
|
|
227
|
-
}
|
|
228
|
-
return "";
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Store the adapter
|
|
232
|
-
std::string adapterId = generateHandle("adapter", pImpl->resourceCounter);
|
|
233
|
-
pImpl->adapters[adapterId] = wgpu::Adapter(wgpuAdapter);
|
|
234
|
-
|
|
235
|
-
// Build response JSON
|
|
236
|
-
json response;
|
|
237
|
-
response["id"] = adapterId;
|
|
238
|
-
response["type"] = "adapter";
|
|
239
|
-
response["features"] = json::array();
|
|
240
|
-
response["limits"] = json::object();
|
|
241
|
-
response["limits"]["maxBindGroups"] = 8;
|
|
242
|
-
response["limits"]["maxDynamicUniformBuffersPerPipelineLayout"] = 8;
|
|
243
|
-
response["limits"]["maxDynamicStorageBuffersPerPipelineLayout"] = 4;
|
|
244
|
-
|
|
245
|
-
if (pImpl->config.verbose) {
|
|
246
|
-
std::cout << "WebGPU: Adapter created: " << adapterId << "\n";
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return response.dump();
|
|
250
|
-
} catch (const std::exception& e) {
|
|
251
|
-
std::cerr << "WebGPU: Error in requestAdapter: " << e.what() << "\n";
|
|
252
|
-
return "";
|
|
253
|
-
}
|
|
254
|
-
#endif
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
std::string WebGPU::getAdapters() {
|
|
258
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
259
|
-
return "[]";
|
|
260
|
-
#else
|
|
261
|
-
json adaptersJson = json::array();
|
|
262
|
-
for (const auto& [id, _] : pImpl->adapters) {
|
|
263
|
-
adaptersJson.push_back(id);
|
|
264
|
-
}
|
|
265
|
-
return adaptersJson.dump();
|
|
266
|
-
#endif
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// ============================================================================
|
|
270
|
-
// Device API
|
|
271
|
-
// ============================================================================
|
|
272
|
-
|
|
273
|
-
std::string WebGPU::requestDevice(const std::string& adapterId, const std::string& descriptor) {
|
|
274
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
275
|
-
return "";
|
|
276
|
-
#else
|
|
277
|
-
if (!pImpl->initialized) {
|
|
278
|
-
return "";
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Find the adapter
|
|
282
|
-
auto adapterIt = pImpl->adapters.find(adapterId);
|
|
283
|
-
if (adapterIt == pImpl->adapters.end()) {
|
|
284
|
-
if (pImpl->config.verbose) {
|
|
285
|
-
std::cerr << "WebGPU: Adapter not found: " << adapterId << "\n";
|
|
286
|
-
}
|
|
287
|
-
return "";
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
try {
|
|
291
|
-
WGPUDeviceDescriptor wgpuDescriptor{};
|
|
292
|
-
wgpuDescriptor.label = "Device";
|
|
293
|
-
|
|
294
|
-
WGPUDevice wgpuDevice = wgpuAdapterRequestDevice(adapterIt->second.Get(), &wgpuDescriptor);
|
|
295
|
-
|
|
296
|
-
if (!wgpuDevice) {
|
|
297
|
-
if (pImpl->config.verbose) {
|
|
298
|
-
std::cerr << "WebGPU: Failed to create device\n";
|
|
299
|
-
}
|
|
300
|
-
return "";
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
std::string deviceId = generateHandle("device", pImpl->resourceCounter);
|
|
304
|
-
pImpl->devices[deviceId] = wgpu::Device(wgpuDevice);
|
|
305
|
-
|
|
306
|
-
// Set error callback
|
|
307
|
-
auto errorCallback = [](WGPUErrorType type, const char* message, void* userdata) {
|
|
308
|
-
std::cerr << "WebGPU Error: " << message << "\n";
|
|
309
|
-
};
|
|
310
|
-
wgpuDeviceSetUncapturedErrorCallback(wgpuDevice, errorCallback, nullptr);
|
|
311
|
-
|
|
312
|
-
json response;
|
|
313
|
-
response["id"] = deviceId;
|
|
314
|
-
response["type"] = "device";
|
|
315
|
-
response["features"] = json::array();
|
|
316
|
-
response["limits"] = json::object();
|
|
317
|
-
|
|
318
|
-
if (pImpl->config.verbose) {
|
|
319
|
-
std::cout << "WebGPU: Device created: " << deviceId << "\n";
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return response.dump();
|
|
323
|
-
} catch (const std::exception& e) {
|
|
324
|
-
std::cerr << "WebGPU: Error in requestDevice: " << e.what() << "\n";
|
|
325
|
-
return "";
|
|
326
|
-
}
|
|
327
|
-
#endif
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
std::string WebGPU::getDeviceInfo(const std::string& deviceId) {
|
|
331
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
332
|
-
return "{}";
|
|
333
|
-
#else
|
|
334
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
335
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
336
|
-
return "{}";
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
json info;
|
|
340
|
-
info["id"] = deviceId;
|
|
341
|
-
info["features"] = json::array();
|
|
342
|
-
info["limits"] = json::object();
|
|
343
|
-
return info.dump();
|
|
344
|
-
#endif
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// ============================================================================
|
|
348
|
-
// Buffer API
|
|
349
|
-
// ============================================================================
|
|
350
|
-
|
|
351
|
-
std::string WebGPU::createBuffer(const std::string& deviceId, const std::string& descriptor) {
|
|
352
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
353
|
-
return "";
|
|
354
|
-
#else
|
|
355
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
356
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
357
|
-
return "";
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
try {
|
|
361
|
-
json desc = json::parse(descriptor);
|
|
362
|
-
|
|
363
|
-
WGPUBufferDescriptor wgpuDesc{};
|
|
364
|
-
wgpuDesc.size = desc.value("size", 256UL);
|
|
365
|
-
wgpuDesc.usage = desc.value("usage", WGPUBufferUsage_CopyDst | WGPUBufferUsage_CopySrc);
|
|
366
|
-
wgpuDesc.mappedAtCreation = desc.value("mappedAtCreation", false);
|
|
367
|
-
|
|
368
|
-
WGPUBuffer wgpuBuffer = wgpuDeviceCreateBuffer(deviceIt->second.Get(), &wgpuDesc);
|
|
369
|
-
|
|
370
|
-
if (!wgpuBuffer) {
|
|
371
|
-
if (pImpl->config.verbose) {
|
|
372
|
-
std::cerr << "WebGPU: Failed to create buffer\n";
|
|
373
|
-
}
|
|
374
|
-
return "";
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
std::string bufferId = generateHandle("buffer", pImpl->resourceCounter);
|
|
378
|
-
pImpl->buffers[bufferId] = wgpu::Buffer(wgpuBuffer);
|
|
379
|
-
|
|
380
|
-
json response;
|
|
381
|
-
response["handle"] = bufferId;
|
|
382
|
-
response["size"] = wgpuDesc.size;
|
|
383
|
-
|
|
384
|
-
return response.dump();
|
|
385
|
-
} catch (const std::exception& e) {
|
|
386
|
-
std::cerr << "WebGPU: Error in createBuffer: " << e.what() << "\n";
|
|
387
|
-
return "";
|
|
388
|
-
}
|
|
389
|
-
#endif
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
bool WebGPU::writeBuffer(const std::string& bufferId, uint32_t offset, const std::string& data) {
|
|
393
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
394
|
-
return false;
|
|
395
|
-
#else
|
|
396
|
-
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
397
|
-
if (bufferIt == pImpl->buffers.end()) {
|
|
398
|
-
return false;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// TODO: Implement data decoding (base64 or hex)
|
|
402
|
-
// For now, just mark as successful
|
|
403
|
-
return true;
|
|
404
|
-
#endif
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
bool WebGPU::mapBuffer(const std::string& bufferId, const std::string& mode) {
|
|
408
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
409
|
-
return false;
|
|
410
|
-
#else
|
|
411
|
-
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
412
|
-
if (bufferIt == pImpl->buffers.end()) {
|
|
413
|
-
return false;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
WGPUMapMode mapMode = (mode == "read") ? WGPUMapMode_Read : WGPUMapMode_Write;
|
|
417
|
-
auto mapAsyncCallback = [](WGPUBufferMapAsyncStatus status, void* userdata) {
|
|
418
|
-
if (status != WGPUBufferMapAsyncStatus_Success) {
|
|
419
|
-
std::cerr << "WebGPU: Buffer mapping failed\n";
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
wgpuBufferMapAsync(bufferIt->second.Get(), mapMode, 0, bufferIt->second.GetSize(), mapAsyncCallback, nullptr);
|
|
424
|
-
return true;
|
|
425
|
-
#endif
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
bool WebGPU::unmapBuffer(const std::string& bufferId) {
|
|
429
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
430
|
-
return false;
|
|
431
|
-
#else
|
|
432
|
-
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
433
|
-
if (bufferIt == pImpl->buffers.end()) {
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
wgpuBufferUnmap(bufferIt->second.Get());
|
|
438
|
-
return true;
|
|
439
|
-
#endif
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
std::string WebGPU::getMappedBufferData(const std::string& bufferId) {
|
|
443
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
444
|
-
return "";
|
|
445
|
-
#else
|
|
446
|
-
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
447
|
-
if (bufferIt == pImpl->buffers.end()) {
|
|
448
|
-
return "";
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// TODO: Implement data retrieval and encoding
|
|
452
|
-
return "";
|
|
453
|
-
#endif
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// ============================================================================
|
|
457
|
-
// Texture API
|
|
458
|
-
// ============================================================================
|
|
459
|
-
|
|
460
|
-
std::string WebGPU::createTexture(const std::string& deviceId, const std::string& descriptor) {
|
|
461
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
462
|
-
return "";
|
|
463
|
-
#else
|
|
464
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
465
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
466
|
-
return "";
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
try {
|
|
470
|
-
json desc = json::parse(descriptor);
|
|
471
|
-
|
|
472
|
-
WGPUTextureDescriptor wgpuDesc{};
|
|
473
|
-
wgpuDesc.size = {
|
|
474
|
-
.width = desc.value("width", 256U),
|
|
475
|
-
.height = desc.value("height", 256U),
|
|
476
|
-
.depthOrArrayLayers = desc.value("depthOrArrayLayers", 1U)
|
|
477
|
-
};
|
|
478
|
-
wgpuDesc.mipLevelCount = desc.value("mipLevelCount", 1U);
|
|
479
|
-
wgpuDesc.sampleCount = desc.value("sampleCount", 1U);
|
|
480
|
-
wgpuDesc.dimension = WGPUTextureDimension_2D;
|
|
481
|
-
wgpuDesc.format = WGPUTextureFormat_BGRA8Unorm; // Default format
|
|
482
|
-
wgpuDesc.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_CopyDst;
|
|
483
|
-
|
|
484
|
-
WGPUTexture wgpuTexture = wgpuDeviceCreateTexture(deviceIt->second.Get(), &wgpuDesc);
|
|
485
|
-
|
|
486
|
-
if (!wgpuTexture) {
|
|
487
|
-
if (pImpl->config.verbose) {
|
|
488
|
-
std::cerr << "WebGPU: Failed to create texture\n";
|
|
489
|
-
}
|
|
490
|
-
return "";
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
std::string textureId = generateHandle("texture", pImpl->resourceCounter);
|
|
494
|
-
pImpl->textures[textureId] = wgpu::Texture(wgpuTexture);
|
|
495
|
-
|
|
496
|
-
json response;
|
|
497
|
-
response["handle"] = textureId;
|
|
498
|
-
response["width"] = wgpuDesc.size.width;
|
|
499
|
-
response["height"] = wgpuDesc.size.height;
|
|
500
|
-
|
|
501
|
-
return response.dump();
|
|
502
|
-
} catch (const std::exception& e) {
|
|
503
|
-
std::cerr << "WebGPU: Error in createTexture: " << e.what() << "\n";
|
|
504
|
-
return "";
|
|
505
|
-
}
|
|
506
|
-
#endif
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
bool WebGPU::writeTexture(const std::string& textureId, const std::string& descriptor, const std::string& data) {
|
|
510
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
511
|
-
return false;
|
|
512
|
-
#else
|
|
513
|
-
auto textureIt = pImpl->textures.find(textureId);
|
|
514
|
-
if (textureIt == pImpl->textures.end()) {
|
|
515
|
-
return false;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// TODO: Implement texture data upload
|
|
519
|
-
return true;
|
|
520
|
-
#endif
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
std::string WebGPU::createTextureView(const std::string& textureId, const std::string& descriptor) {
|
|
524
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
525
|
-
return "";
|
|
526
|
-
#else
|
|
527
|
-
auto textureIt = pImpl->textures.find(textureId);
|
|
528
|
-
if (textureIt == pImpl->textures.end()) {
|
|
529
|
-
return "";
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
try {
|
|
533
|
-
WGPUTextureViewDescriptor wgpuDesc{};
|
|
534
|
-
|
|
535
|
-
WGPUTextureView wgpuView = wgpuTextureCreateView(textureIt->second.Get(), &wgpuDesc);
|
|
536
|
-
|
|
537
|
-
if (!wgpuView) {
|
|
538
|
-
return "";
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
std::string viewId = generateHandle("textureview", pImpl->resourceCounter);
|
|
542
|
-
pImpl->textureViews[viewId] = wgpu::TextureView(wgpuView);
|
|
543
|
-
|
|
544
|
-
return viewId;
|
|
545
|
-
} catch (const std::exception& e) {
|
|
546
|
-
std::cerr << "WebGPU: Error in createTextureView: " << e.what() << "\n";
|
|
547
|
-
return "";
|
|
548
|
-
}
|
|
549
|
-
#endif
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// ============================================================================
|
|
553
|
-
// Sampler API
|
|
554
|
-
// ============================================================================
|
|
555
|
-
|
|
556
|
-
std::string WebGPU::createSampler(const std::string& deviceId, const std::string& descriptor) {
|
|
557
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
558
|
-
return "";
|
|
559
|
-
#else
|
|
560
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
561
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
562
|
-
return "";
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
try {
|
|
566
|
-
WGPUSamplerDescriptor wgpuDesc{};
|
|
567
|
-
wgpuDesc.magFilter = WGPUFilterMode_Linear;
|
|
568
|
-
wgpuDesc.minFilter = WGPUFilterMode_Linear;
|
|
569
|
-
wgpuDesc.mipmapFilter = WGPUFilterMode_Linear;
|
|
570
|
-
wgpuDesc.addressModeU = WGPUAddressMode_ClampToEdge;
|
|
571
|
-
wgpuDesc.addressModeV = WGPUAddressMode_ClampToEdge;
|
|
572
|
-
wgpuDesc.addressModeW = WGPUAddressMode_ClampToEdge;
|
|
573
|
-
|
|
574
|
-
WGPUSampler wgpuSampler = wgpuDeviceCreateSampler(deviceIt->second.Get(), &wgpuDesc);
|
|
575
|
-
|
|
576
|
-
if (!wgpuSampler) {
|
|
577
|
-
return "";
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
std::string samplerId = generateHandle("sampler", pImpl->resourceCounter);
|
|
581
|
-
pImpl->samplers[samplerId] = wgpu::Sampler(wgpuSampler);
|
|
582
|
-
|
|
583
|
-
return samplerId;
|
|
584
|
-
} catch (const std::exception& e) {
|
|
585
|
-
std::cerr << "WebGPU: Error in createSampler: " << e.what() << "\n";
|
|
586
|
-
return "";
|
|
587
|
-
}
|
|
588
|
-
#endif
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// ============================================================================
|
|
592
|
-
// Shader API
|
|
593
|
-
// ============================================================================
|
|
594
|
-
|
|
595
|
-
std::string WebGPU::createShaderModule(const std::string& deviceId, const std::string& wgslSource) {
|
|
596
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
597
|
-
return "";
|
|
598
|
-
#else
|
|
599
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
600
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
601
|
-
return "";
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
try {
|
|
605
|
-
WGPUShaderModuleDescriptor wgpuDesc{};
|
|
606
|
-
WGPUShaderModuleWGSLDescriptor wgslDesc{};
|
|
607
|
-
wgslDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
|
608
|
-
wgslDesc.code = wgslSource.c_str();
|
|
609
|
-
wgpuDesc.nextInChain = &wgslDesc.chain;
|
|
610
|
-
|
|
611
|
-
WGPUShaderModule wgpuShader = wgpuDeviceCreateShaderModule(deviceIt->second.Get(), &wgpuDesc);
|
|
612
|
-
|
|
613
|
-
if (!wgpuShader) {
|
|
614
|
-
if (pImpl->config.verbose) {
|
|
615
|
-
std::cerr << "WebGPU: Failed to create shader module\n";
|
|
616
|
-
}
|
|
617
|
-
return "";
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
std::string shaderId = generateHandle("shader", pImpl->resourceCounter);
|
|
621
|
-
pImpl->shaderModules[shaderId] = wgpu::ShaderModule(wgpuShader);
|
|
622
|
-
|
|
623
|
-
return shaderId;
|
|
624
|
-
} catch (const std::exception& e) {
|
|
625
|
-
std::cerr << "WebGPU: Error in createShaderModule: " << e.what() << "\n";
|
|
626
|
-
return "";
|
|
627
|
-
}
|
|
628
|
-
#endif
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
std::string WebGPU::getShaderErrors(const std::string& shaderId) {
|
|
632
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
633
|
-
return "{}";
|
|
634
|
-
#else
|
|
635
|
-
// TODO: Implement shader error reporting
|
|
636
|
-
return "{}";
|
|
637
|
-
#endif
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// ============================================================================
|
|
641
|
-
// Pipeline API
|
|
642
|
-
// ============================================================================
|
|
643
|
-
|
|
644
|
-
std::string WebGPU::createRenderPipeline(const std::string& deviceId, const std::string& descriptor) {
|
|
645
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
646
|
-
return "";
|
|
647
|
-
#else
|
|
648
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
649
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
650
|
-
return "";
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// TODO: Implement full pipeline creation
|
|
654
|
-
std::string pipelineId = generateHandle("pipeline", pImpl->resourceCounter);
|
|
655
|
-
return pipelineId;
|
|
656
|
-
#endif
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
std::string WebGPU::createComputePipeline(const std::string& deviceId, const std::string& descriptor) {
|
|
660
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
661
|
-
return "";
|
|
662
|
-
#else
|
|
663
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
664
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
665
|
-
return "";
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// TODO: Implement compute pipeline creation
|
|
669
|
-
std::string pipelineId = generateHandle("pipeline", pImpl->resourceCounter);
|
|
670
|
-
return pipelineId;
|
|
671
|
-
#endif
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
std::string WebGPU::getPipelineInfo(const std::string& pipelineId) {
|
|
675
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
676
|
-
return "{}";
|
|
677
|
-
#else
|
|
678
|
-
json info;
|
|
679
|
-
info["id"] = pipelineId;
|
|
680
|
-
return info.dump();
|
|
681
|
-
#endif
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// ============================================================================
|
|
685
|
-
// Bind Group API
|
|
686
|
-
// ============================================================================
|
|
687
|
-
|
|
688
|
-
std::string WebGPU::createBindGroupLayout(const std::string& deviceId, const std::string& descriptor) {
|
|
689
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
690
|
-
return "";
|
|
691
|
-
#else
|
|
692
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
693
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
694
|
-
return "";
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
std::string layoutId = generateHandle("bindgrouplayout", pImpl->resourceCounter);
|
|
698
|
-
return layoutId;
|
|
699
|
-
#endif
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
std::string WebGPU::createBindGroup(const std::string& deviceId, const std::string& descriptor) {
|
|
703
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
704
|
-
return "";
|
|
705
|
-
#else
|
|
706
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
707
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
708
|
-
return "";
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
std::string bindGroupId = generateHandle("bindgroup", pImpl->resourceCounter);
|
|
712
|
-
return bindGroupId;
|
|
713
|
-
#endif
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// ============================================================================
|
|
717
|
-
// Surface API
|
|
718
|
-
// ============================================================================
|
|
719
|
-
|
|
720
|
-
std::string WebGPU::createSurface(void* windowHandle, uint32_t width, uint32_t height) {
|
|
721
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
722
|
-
return "";
|
|
723
|
-
#else
|
|
724
|
-
if (!pImpl->initialized) {
|
|
725
|
-
return "";
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
std::string surfaceId = generateHandle("surface", pImpl->resourceCounter);
|
|
729
|
-
|
|
730
|
-
if (pImpl->config.verbose) {
|
|
731
|
-
std::cout << "WebGPU: Surface created: " << surfaceId << "\n";
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
return surfaceId;
|
|
735
|
-
#endif
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
bool WebGPU::configureSurface(const std::string& surfaceId, const std::string& descriptor) {
|
|
739
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
740
|
-
return false;
|
|
741
|
-
#else
|
|
742
|
-
return true;
|
|
743
|
-
#endif
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
bool WebGPU::resizeSurface(const std::string& surfaceId, uint32_t width, uint32_t height) {
|
|
747
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
748
|
-
return false;
|
|
749
|
-
#else
|
|
750
|
-
return true;
|
|
751
|
-
#endif
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
std::string WebGPU::getNextTexture(const std::string& surfaceId) {
|
|
755
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
756
|
-
return "";
|
|
757
|
-
#else
|
|
758
|
-
std::string textureId = generateHandle("texture", pImpl->resourceCounter);
|
|
759
|
-
return textureId;
|
|
760
|
-
#endif
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// ============================================================================
|
|
764
|
-
// Command Encoding API
|
|
765
|
-
// ============================================================================
|
|
766
|
-
|
|
767
|
-
std::string WebGPU::createCommandEncoder(const std::string& deviceId) {
|
|
768
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
769
|
-
return "";
|
|
770
|
-
#else
|
|
771
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
772
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
773
|
-
return "";
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
std::string encoderId = generateHandle("encoder", pImpl->resourceCounter);
|
|
777
|
-
return encoderId;
|
|
778
|
-
#endif
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
std::string WebGPU::beginRenderPass(const std::string& encoderId, const std::string& descriptor) {
|
|
782
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
783
|
-
return "";
|
|
784
|
-
#else
|
|
785
|
-
std::string passId = generateHandle("renderpass", pImpl->resourceCounter);
|
|
786
|
-
return passId;
|
|
787
|
-
#endif
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
bool WebGPU::endRenderPass(const std::string& passId) {
|
|
791
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
792
|
-
return false;
|
|
793
|
-
#else
|
|
794
|
-
return true;
|
|
795
|
-
#endif
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
bool WebGPU::setRenderPipeline(const std::string& passId, const std::string& pipelineId) {
|
|
799
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
800
|
-
return false;
|
|
801
|
-
#else
|
|
802
|
-
return true;
|
|
803
|
-
#endif
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
bool WebGPU::setBindGroup(const std::string& passId, uint32_t groupIndex, const std::string& bindGroupId) {
|
|
807
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
808
|
-
return false;
|
|
809
|
-
#else
|
|
810
|
-
return true;
|
|
811
|
-
#endif
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
bool WebGPU::setVertexBuffer(const std::string& passId, uint32_t slot, const std::string& bufferId, uint64_t offset) {
|
|
815
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
816
|
-
return false;
|
|
817
|
-
#else
|
|
818
|
-
return true;
|
|
819
|
-
#endif
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
bool WebGPU::setIndexBuffer(const std::string& passId, const std::string& bufferId, const std::string& format, uint64_t offset) {
|
|
823
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
824
|
-
return false;
|
|
825
|
-
#else
|
|
826
|
-
return true;
|
|
827
|
-
#endif
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
bool WebGPU::draw(const std::string& passId, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) {
|
|
831
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
832
|
-
return false;
|
|
833
|
-
#else
|
|
834
|
-
return true;
|
|
835
|
-
#endif
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
bool WebGPU::drawIndexed(const std::string& passId, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t baseVertex, uint32_t firstInstance) {
|
|
839
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
840
|
-
return false;
|
|
841
|
-
#else
|
|
842
|
-
return true;
|
|
843
|
-
#endif
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
std::string WebGPU::finish(const std::string& encoderId) {
|
|
847
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
848
|
-
return "";
|
|
849
|
-
#else
|
|
850
|
-
std::string bufferId = generateHandle("cmdbuffer", pImpl->resourceCounter);
|
|
851
|
-
return bufferId;
|
|
852
|
-
#endif
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// ============================================================================
|
|
856
|
-
// Queue API
|
|
857
|
-
// ============================================================================
|
|
858
|
-
|
|
859
|
-
bool WebGPU::submitCommands(const std::string& deviceId, const std::string& commandBufferIds) {
|
|
860
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
861
|
-
return false;
|
|
862
|
-
#else
|
|
863
|
-
auto deviceIt = pImpl->devices.find(deviceId);
|
|
864
|
-
if (deviceIt == pImpl->devices.end()) {
|
|
865
|
-
return false;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
return true;
|
|
869
|
-
#endif
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
bool WebGPU::presentSurface(const std::string& surfaceId) {
|
|
873
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
874
|
-
return false;
|
|
875
|
-
#else
|
|
876
|
-
return true;
|
|
877
|
-
#endif
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
// ============================================================================
|
|
881
|
-
// Resource Management
|
|
882
|
-
// ============================================================================
|
|
883
|
-
|
|
884
|
-
bool WebGPU::destroyResource(const std::string& handle) {
|
|
885
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
886
|
-
(void)handle;
|
|
887
|
-
return false;
|
|
888
|
-
#else
|
|
889
|
-
// Try to find and erase from all resource maps
|
|
890
|
-
pImpl->buffers.erase(handle);
|
|
891
|
-
pImpl->textures.erase(handle);
|
|
892
|
-
pImpl->textureViews.erase(handle);
|
|
893
|
-
pImpl->samplers.erase(handle);
|
|
894
|
-
pImpl->shaderModules.erase(handle);
|
|
895
|
-
pImpl->renderPipelines.erase(handle);
|
|
896
|
-
pImpl->computePipelines.erase(handle);
|
|
897
|
-
pImpl->bindGroups.erase(handle);
|
|
898
|
-
pImpl->bindGroupLayouts.erase(handle);
|
|
899
|
-
pImpl->surfaces.erase(handle);
|
|
900
|
-
pImpl->swapChains.erase(handle);
|
|
901
|
-
pImpl->commandBuffers.erase(handle);
|
|
902
|
-
pImpl->adapters.erase(handle);
|
|
903
|
-
|
|
904
|
-
return true;
|
|
905
|
-
#endif
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
bool WebGPU::destroyDevice(const std::string& deviceId) {
|
|
909
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
910
|
-
(void)deviceId;
|
|
911
|
-
return false;
|
|
912
|
-
#else
|
|
913
|
-
// Destroy all resources associated with device
|
|
914
|
-
pImpl->buffers.clear();
|
|
915
|
-
pImpl->textures.clear();
|
|
916
|
-
pImpl->textureViews.clear();
|
|
917
|
-
pImpl->samplers.clear();
|
|
918
|
-
pImpl->shaderModules.clear();
|
|
919
|
-
pImpl->renderPipelines.clear();
|
|
920
|
-
pImpl->computePipelines.clear();
|
|
921
|
-
pImpl->bindGroups.clear();
|
|
922
|
-
|
|
923
|
-
pImpl->devices.erase(deviceId);
|
|
924
|
-
|
|
925
|
-
return true;
|
|
926
|
-
#endif
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
std::string WebGPU::getMemoryStats() {
|
|
930
|
-
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
931
|
-
return "{}";
|
|
932
|
-
#else
|
|
933
|
-
json stats;
|
|
934
|
-
stats["buffers"] = pImpl->buffers.size();
|
|
935
|
-
stats["textures"] = pImpl->textures.size();
|
|
936
|
-
stats["samplers"] = pImpl->samplers.size();
|
|
937
|
-
stats["shaders"] = pImpl->shaderModules.size();
|
|
938
|
-
stats["pipelines"] = pImpl->renderPipelines.size() + pImpl->computePipelines.size();
|
|
939
|
-
stats["devices"] = pImpl->devices.size();
|
|
940
|
-
return stats.dump();
|
|
941
|
-
#endif
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
} // namespace plusui
|
|
945
|
-
|
|
946
|
-
#ifdef _WIN32
|
|
947
|
-
#pragma warning(pop)
|
|
948
|
-
#endif
|
|
1
|
+
#include <plusui/webgpu.hpp>
|
|
2
|
+
|
|
3
|
+
#ifdef _WIN32
|
|
4
|
+
#pragma warning(push)
|
|
5
|
+
#pragma warning(disable: 4100) // Suppress unreferenced parameter warnings - placeholder implementations
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
9
|
+
#include <dawn/webgpu_cpp.h>
|
|
10
|
+
#include <dawn_native/DawnNative.h>
|
|
11
|
+
#include <dawn_proc/dawn_proc.h>
|
|
12
|
+
#include <nlohmann/json.hpp>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <sstream>
|
|
17
|
+
#include <iostream>
|
|
18
|
+
#include <iomanip>
|
|
19
|
+
|
|
20
|
+
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
21
|
+
using json = nlohmann::json;
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
namespace plusui {
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @brief Implementation details for WebGPU using Pimpl idiom
|
|
28
|
+
*/
|
|
29
|
+
struct WebGPU::Impl {
|
|
30
|
+
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
31
|
+
wgpu::Instance instance;
|
|
32
|
+
std::unordered_map<std::string, wgpu::Adapter> adapters;
|
|
33
|
+
std::unordered_map<std::string, wgpu::Device> devices;
|
|
34
|
+
std::unordered_map<std::string, wgpu::Buffer> buffers;
|
|
35
|
+
std::unordered_map<std::string, wgpu::Texture> textures;
|
|
36
|
+
std::unordered_map<std::string, wgpu::TextureView> textureViews;
|
|
37
|
+
std::unordered_map<std::string, wgpu::Sampler> samplers;
|
|
38
|
+
std::unordered_map<std::string, wgpu::ShaderModule> shaderModules;
|
|
39
|
+
std::unordered_map<std::string, wgpu::RenderPipeline> renderPipelines;
|
|
40
|
+
std::unordered_map<std::string, wgpu::ComputePipeline> computePipelines;
|
|
41
|
+
std::unordered_map<std::string, wgpu::BindGroupLayout> bindGroupLayouts;
|
|
42
|
+
std::unordered_map<std::string, wgpu::BindGroup> bindGroups;
|
|
43
|
+
std::unordered_map<std::string, wgpu::CommandEncoder> commandEncoders;
|
|
44
|
+
std::unordered_map<std::string, wgpu::RenderPassEncoder> renderPasses;
|
|
45
|
+
std::unordered_map<std::string, wgpu::CommandBuffer> commandBuffers;
|
|
46
|
+
std::unordered_map<std::string, wgpu::Surface> surfaces;
|
|
47
|
+
std::unordered_map<std::string, wgpu::SwapChain> swapChains;
|
|
48
|
+
|
|
49
|
+
// Resource counter for generating unique IDs
|
|
50
|
+
uint64_t resourceCounter = 0;
|
|
51
|
+
#endif
|
|
52
|
+
|
|
53
|
+
WebGPUConfig config;
|
|
54
|
+
bool initialized = false;
|
|
55
|
+
|
|
56
|
+
#ifdef _WIN32
|
|
57
|
+
// Windows-specific members can be added here
|
|
58
|
+
#elif defined(__APPLE__)
|
|
59
|
+
// macOS-specific members can be added here
|
|
60
|
+
#else
|
|
61
|
+
// Linux-specific members can be added here
|
|
62
|
+
#endif
|
|
63
|
+
|
|
64
|
+
Impl() = default;
|
|
65
|
+
~Impl() = default;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// WebGPU Implementation
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
WebGPU::WebGPU() : pImpl(std::make_shared<Impl>()) {}
|
|
73
|
+
|
|
74
|
+
WebGPU::~WebGPU() {
|
|
75
|
+
if (pImpl && pImpl->initialized) {
|
|
76
|
+
destroy();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
WebGPU::WebGPU(WebGPU&&) noexcept = default;
|
|
81
|
+
WebGPU& WebGPU::operator=(WebGPU&&) noexcept = default;
|
|
82
|
+
|
|
83
|
+
WebGPU WebGPU::create(const WebGPUConfig& config) {
|
|
84
|
+
WebGPU instance;
|
|
85
|
+
instance.pImpl->config = config;
|
|
86
|
+
return instance;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
bool WebGPU::initialize() {
|
|
90
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
91
|
+
if (pImpl->config.verbose) {
|
|
92
|
+
std::cerr << "WebGPU: Support not compiled (PLUSUI_WEBGPU_ENABLED not defined)\n";
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
#else
|
|
96
|
+
if (pImpl->initialized) {
|
|
97
|
+
if (pImpl->config.verbose) {
|
|
98
|
+
std::cout << "WebGPU: Already initialized\n";
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!pImpl->config.enabled) {
|
|
104
|
+
if (pImpl->config.verbose) {
|
|
105
|
+
std::cout << "WebGPU: Disabled in configuration\n";
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
// Initialize the Dawn proc table
|
|
112
|
+
dawnProcSetProcs(dawn_native::GetProcs());
|
|
113
|
+
|
|
114
|
+
// Create the instance
|
|
115
|
+
WGPUInstanceDescriptor instanceDesc{};
|
|
116
|
+
pImpl->instance = wgpu::Instance(wgpuCreateInstance(&instanceDesc));
|
|
117
|
+
|
|
118
|
+
if (!pImpl->instance) {
|
|
119
|
+
std::cerr << "WebGPU: Failed to create instance\n";
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pImpl->initialized = true;
|
|
124
|
+
|
|
125
|
+
if (pImpl->config.verbose) {
|
|
126
|
+
std::cout << "WebGPU: Initialization successful\n";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
} catch (const std::exception& e) {
|
|
131
|
+
std::cerr << "WebGPU: Initialization error: " << e.what() << "\n";
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
#endif
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void WebGPU::destroy() {
|
|
138
|
+
if (!pImpl->initialized) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#ifdef PLUSUI_WEBGPU_ENABLED
|
|
143
|
+
// Destroy all resources in reverse order of dependency
|
|
144
|
+
pImpl->renderPasses.clear();
|
|
145
|
+
pImpl->commandEncoders.clear();
|
|
146
|
+
pImpl->commandBuffers.clear();
|
|
147
|
+
pImpl->renderPipelines.clear();
|
|
148
|
+
pImpl->computePipelines.clear();
|
|
149
|
+
pImpl->bindGroups.clear();
|
|
150
|
+
pImpl->bindGroupLayouts.clear();
|
|
151
|
+
pImpl->shaderModules.clear();
|
|
152
|
+
pImpl->samplers.clear();
|
|
153
|
+
pImpl->textureViews.clear();
|
|
154
|
+
pImpl->textures.clear();
|
|
155
|
+
pImpl->buffers.clear();
|
|
156
|
+
pImpl->swapChains.clear();
|
|
157
|
+
pImpl->surfaces.clear();
|
|
158
|
+
pImpl->devices.clear();
|
|
159
|
+
pImpl->adapters.clear();
|
|
160
|
+
pImpl->instance = nullptr;
|
|
161
|
+
#endif
|
|
162
|
+
|
|
163
|
+
pImpl->initialized = false;
|
|
164
|
+
|
|
165
|
+
if (pImpl->config.verbose) {
|
|
166
|
+
std::cout << "WebGPU: Shutdown complete\n";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
bool WebGPU::isAvailable() const {
|
|
171
|
+
return pImpl->initialized;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ============================================================================
|
|
175
|
+
// Utility Functions
|
|
176
|
+
// ============================================================================
|
|
177
|
+
|
|
178
|
+
namespace {
|
|
179
|
+
std::string generateHandle(const std::string& prefix, uint64_t& counter) {
|
|
180
|
+
std::ostringstream oss;
|
|
181
|
+
oss << prefix << "_" << std::hex << ++counter;
|
|
182
|
+
return oss.str();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ============================================================================
|
|
187
|
+
// Adapter API
|
|
188
|
+
// ============================================================================
|
|
189
|
+
|
|
190
|
+
std::string WebGPU::requestAdapter(const std::string& options) {
|
|
191
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
192
|
+
return "";
|
|
193
|
+
#else
|
|
194
|
+
if (!pImpl->initialized) {
|
|
195
|
+
if (pImpl->config.verbose) {
|
|
196
|
+
std::cerr << "WebGPU: Not initialized\n";
|
|
197
|
+
}
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
WGPURequestAdapterOptions wgpuOptions{};
|
|
203
|
+
|
|
204
|
+
// Parse options from JSON if provided
|
|
205
|
+
if (!options.empty() && options != "{}") {
|
|
206
|
+
try {
|
|
207
|
+
json opts = json::parse(options);
|
|
208
|
+
// Parse power preference if provided
|
|
209
|
+
if (opts.contains("powerPreference")) {
|
|
210
|
+
std::string powerPref = opts["powerPreference"];
|
|
211
|
+
if (powerPref == "low-power") {
|
|
212
|
+
wgpuOptions.powerPreference = WGPUPowerPreference_LowPower;
|
|
213
|
+
} else if (powerPref == "high-performance") {
|
|
214
|
+
wgpuOptions.powerPreference = WGPUPowerPreference_HighPerformance;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (const std::exception& e) {
|
|
218
|
+
std::cerr << "WebGPU: Failed to parse options: " << e.what() << "\n";
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
WGPUAdapter wgpuAdapter = wgpuInstanceRequestAdapter(pImpl->instance.Get(), &wgpuOptions);
|
|
223
|
+
|
|
224
|
+
if (!wgpuAdapter) {
|
|
225
|
+
if (pImpl->config.verbose) {
|
|
226
|
+
std::cerr << "WebGPU: No suitable adapter found\n";
|
|
227
|
+
}
|
|
228
|
+
return "";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Store the adapter
|
|
232
|
+
std::string adapterId = generateHandle("adapter", pImpl->resourceCounter);
|
|
233
|
+
pImpl->adapters[adapterId] = wgpu::Adapter(wgpuAdapter);
|
|
234
|
+
|
|
235
|
+
// Build response JSON
|
|
236
|
+
json response;
|
|
237
|
+
response["id"] = adapterId;
|
|
238
|
+
response["type"] = "adapter";
|
|
239
|
+
response["features"] = json::array();
|
|
240
|
+
response["limits"] = json::object();
|
|
241
|
+
response["limits"]["maxBindGroups"] = 8;
|
|
242
|
+
response["limits"]["maxDynamicUniformBuffersPerPipelineLayout"] = 8;
|
|
243
|
+
response["limits"]["maxDynamicStorageBuffersPerPipelineLayout"] = 4;
|
|
244
|
+
|
|
245
|
+
if (pImpl->config.verbose) {
|
|
246
|
+
std::cout << "WebGPU: Adapter created: " << adapterId << "\n";
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return response.dump();
|
|
250
|
+
} catch (const std::exception& e) {
|
|
251
|
+
std::cerr << "WebGPU: Error in requestAdapter: " << e.what() << "\n";
|
|
252
|
+
return "";
|
|
253
|
+
}
|
|
254
|
+
#endif
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
std::string WebGPU::getAdapters() {
|
|
258
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
259
|
+
return "[]";
|
|
260
|
+
#else
|
|
261
|
+
json adaptersJson = json::array();
|
|
262
|
+
for (const auto& [id, _] : pImpl->adapters) {
|
|
263
|
+
adaptersJson.push_back(id);
|
|
264
|
+
}
|
|
265
|
+
return adaptersJson.dump();
|
|
266
|
+
#endif
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// Device API
|
|
271
|
+
// ============================================================================
|
|
272
|
+
|
|
273
|
+
std::string WebGPU::requestDevice(const std::string& adapterId, const std::string& descriptor) {
|
|
274
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
275
|
+
return "";
|
|
276
|
+
#else
|
|
277
|
+
if (!pImpl->initialized) {
|
|
278
|
+
return "";
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Find the adapter
|
|
282
|
+
auto adapterIt = pImpl->adapters.find(adapterId);
|
|
283
|
+
if (adapterIt == pImpl->adapters.end()) {
|
|
284
|
+
if (pImpl->config.verbose) {
|
|
285
|
+
std::cerr << "WebGPU: Adapter not found: " << adapterId << "\n";
|
|
286
|
+
}
|
|
287
|
+
return "";
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
WGPUDeviceDescriptor wgpuDescriptor{};
|
|
292
|
+
wgpuDescriptor.label = "Device";
|
|
293
|
+
|
|
294
|
+
WGPUDevice wgpuDevice = wgpuAdapterRequestDevice(adapterIt->second.Get(), &wgpuDescriptor);
|
|
295
|
+
|
|
296
|
+
if (!wgpuDevice) {
|
|
297
|
+
if (pImpl->config.verbose) {
|
|
298
|
+
std::cerr << "WebGPU: Failed to create device\n";
|
|
299
|
+
}
|
|
300
|
+
return "";
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
std::string deviceId = generateHandle("device", pImpl->resourceCounter);
|
|
304
|
+
pImpl->devices[deviceId] = wgpu::Device(wgpuDevice);
|
|
305
|
+
|
|
306
|
+
// Set error callback
|
|
307
|
+
auto errorCallback = [](WGPUErrorType type, const char* message, void* userdata) {
|
|
308
|
+
std::cerr << "WebGPU Error: " << message << "\n";
|
|
309
|
+
};
|
|
310
|
+
wgpuDeviceSetUncapturedErrorCallback(wgpuDevice, errorCallback, nullptr);
|
|
311
|
+
|
|
312
|
+
json response;
|
|
313
|
+
response["id"] = deviceId;
|
|
314
|
+
response["type"] = "device";
|
|
315
|
+
response["features"] = json::array();
|
|
316
|
+
response["limits"] = json::object();
|
|
317
|
+
|
|
318
|
+
if (pImpl->config.verbose) {
|
|
319
|
+
std::cout << "WebGPU: Device created: " << deviceId << "\n";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return response.dump();
|
|
323
|
+
} catch (const std::exception& e) {
|
|
324
|
+
std::cerr << "WebGPU: Error in requestDevice: " << e.what() << "\n";
|
|
325
|
+
return "";
|
|
326
|
+
}
|
|
327
|
+
#endif
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
std::string WebGPU::getDeviceInfo(const std::string& deviceId) {
|
|
331
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
332
|
+
return "{}";
|
|
333
|
+
#else
|
|
334
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
335
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
336
|
+
return "{}";
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
json info;
|
|
340
|
+
info["id"] = deviceId;
|
|
341
|
+
info["features"] = json::array();
|
|
342
|
+
info["limits"] = json::object();
|
|
343
|
+
return info.dump();
|
|
344
|
+
#endif
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ============================================================================
|
|
348
|
+
// Buffer API
|
|
349
|
+
// ============================================================================
|
|
350
|
+
|
|
351
|
+
std::string WebGPU::createBuffer(const std::string& deviceId, const std::string& descriptor) {
|
|
352
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
353
|
+
return "";
|
|
354
|
+
#else
|
|
355
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
356
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
357
|
+
return "";
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
json desc = json::parse(descriptor);
|
|
362
|
+
|
|
363
|
+
WGPUBufferDescriptor wgpuDesc{};
|
|
364
|
+
wgpuDesc.size = desc.value("size", 256UL);
|
|
365
|
+
wgpuDesc.usage = desc.value("usage", WGPUBufferUsage_CopyDst | WGPUBufferUsage_CopySrc);
|
|
366
|
+
wgpuDesc.mappedAtCreation = desc.value("mappedAtCreation", false);
|
|
367
|
+
|
|
368
|
+
WGPUBuffer wgpuBuffer = wgpuDeviceCreateBuffer(deviceIt->second.Get(), &wgpuDesc);
|
|
369
|
+
|
|
370
|
+
if (!wgpuBuffer) {
|
|
371
|
+
if (pImpl->config.verbose) {
|
|
372
|
+
std::cerr << "WebGPU: Failed to create buffer\n";
|
|
373
|
+
}
|
|
374
|
+
return "";
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
std::string bufferId = generateHandle("buffer", pImpl->resourceCounter);
|
|
378
|
+
pImpl->buffers[bufferId] = wgpu::Buffer(wgpuBuffer);
|
|
379
|
+
|
|
380
|
+
json response;
|
|
381
|
+
response["handle"] = bufferId;
|
|
382
|
+
response["size"] = wgpuDesc.size;
|
|
383
|
+
|
|
384
|
+
return response.dump();
|
|
385
|
+
} catch (const std::exception& e) {
|
|
386
|
+
std::cerr << "WebGPU: Error in createBuffer: " << e.what() << "\n";
|
|
387
|
+
return "";
|
|
388
|
+
}
|
|
389
|
+
#endif
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
bool WebGPU::writeBuffer(const std::string& bufferId, uint32_t offset, const std::string& data) {
|
|
393
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
394
|
+
return false;
|
|
395
|
+
#else
|
|
396
|
+
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
397
|
+
if (bufferIt == pImpl->buffers.end()) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// TODO: Implement data decoding (base64 or hex)
|
|
402
|
+
// For now, just mark as successful
|
|
403
|
+
return true;
|
|
404
|
+
#endif
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
bool WebGPU::mapBuffer(const std::string& bufferId, const std::string& mode) {
|
|
408
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
409
|
+
return false;
|
|
410
|
+
#else
|
|
411
|
+
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
412
|
+
if (bufferIt == pImpl->buffers.end()) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
WGPUMapMode mapMode = (mode == "read") ? WGPUMapMode_Read : WGPUMapMode_Write;
|
|
417
|
+
auto mapAsyncCallback = [](WGPUBufferMapAsyncStatus status, void* userdata) {
|
|
418
|
+
if (status != WGPUBufferMapAsyncStatus_Success) {
|
|
419
|
+
std::cerr << "WebGPU: Buffer mapping failed\n";
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
wgpuBufferMapAsync(bufferIt->second.Get(), mapMode, 0, bufferIt->second.GetSize(), mapAsyncCallback, nullptr);
|
|
424
|
+
return true;
|
|
425
|
+
#endif
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
bool WebGPU::unmapBuffer(const std::string& bufferId) {
|
|
429
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
430
|
+
return false;
|
|
431
|
+
#else
|
|
432
|
+
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
433
|
+
if (bufferIt == pImpl->buffers.end()) {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
wgpuBufferUnmap(bufferIt->second.Get());
|
|
438
|
+
return true;
|
|
439
|
+
#endif
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
std::string WebGPU::getMappedBufferData(const std::string& bufferId) {
|
|
443
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
444
|
+
return "";
|
|
445
|
+
#else
|
|
446
|
+
auto bufferIt = pImpl->buffers.find(bufferId);
|
|
447
|
+
if (bufferIt == pImpl->buffers.end()) {
|
|
448
|
+
return "";
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// TODO: Implement data retrieval and encoding
|
|
452
|
+
return "";
|
|
453
|
+
#endif
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ============================================================================
|
|
457
|
+
// Texture API
|
|
458
|
+
// ============================================================================
|
|
459
|
+
|
|
460
|
+
std::string WebGPU::createTexture(const std::string& deviceId, const std::string& descriptor) {
|
|
461
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
462
|
+
return "";
|
|
463
|
+
#else
|
|
464
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
465
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
466
|
+
return "";
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
try {
|
|
470
|
+
json desc = json::parse(descriptor);
|
|
471
|
+
|
|
472
|
+
WGPUTextureDescriptor wgpuDesc{};
|
|
473
|
+
wgpuDesc.size = {
|
|
474
|
+
.width = desc.value("width", 256U),
|
|
475
|
+
.height = desc.value("height", 256U),
|
|
476
|
+
.depthOrArrayLayers = desc.value("depthOrArrayLayers", 1U)
|
|
477
|
+
};
|
|
478
|
+
wgpuDesc.mipLevelCount = desc.value("mipLevelCount", 1U);
|
|
479
|
+
wgpuDesc.sampleCount = desc.value("sampleCount", 1U);
|
|
480
|
+
wgpuDesc.dimension = WGPUTextureDimension_2D;
|
|
481
|
+
wgpuDesc.format = WGPUTextureFormat_BGRA8Unorm; // Default format
|
|
482
|
+
wgpuDesc.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_CopyDst;
|
|
483
|
+
|
|
484
|
+
WGPUTexture wgpuTexture = wgpuDeviceCreateTexture(deviceIt->second.Get(), &wgpuDesc);
|
|
485
|
+
|
|
486
|
+
if (!wgpuTexture) {
|
|
487
|
+
if (pImpl->config.verbose) {
|
|
488
|
+
std::cerr << "WebGPU: Failed to create texture\n";
|
|
489
|
+
}
|
|
490
|
+
return "";
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
std::string textureId = generateHandle("texture", pImpl->resourceCounter);
|
|
494
|
+
pImpl->textures[textureId] = wgpu::Texture(wgpuTexture);
|
|
495
|
+
|
|
496
|
+
json response;
|
|
497
|
+
response["handle"] = textureId;
|
|
498
|
+
response["width"] = wgpuDesc.size.width;
|
|
499
|
+
response["height"] = wgpuDesc.size.height;
|
|
500
|
+
|
|
501
|
+
return response.dump();
|
|
502
|
+
} catch (const std::exception& e) {
|
|
503
|
+
std::cerr << "WebGPU: Error in createTexture: " << e.what() << "\n";
|
|
504
|
+
return "";
|
|
505
|
+
}
|
|
506
|
+
#endif
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
bool WebGPU::writeTexture(const std::string& textureId, const std::string& descriptor, const std::string& data) {
|
|
510
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
511
|
+
return false;
|
|
512
|
+
#else
|
|
513
|
+
auto textureIt = pImpl->textures.find(textureId);
|
|
514
|
+
if (textureIt == pImpl->textures.end()) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// TODO: Implement texture data upload
|
|
519
|
+
return true;
|
|
520
|
+
#endif
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
std::string WebGPU::createTextureView(const std::string& textureId, const std::string& descriptor) {
|
|
524
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
525
|
+
return "";
|
|
526
|
+
#else
|
|
527
|
+
auto textureIt = pImpl->textures.find(textureId);
|
|
528
|
+
if (textureIt == pImpl->textures.end()) {
|
|
529
|
+
return "";
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
try {
|
|
533
|
+
WGPUTextureViewDescriptor wgpuDesc{};
|
|
534
|
+
|
|
535
|
+
WGPUTextureView wgpuView = wgpuTextureCreateView(textureIt->second.Get(), &wgpuDesc);
|
|
536
|
+
|
|
537
|
+
if (!wgpuView) {
|
|
538
|
+
return "";
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
std::string viewId = generateHandle("textureview", pImpl->resourceCounter);
|
|
542
|
+
pImpl->textureViews[viewId] = wgpu::TextureView(wgpuView);
|
|
543
|
+
|
|
544
|
+
return viewId;
|
|
545
|
+
} catch (const std::exception& e) {
|
|
546
|
+
std::cerr << "WebGPU: Error in createTextureView: " << e.what() << "\n";
|
|
547
|
+
return "";
|
|
548
|
+
}
|
|
549
|
+
#endif
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ============================================================================
|
|
553
|
+
// Sampler API
|
|
554
|
+
// ============================================================================
|
|
555
|
+
|
|
556
|
+
std::string WebGPU::createSampler(const std::string& deviceId, const std::string& descriptor) {
|
|
557
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
558
|
+
return "";
|
|
559
|
+
#else
|
|
560
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
561
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
562
|
+
return "";
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
try {
|
|
566
|
+
WGPUSamplerDescriptor wgpuDesc{};
|
|
567
|
+
wgpuDesc.magFilter = WGPUFilterMode_Linear;
|
|
568
|
+
wgpuDesc.minFilter = WGPUFilterMode_Linear;
|
|
569
|
+
wgpuDesc.mipmapFilter = WGPUFilterMode_Linear;
|
|
570
|
+
wgpuDesc.addressModeU = WGPUAddressMode_ClampToEdge;
|
|
571
|
+
wgpuDesc.addressModeV = WGPUAddressMode_ClampToEdge;
|
|
572
|
+
wgpuDesc.addressModeW = WGPUAddressMode_ClampToEdge;
|
|
573
|
+
|
|
574
|
+
WGPUSampler wgpuSampler = wgpuDeviceCreateSampler(deviceIt->second.Get(), &wgpuDesc);
|
|
575
|
+
|
|
576
|
+
if (!wgpuSampler) {
|
|
577
|
+
return "";
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
std::string samplerId = generateHandle("sampler", pImpl->resourceCounter);
|
|
581
|
+
pImpl->samplers[samplerId] = wgpu::Sampler(wgpuSampler);
|
|
582
|
+
|
|
583
|
+
return samplerId;
|
|
584
|
+
} catch (const std::exception& e) {
|
|
585
|
+
std::cerr << "WebGPU: Error in createSampler: " << e.what() << "\n";
|
|
586
|
+
return "";
|
|
587
|
+
}
|
|
588
|
+
#endif
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// ============================================================================
|
|
592
|
+
// Shader API
|
|
593
|
+
// ============================================================================
|
|
594
|
+
|
|
595
|
+
std::string WebGPU::createShaderModule(const std::string& deviceId, const std::string& wgslSource) {
|
|
596
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
597
|
+
return "";
|
|
598
|
+
#else
|
|
599
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
600
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
601
|
+
return "";
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
try {
|
|
605
|
+
WGPUShaderModuleDescriptor wgpuDesc{};
|
|
606
|
+
WGPUShaderModuleWGSLDescriptor wgslDesc{};
|
|
607
|
+
wgslDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
|
608
|
+
wgslDesc.code = wgslSource.c_str();
|
|
609
|
+
wgpuDesc.nextInChain = &wgslDesc.chain;
|
|
610
|
+
|
|
611
|
+
WGPUShaderModule wgpuShader = wgpuDeviceCreateShaderModule(deviceIt->second.Get(), &wgpuDesc);
|
|
612
|
+
|
|
613
|
+
if (!wgpuShader) {
|
|
614
|
+
if (pImpl->config.verbose) {
|
|
615
|
+
std::cerr << "WebGPU: Failed to create shader module\n";
|
|
616
|
+
}
|
|
617
|
+
return "";
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
std::string shaderId = generateHandle("shader", pImpl->resourceCounter);
|
|
621
|
+
pImpl->shaderModules[shaderId] = wgpu::ShaderModule(wgpuShader);
|
|
622
|
+
|
|
623
|
+
return shaderId;
|
|
624
|
+
} catch (const std::exception& e) {
|
|
625
|
+
std::cerr << "WebGPU: Error in createShaderModule: " << e.what() << "\n";
|
|
626
|
+
return "";
|
|
627
|
+
}
|
|
628
|
+
#endif
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
std::string WebGPU::getShaderErrors(const std::string& shaderId) {
|
|
632
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
633
|
+
return "{}";
|
|
634
|
+
#else
|
|
635
|
+
// TODO: Implement shader error reporting
|
|
636
|
+
return "{}";
|
|
637
|
+
#endif
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// ============================================================================
|
|
641
|
+
// Pipeline API
|
|
642
|
+
// ============================================================================
|
|
643
|
+
|
|
644
|
+
std::string WebGPU::createRenderPipeline(const std::string& deviceId, const std::string& descriptor) {
|
|
645
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
646
|
+
return "";
|
|
647
|
+
#else
|
|
648
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
649
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
650
|
+
return "";
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// TODO: Implement full pipeline creation
|
|
654
|
+
std::string pipelineId = generateHandle("pipeline", pImpl->resourceCounter);
|
|
655
|
+
return pipelineId;
|
|
656
|
+
#endif
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
std::string WebGPU::createComputePipeline(const std::string& deviceId, const std::string& descriptor) {
|
|
660
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
661
|
+
return "";
|
|
662
|
+
#else
|
|
663
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
664
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
665
|
+
return "";
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// TODO: Implement compute pipeline creation
|
|
669
|
+
std::string pipelineId = generateHandle("pipeline", pImpl->resourceCounter);
|
|
670
|
+
return pipelineId;
|
|
671
|
+
#endif
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
std::string WebGPU::getPipelineInfo(const std::string& pipelineId) {
|
|
675
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
676
|
+
return "{}";
|
|
677
|
+
#else
|
|
678
|
+
json info;
|
|
679
|
+
info["id"] = pipelineId;
|
|
680
|
+
return info.dump();
|
|
681
|
+
#endif
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// ============================================================================
|
|
685
|
+
// Bind Group API
|
|
686
|
+
// ============================================================================
|
|
687
|
+
|
|
688
|
+
std::string WebGPU::createBindGroupLayout(const std::string& deviceId, const std::string& descriptor) {
|
|
689
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
690
|
+
return "";
|
|
691
|
+
#else
|
|
692
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
693
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
694
|
+
return "";
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
std::string layoutId = generateHandle("bindgrouplayout", pImpl->resourceCounter);
|
|
698
|
+
return layoutId;
|
|
699
|
+
#endif
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
std::string WebGPU::createBindGroup(const std::string& deviceId, const std::string& descriptor) {
|
|
703
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
704
|
+
return "";
|
|
705
|
+
#else
|
|
706
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
707
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
708
|
+
return "";
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
std::string bindGroupId = generateHandle("bindgroup", pImpl->resourceCounter);
|
|
712
|
+
return bindGroupId;
|
|
713
|
+
#endif
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// ============================================================================
|
|
717
|
+
// Surface API
|
|
718
|
+
// ============================================================================
|
|
719
|
+
|
|
720
|
+
std::string WebGPU::createSurface(void* windowHandle, uint32_t width, uint32_t height) {
|
|
721
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
722
|
+
return "";
|
|
723
|
+
#else
|
|
724
|
+
if (!pImpl->initialized) {
|
|
725
|
+
return "";
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
std::string surfaceId = generateHandle("surface", pImpl->resourceCounter);
|
|
729
|
+
|
|
730
|
+
if (pImpl->config.verbose) {
|
|
731
|
+
std::cout << "WebGPU: Surface created: " << surfaceId << "\n";
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
return surfaceId;
|
|
735
|
+
#endif
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
bool WebGPU::configureSurface(const std::string& surfaceId, const std::string& descriptor) {
|
|
739
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
740
|
+
return false;
|
|
741
|
+
#else
|
|
742
|
+
return true;
|
|
743
|
+
#endif
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
bool WebGPU::resizeSurface(const std::string& surfaceId, uint32_t width, uint32_t height) {
|
|
747
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
748
|
+
return false;
|
|
749
|
+
#else
|
|
750
|
+
return true;
|
|
751
|
+
#endif
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
std::string WebGPU::getNextTexture(const std::string& surfaceId) {
|
|
755
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
756
|
+
return "";
|
|
757
|
+
#else
|
|
758
|
+
std::string textureId = generateHandle("texture", pImpl->resourceCounter);
|
|
759
|
+
return textureId;
|
|
760
|
+
#endif
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// ============================================================================
|
|
764
|
+
// Command Encoding API
|
|
765
|
+
// ============================================================================
|
|
766
|
+
|
|
767
|
+
std::string WebGPU::createCommandEncoder(const std::string& deviceId) {
|
|
768
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
769
|
+
return "";
|
|
770
|
+
#else
|
|
771
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
772
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
773
|
+
return "";
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
std::string encoderId = generateHandle("encoder", pImpl->resourceCounter);
|
|
777
|
+
return encoderId;
|
|
778
|
+
#endif
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
std::string WebGPU::beginRenderPass(const std::string& encoderId, const std::string& descriptor) {
|
|
782
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
783
|
+
return "";
|
|
784
|
+
#else
|
|
785
|
+
std::string passId = generateHandle("renderpass", pImpl->resourceCounter);
|
|
786
|
+
return passId;
|
|
787
|
+
#endif
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
bool WebGPU::endRenderPass(const std::string& passId) {
|
|
791
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
792
|
+
return false;
|
|
793
|
+
#else
|
|
794
|
+
return true;
|
|
795
|
+
#endif
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
bool WebGPU::setRenderPipeline(const std::string& passId, const std::string& pipelineId) {
|
|
799
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
800
|
+
return false;
|
|
801
|
+
#else
|
|
802
|
+
return true;
|
|
803
|
+
#endif
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
bool WebGPU::setBindGroup(const std::string& passId, uint32_t groupIndex, const std::string& bindGroupId) {
|
|
807
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
808
|
+
return false;
|
|
809
|
+
#else
|
|
810
|
+
return true;
|
|
811
|
+
#endif
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
bool WebGPU::setVertexBuffer(const std::string& passId, uint32_t slot, const std::string& bufferId, uint64_t offset) {
|
|
815
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
816
|
+
return false;
|
|
817
|
+
#else
|
|
818
|
+
return true;
|
|
819
|
+
#endif
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
bool WebGPU::setIndexBuffer(const std::string& passId, const std::string& bufferId, const std::string& format, uint64_t offset) {
|
|
823
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
824
|
+
return false;
|
|
825
|
+
#else
|
|
826
|
+
return true;
|
|
827
|
+
#endif
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
bool WebGPU::draw(const std::string& passId, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) {
|
|
831
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
832
|
+
return false;
|
|
833
|
+
#else
|
|
834
|
+
return true;
|
|
835
|
+
#endif
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
bool WebGPU::drawIndexed(const std::string& passId, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t baseVertex, uint32_t firstInstance) {
|
|
839
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
840
|
+
return false;
|
|
841
|
+
#else
|
|
842
|
+
return true;
|
|
843
|
+
#endif
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
std::string WebGPU::finish(const std::string& encoderId) {
|
|
847
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
848
|
+
return "";
|
|
849
|
+
#else
|
|
850
|
+
std::string bufferId = generateHandle("cmdbuffer", pImpl->resourceCounter);
|
|
851
|
+
return bufferId;
|
|
852
|
+
#endif
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// ============================================================================
|
|
856
|
+
// Queue API
|
|
857
|
+
// ============================================================================
|
|
858
|
+
|
|
859
|
+
bool WebGPU::submitCommands(const std::string& deviceId, const std::string& commandBufferIds) {
|
|
860
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
861
|
+
return false;
|
|
862
|
+
#else
|
|
863
|
+
auto deviceIt = pImpl->devices.find(deviceId);
|
|
864
|
+
if (deviceIt == pImpl->devices.end()) {
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return true;
|
|
869
|
+
#endif
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
bool WebGPU::presentSurface(const std::string& surfaceId) {
|
|
873
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
874
|
+
return false;
|
|
875
|
+
#else
|
|
876
|
+
return true;
|
|
877
|
+
#endif
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// ============================================================================
|
|
881
|
+
// Resource Management
|
|
882
|
+
// ============================================================================
|
|
883
|
+
|
|
884
|
+
bool WebGPU::destroyResource(const std::string& handle) {
|
|
885
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
886
|
+
(void)handle;
|
|
887
|
+
return false;
|
|
888
|
+
#else
|
|
889
|
+
// Try to find and erase from all resource maps
|
|
890
|
+
pImpl->buffers.erase(handle);
|
|
891
|
+
pImpl->textures.erase(handle);
|
|
892
|
+
pImpl->textureViews.erase(handle);
|
|
893
|
+
pImpl->samplers.erase(handle);
|
|
894
|
+
pImpl->shaderModules.erase(handle);
|
|
895
|
+
pImpl->renderPipelines.erase(handle);
|
|
896
|
+
pImpl->computePipelines.erase(handle);
|
|
897
|
+
pImpl->bindGroups.erase(handle);
|
|
898
|
+
pImpl->bindGroupLayouts.erase(handle);
|
|
899
|
+
pImpl->surfaces.erase(handle);
|
|
900
|
+
pImpl->swapChains.erase(handle);
|
|
901
|
+
pImpl->commandBuffers.erase(handle);
|
|
902
|
+
pImpl->adapters.erase(handle);
|
|
903
|
+
|
|
904
|
+
return true;
|
|
905
|
+
#endif
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
bool WebGPU::destroyDevice(const std::string& deviceId) {
|
|
909
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
910
|
+
(void)deviceId;
|
|
911
|
+
return false;
|
|
912
|
+
#else
|
|
913
|
+
// Destroy all resources associated with device
|
|
914
|
+
pImpl->buffers.clear();
|
|
915
|
+
pImpl->textures.clear();
|
|
916
|
+
pImpl->textureViews.clear();
|
|
917
|
+
pImpl->samplers.clear();
|
|
918
|
+
pImpl->shaderModules.clear();
|
|
919
|
+
pImpl->renderPipelines.clear();
|
|
920
|
+
pImpl->computePipelines.clear();
|
|
921
|
+
pImpl->bindGroups.clear();
|
|
922
|
+
|
|
923
|
+
pImpl->devices.erase(deviceId);
|
|
924
|
+
|
|
925
|
+
return true;
|
|
926
|
+
#endif
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
std::string WebGPU::getMemoryStats() {
|
|
930
|
+
#ifndef PLUSUI_WEBGPU_ENABLED
|
|
931
|
+
return "{}";
|
|
932
|
+
#else
|
|
933
|
+
json stats;
|
|
934
|
+
stats["buffers"] = pImpl->buffers.size();
|
|
935
|
+
stats["textures"] = pImpl->textures.size();
|
|
936
|
+
stats["samplers"] = pImpl->samplers.size();
|
|
937
|
+
stats["shaders"] = pImpl->shaderModules.size();
|
|
938
|
+
stats["pipelines"] = pImpl->renderPipelines.size() + pImpl->computePipelines.size();
|
|
939
|
+
stats["devices"] = pImpl->devices.size();
|
|
940
|
+
return stats.dump();
|
|
941
|
+
#endif
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
} // namespace plusui
|
|
945
|
+
|
|
946
|
+
#ifdef _WIN32
|
|
947
|
+
#pragma warning(pop)
|
|
948
|
+
#endif
|