plusui-native-core 0.1.3 → 0.1.5

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