Cogs.Core
GraphicsDeviceWebGPU.cpp
1#include "Foundation/Platform/WindowData.h"
2
3#include "GraphicsDeviceWebGPU.h"
4
5#ifndef EMSCRIPTEN
6#include "dawn/webgpu_cpp_print.h"
7#include "dawn/dawn_proc.h"
8#include "dawn/native/DawnNative.h"
9#endif
10
11#ifdef EMSCRIPTEN
12#include <emscripten/version.h>
13#endif
14
15#include "Foundation/Logging/Logger.h"
16
17namespace {
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("GraphicsDeviceWebGPU");
19
20 void request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void * userdata, void * /* userdata2 */)
21 {
23 char const *msg = message.data ? message.data : "";
24 int siz = message.data ? static_cast<int>(message.length) : 0;
25 char const *stat = status == WGPURequestAdapterStatus_Success ? "success" : "";
26 LOG_INFO(logger, "request_adapter %p %.*s %s", adapter, siz, msg, stat);
27 ptr->initialize_adapter(adapter);
28 }
29
30 void request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void * userdata, void * /* userdata2 */)
31 {
33 char const *msg = message.data ? message.data : "";
34 int siz = message.data ? static_cast<int>(message.length) : 0;
35 char const *stat = status == WGPURequestDeviceStatus_Success ? "success" : "";
36 LOG_INFO(logger, "request_device %p %.*s %s", device, siz, msg, stat);
37 ptr->initialize_device(device);
38 }
39
40 void error_callback(const WGPUDevice * /* device */, WGPUErrorType type, WGPUStringView message, void * userdata1, void * /* userdata2 */)
41 {
43 (void)ptr;
44 LOG_ERROR(logger, "WebGPU err (%d) %.*s", type, WGPUStringViewFormat(message));
45 }
46
47#ifndef EMSCRIPTEN
48 void logging_callback(WGPULoggingType type, WGPUStringView message, void * userdata1, void * /* userdata2 */)
49 {
51 (void)ptr;
52 LOG_INFO(logger, "WebGPU log (%d) x%.*s", type, WGPUStringViewFormat(message));
53 }
54#endif
55
56 // void queue_done_callback(WGPUQueueWorkDoneStatus status, void * userdata)
57 // {
58 // Cogs::GraphicsDeviceWebGPU *ptr = (Cogs::GraphicsDeviceWebGPU*)userdata;
59 // (void)ptr;
60 // LOG_INFO(logger, "queue_done (%d)", status);
61 // }
62
63 void device_lost(const WGPUDevice * /* device */, WGPUDeviceLostReason reason, WGPUStringView message, void * userdata, void * /* userdata2 */)
64 {
66 (void)ptr;
67 if(reason == WGPUDeviceLostReason_Destroyed)
68 LOG_INFO(logger, "device_lost (%d) %.*s", reason, WGPUStringViewFormat(message));
69 else if(reason != WGPUDeviceLostReason_CallbackCancelled) {
70 LOG_FATAL(logger, "device_lost (%d) %.*s", reason, WGPUStringViewFormat(message));
71 assert(reason == WGPUDeviceLostReason_Destroyed);
72 }
73 }
74
75 WGPULimits WebGPUDefaultLimits()
76 {
77 // WebGPU default limits (Minimum required limits for an implementation).
78 WGPULimits limits = {};
79 limits.maxTextureDimension1D = 8192;
80 limits.maxTextureDimension2D = 8192;
81 limits.maxTextureDimension3D = 2048;
82 limits.maxTextureArrayLayers = 256;
83 limits.maxBindGroups = 4;
84 limits.maxBindGroupsPlusVertexBuffers = 24;
85 limits.maxBindingsPerBindGroup = 1000;
86 limits.maxDynamicUniformBuffersPerPipelineLayout = 8;
87 limits.maxDynamicStorageBuffersPerPipelineLayout = 4;
88 limits.maxSampledTexturesPerShaderStage = 16;
89 limits.maxSamplersPerShaderStage = 16;
90 limits.maxStorageBuffersPerShaderStage = 8;
91 limits.maxStorageTexturesPerShaderStage = 4;
92 limits.maxUniformBuffersPerShaderStage = 12;
93 limits.maxUniformBufferBindingSize = 65536;
94 limits.maxStorageBufferBindingSize = 134217728;
95 limits.minUniformBufferOffsetAlignment = 256;
96 limits.minStorageBufferOffsetAlignment = 256;
97 limits.maxVertexBuffers = 8;
98 limits.maxBufferSize = 268435456;
99 limits.maxVertexAttributes = 16;
100 limits.maxVertexBufferArrayStride = 2048;
101 limits.maxInterStageShaderVariables = 16;
102 limits.maxColorAttachments = 8;
103 limits.maxColorAttachmentBytesPerSample = 32;
104 limits.maxComputeWorkgroupStorageSize = 16384;
105 limits.maxComputeInvocationsPerWorkgroup = 256;
106 limits.maxComputeWorkgroupSizeX = 256;
107 limits.maxComputeWorkgroupSizeY = 256;
108 limits.maxComputeWorkgroupSizeZ = 64;
109 limits.maxComputeWorkgroupsPerDimension = 65535;
110 // limits.maxImmediateSize = 64;
111 return limits;
112 }
113}
114
115namespace Cogs {
116
117 GraphicsDeviceWebGPU::GraphicsDeviceWebGPU(RenderingAllocatorInfo* /*allocator*/)
118 {
119 buffers.initialize(this);
120 effects.initialize(this, &buffers);
121 pipeline_states.initialize(this);
122 renderTargets.initialize(this);
123 context.initialize(this);
124 textures.initialize(this);
125 }
126
127 GraphicsDeviceWebGPU::~GraphicsDeviceWebGPU()
128 {
129 destroy();
130 }
131
133 {
134 if (settings.ioHandler) {
135 effects.setIOHandler(settings.ioHandler);
136 }
137
138#ifndef EMSCRIPTEN
139 // Load dawn procs
140 DawnProcTable procTable = dawn::native::GetProcs();
141 dawnProcSetProcs(&procTable);
142#endif
143
144 // Create instance
145 WGPUInstanceDescriptor instance_desc = {};
146 instance = wgpuCreateInstance(&instance_desc);
147
148 // Create surface
149 WGPUSurfaceDescriptor surface_desc = {};
150 surface_desc.label = {"WebGPU Surface", WGPU_STRLEN};
151#if defined(_WIN32)
152 WGPUSurfaceSourceWindowsHWND hwnd_window = {};
153 hwnd_window.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
154 hwnd_window.hinstance = ::GetModuleHandle(nullptr);
155 hwnd_window.hwnd = settings.windowData->windowHandle;
156 surface_desc.nextInChain = (WGPUChainedStruct*)&hwnd_window;
157 // WGPUSurfaceDescriptorFromWindowsCoreWindow windows_core_window = {};
158 // WGPUSType_SurfaceDescriptorFromWindowsCoreWindow;
159 // void * coreWindow;
160 // WGPUSurfaceDescriptorFromWindowsSwapChainPanel windows_swap_chain_panel = {};
161 // WGPUSType_SurfaceDescriptorFromWindowsSwapChainPanel;
162 // void * swapChainPanel;
163#elif defined(EMSCRIPTEN)
164 WGPUEmscriptenSurfaceSourceCanvasHTMLSelector html_canvas = {};
165 html_canvas.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
166 html_canvas.selector = {"canvas", WGPU_STRLEN};
167 surface_desc.nextInChain = (WGPUChainedStruct*)&html_canvas;
168#elif defined(__APPLE__)
169 // WGPUSurfaceDescriptorFromMetalLayer metal_layer = {};
170 // metal_layer.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
171 // void * layer;
172 static_assert(false, "Implement WebGPU Apple surface");
173#elif defined(__linux__)
174 WGPUSurfaceDescriptorFromXlibWindow x11_window = {};
175 x11_window.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
176 x11_window.display = settings.windowData->display;
177 x11_window.window = settings.windowData->windowHandle;
178 surface_desc.nextInChain = (WGPUChainedStruct*)&x11_window;
179 // WGPUSurfaceDescriptorFromWaylandSurface wayland_surface = {};
180 // wayland_surface.chain.sType = WGPUSType_SurfaceDescriptorFromWaylandSurface;
181 // wayland_surface.display = settings.windowData->display;
182 // void * surface;
183#elif defined(__ANDROID_API__)
184 // WGPUSurfaceDescriptorFromAndroidNativeWindow android_window = {};
185 // android_window.chain.sType = WGPUSType_SurfaceDescriptorFromAndroidNativeWindow;
186 // void * window;
187 static_assert(false, "Implement WebGPU Android surface");
188#endif
189 surface = wgpuInstanceCreateSurface(instance, &surface_desc);
190
191 // Get adapter
192 WGPURequestAdapterOptions adapter_options = {};
193 adapter_options.nextInChain;
194 adapter_options.compatibleSurface = surface;
195 adapter_options.powerPreference = WGPUPowerPreference_HighPerformance;
196 adapter_options.forceFallbackAdapter;
197 adapter_options.backendType = WGPUBackendType_D3D11;
198 has_device = false;
199 WGPURequestAdapterCallbackInfo callbackInfo = {};
200 callbackInfo.nextInChain = nullptr;
201 callbackInfo.callback = request_adapter;
202 callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
203 callbackInfo.userdata1 = this;
204
205 WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, callbackInfo);
206
207 WGPUFutureWaitInfo waitInfo = {};
208 waitInfo.future = future;
209 wgpuInstanceWaitAny(instance, 1, &waitInfo, 0);
210
211 return true;
212 }
213
214 void GraphicsDeviceWebGPU::initialize_adapter(WGPUAdapter adapter_in)
215 {
216 adapter = adapter_in;
217
218 // size_t wgpuAdapterEnumerateFeatures(WGPUAdapter adapter, WGPUFeatureName * features) WGPU_FUNCTION_ATTRIBUTE;
219
220 WGPUAdapterInfo properties = {};
221 // WGPUDawnAdapterPropertiesPowerPreference power_pref = {};
222 // WGPUPowerPreference powerPreference;
223 wgpuAdapterGetInfo(adapter, &properties);
224 LOG_INFO(logger, "vendorID %u", properties.vendorID);
225 LOG_INFO(logger, "vendor %.*s", WGPUStringViewFormat(properties.vendor));
226 LOG_INFO(logger, "architecture %.*s", WGPUStringViewFormat(properties.architecture));
227 LOG_INFO(logger, "deviceID %u", properties.deviceID);
228 LOG_INFO(logger, "device %.*s", WGPUStringViewFormat(properties.device));
229 LOG_INFO(logger, "description %.*s", WGPUStringViewFormat(properties.description));
230 LOG_INFO(logger, "adapterType %d", properties.adapterType);
231 LOG_INFO(logger, "backendType %d", properties.backendType);
232 LOG_INFO(logger, "subgroupMinSize %u", properties.subgroupMinSize);
233 LOG_INFO(logger, "subgroupMaxSize %u", properties.subgroupMaxSize);
234
235 if(properties.vendorID == 4130)
236 capabilities.vendor = Vendors::AMD;
237 else if(properties.vendorID == 4318)
238 capabilities.vendor = Vendors::nVidia;
239 else if(properties.vendorID == 32902)
240 capabilities.vendor = Vendors::Intel;
241 else if(properties.vendorID == 4203)
242 capabilities.vendor = Vendors::Apple;
243
244 if(properties.vendorID == 4130){ // AMD
245 if(strstr(properties.device.data, "FireGL") != nullptr){
246 capabilities.series = Series::FireGL;
247 }
248 else if(strstr(properties.device.data, "RadeonX") != nullptr){
249 capabilities.series = Series::RadeonX;
250 }
251 else if(strstr(properties.device.data, "RadeonHD") != nullptr){
252 capabilities.series = Series::RadeonHD;
253 }
254 }
255 else if(properties.vendorID == 4318){ // nVidia
256 if(strstr(properties.device.data, "QuadroFX") != nullptr){
257 capabilities.series = Series::QuadroFX;
258 }
259 else if(strstr(properties.device.data, "Quadro") != nullptr){
260 capabilities.series = Series::Quadro;
261 }
262 else if(strstr(properties.device.data, "GeForce") != nullptr){
263 capabilities.series = Series::geForce;
264 }
265 }
266 else if(properties.vendorID == 32902){ // Intel
267 if(strstr(properties.device.data, "IrisPro") != nullptr){
268 capabilities.series = Series::IrisPro;
269 }
270 else if(strstr(properties.device.data, "Iris") != nullptr){
271 capabilities.series = Series::Iris;
272 }
273 else if(strstr(properties.device.data, "HD") != nullptr){
274 capabilities.series = Series::HD;
275 }
276 }
277
278 capabilities.model = properties.deviceID;
279
280#ifndef EMSCRIPTEN
281 WGPULimits adapter_limits = {};
282 if(wgpuAdapterGetLimits(adapter, &adapter_limits)){
283 LOG_INFO(logger, "adapter_limits ");
284 LOG_INFO(logger, "maxTextureDimension1D %u", adapter_limits.maxTextureDimension1D);
285 LOG_INFO(logger, "maxTextureDimension2D %u", adapter_limits.maxTextureDimension2D);
286 LOG_INFO(logger, "maxTextureDimension3D %u", adapter_limits.maxTextureDimension3D);
287 LOG_INFO(logger, "maxTextureArrayLayers %u", adapter_limits.maxTextureArrayLayers);
288 LOG_INFO(logger, "maxBindGroups %u", adapter_limits.maxBindGroups);
289 LOG_INFO(logger, "maxBindGroupsPlusVertexBuffers %u", adapter_limits.maxBindGroupsPlusVertexBuffers);
290 LOG_INFO(logger, "maxBindingsPerBindGroup %u", adapter_limits.maxBindingsPerBindGroup);
291 LOG_INFO(logger, "maxDynamicUniformBuffersPerPipelineLayout %u", adapter_limits.maxDynamicUniformBuffersPerPipelineLayout);
292 LOG_INFO(logger, "maxDynamicStorageBuffersPerPipelineLayout %u", adapter_limits.maxDynamicStorageBuffersPerPipelineLayout);
293 LOG_INFO(logger, "maxSampledTexturesPerShaderStage %u", adapter_limits.maxSampledTexturesPerShaderStage);
294 LOG_INFO(logger, "maxSamplersPerShaderStage %u", adapter_limits.maxSamplersPerShaderStage);
295 LOG_INFO(logger, "maxStorageBuffersPerShaderStage %u", adapter_limits.maxStorageBuffersPerShaderStage);
296 LOG_INFO(logger, "maxStorageTexturesPerShaderStage %u", adapter_limits.maxStorageTexturesPerShaderStage);
297 LOG_INFO(logger, "maxUniformBuffersPerShaderStage %u", adapter_limits.maxUniformBuffersPerShaderStage);
298 LOG_INFO(logger, "maxUniformBufferBindingSize %llu", adapter_limits.maxUniformBufferBindingSize);
299 LOG_INFO(logger, "maxStorageBufferBindingSize %llu", adapter_limits.maxStorageBufferBindingSize);
300 LOG_INFO(logger, "minUniformBufferOffsetAlignment %u", adapter_limits.minUniformBufferOffsetAlignment);
301 LOG_INFO(logger, "minStorageBufferOffsetAlignment %u", adapter_limits.minStorageBufferOffsetAlignment);
302 LOG_INFO(logger, "maxVertexBuffers %u", adapter_limits.maxVertexBuffers);
303 LOG_INFO(logger, "maxBufferSize %llu", adapter_limits.maxBufferSize);
304 LOG_INFO(logger, "maxVertexAttributes %u", adapter_limits.maxVertexAttributes);
305 LOG_INFO(logger, "maxVertexBufferArrayStride %u", adapter_limits.maxVertexBufferArrayStride);
306 LOG_INFO(logger, "maxInterStageShaderVariables %u", adapter_limits.maxInterStageShaderVariables);
307 LOG_INFO(logger, "maxColorAttachments %u", adapter_limits.maxColorAttachments);
308 LOG_INFO(logger, "maxColorAttachmentBytesPerSample %u", adapter_limits.maxColorAttachmentBytesPerSample);
309 LOG_INFO(logger, "maxComputeWorkgroupStorageSize %u", adapter_limits.maxComputeWorkgroupStorageSize);
310 LOG_INFO(logger, "maxComputeInvocationsPerWorkgroup %u", adapter_limits.maxComputeInvocationsPerWorkgroup);
311 LOG_INFO(logger, "maxComputeWorkgroupSizeX %u", adapter_limits.maxComputeWorkgroupSizeX);
312 LOG_INFO(logger, "maxComputeWorkgroupSizeY %u", adapter_limits.maxComputeWorkgroupSizeY);
313 LOG_INFO(logger, "maxComputeWorkgroupSizeZ %u", adapter_limits.maxComputeWorkgroupSizeZ);
314 LOG_INFO(logger, "maxComputeWorkgroupsPerDimension %u", adapter_limits.maxComputeWorkgroupsPerDimension);
315 LOG_INFO(logger, "maxImmediateSize %u", adapter_limits.maxImmediateSize);
316 }
317#endif
318
319 // Sample adapter_limits (GTX 1070)
320 // maxTextureDimension1D 16384
321 // maxTextureDimension2D 16384
322 // maxTextureDimension3D 2048
323 // maxTextureArrayLayers 2048
324 // maxBindGroups 4
325 // maxBindingsPerBindGroup 1000
326 // maxDynamicUniformBuffersPerPipelineLayout 0
327 // maxDynamicStorageBuffersPerPipelineLayout 0
328 // maxSampledTexturesPerShaderStage 16
329 // maxSamplersPerShaderStage 16
330 // maxStorageBuffersPerShaderStage 8
331 // maxStorageTexturesPerShaderStage 8
332 // maxUniformBuffersPerShaderStage 12
333 // maxUniformBufferBindingSize 65536
334 // maxStorageBufferBindingSize 134217728
335 // minUniformBufferOffsetAlignment 256
336 // minStorageBufferOffsetAlignment 256
337 // maxVertexBuffers 8
338 // maxBufferSize 2147483648
339 // maxVertexAttributes 16
340 // maxVertexBufferArrayStride 2048
341 // maxInterStageShaderVariables 16
342 // maxColorAttachments 8
343 // maxColorAttachmentBytesPerSample 32
344 // maxComputeWorkgroupStorageSize 32768
345 // maxComputeInvocationsPerWorkgroup 1024
346 // maxComputeWorkgroupSizeX 1024
347 // maxComputeWorkgroupSizeY 1024
348 // maxComputeWorkgroupSizeZ 64
349 // maxComputeWorkgroupsPerDimension 65535
350
351 // Required limits
352 WGPULimits required_limits = {};
353 required_limits = WebGPUDefaultLimits(); // Request WebGPU default limits
354
355 // Some buggy limits
356 required_limits.maxDynamicUniformBuffersPerPipelineLayout = 0;
357 required_limits.maxDynamicStorageBuffersPerPipelineLayout = 0;
358
359 std::vector<WGPUFeatureName> features;
360
361 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionBC)) {
362 features.push_back(WGPUFeatureName_TextureCompressionBC);
363 capabilities.capabilities.TextureCompressionBPTC = true;
364 }
365 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionASTC)) {
366 features.push_back(WGPUFeatureName_TextureCompressionASTC);
367 capabilities.capabilities.TextureCompressionASTC = true;
368 }
369 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) {
370 features.push_back(WGPUFeatureName_TextureCompressionETC2);
371 capabilities.capabilities.TextureCompressionETC = true;
372 }
373 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_Float32Filterable)) {
374 features.push_back(WGPUFeatureName_Float32Filterable);
375 }
376
377 // Get device
378 WGPUDeviceDescriptor device_desc = {};
379 device_desc.label = {"WebGPU device", WGPU_STRLEN};
380
381#if defined(EMSCRIPTEN) && (__EMSCRIPTEN_major__ <= 3) && (__EMSCRIPTEN_minor__ <= 1) && (__EMSCRIPTEN_tiny__ < 61)
382 // Name of this field changed sometime before emscripten 3.1.61
383 device_desc.requiredFeaturesCount = features.size();
384#else
385 device_desc.requiredFeatureCount = features.size();
386#endif
387 device_desc.requiredFeatures = features.data();
388 device_desc.requiredLimits = &required_limits;
389 device_desc.defaultQueue.label = {"Default WebGPU queue", WGPU_STRLEN};
390
391 WGPUDeviceLostCallbackInfo deviceLostCallbackInfo = {};
392 deviceLostCallbackInfo.nextInChain = nullptr;
393 deviceLostCallbackInfo.callback = device_lost;
394 deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
395 deviceLostCallbackInfo.userdata1 = this;
396 device_desc.deviceLostCallbackInfo = deviceLostCallbackInfo;
397
398 WGPUUncapturedErrorCallbackInfo uncapturedErrorCallbackInfo = {};
399 uncapturedErrorCallbackInfo.nextInChain = nullptr;
400 uncapturedErrorCallbackInfo.callback = error_callback;
401 uncapturedErrorCallbackInfo.userdata1 = this;
402 device_desc.uncapturedErrorCallbackInfo = uncapturedErrorCallbackInfo;
403 // WGPUDawnTogglesDescriptor toggles_desc = {};
404 // toggles_desc.chain;
405 // toggles_desc.enabledTogglesCount;
406 // toggles_desc.enabledToggles;
407 // toggles_desc.disabledTogglesCount;
408 // toggles_desc.disabledToggles;
409 // WGPUDawnCacheDeviceDescriptor dawn_cache_desc = {};
410 // dawn_cache_desc.chain;
411 // dawn_cache_desc.isolationKey;
412
413 WGPURequestDeviceCallbackInfo requestDeviceCallbackInfo = {};
414 requestDeviceCallbackInfo.nextInChain = nullptr;
415 requestDeviceCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
416 requestDeviceCallbackInfo.userdata1 = this;
417 requestDeviceCallbackInfo.callback = request_device;
418 WGPUFuture future = wgpuAdapterRequestDevice(adapter, &device_desc, requestDeviceCallbackInfo);
419
420 WGPUFutureWaitInfo waitInfo = {};
421 waitInfo.future = future;
422 wgpuInstanceWaitAny(instance, 1, &waitInfo, 0);
423 }
424
425 void GraphicsDeviceWebGPU::maybeCreateUploadCommandEncoder()
426 {
427 if(commandEncoder) return;
428 WGPUCommandEncoderDescriptor command_encoder_desc = {};
429 command_encoder_desc.label = {"Upload Command Encoder", WGPU_STRLEN};
430 commandEncoder = wgpuDeviceCreateCommandEncoder(device, &command_encoder_desc);
431 }
432 void GraphicsDeviceWebGPU::initialize_device(WGPUDevice device_in)
433 {
434 device = device_in;
435
436 // Setup logging
437#ifndef EMSCRIPTEN
438 WGPULoggingCallbackInfo loggingCallbackInfo = {};
439 loggingCallbackInfo.nextInChain = nullptr;
440 loggingCallbackInfo.callback = logging_callback;
441 loggingCallbackInfo.userdata1 = this;
442 wgpuDeviceSetLoggingCallback(device, loggingCallbackInfo);
443#endif
444
445 WGPULimits device_limits = {};
446 if(wgpuDeviceGetLimits(device, &device_limits)){
447 LOG_INFO(logger, "device_limits ");
448 LOG_INFO(logger, "maxTextureDimension1D %u", device_limits.maxTextureDimension1D);
449 LOG_INFO(logger, "maxTextureDimension2D %u", device_limits.maxTextureDimension2D);
450 LOG_INFO(logger, "maxTextureDimension3D %u", device_limits.maxTextureDimension3D);
451 LOG_INFO(logger, "maxTextureArrayLayers %u", device_limits.maxTextureArrayLayers);
452 LOG_INFO(logger, "maxBindGroups %u", device_limits.maxBindGroups);
453 LOG_INFO(logger, "maxBindGroupsPlusVertexBuffers %u", device_limits.maxBindGroupsPlusVertexBuffers);
454 LOG_INFO(logger, "maxBindingsPerBindGroup %u", device_limits.maxBindingsPerBindGroup);
455 LOG_INFO(logger, "maxDynamicUniformBuffersPerPipelineLayout %u", device_limits.maxDynamicUniformBuffersPerPipelineLayout);
456 LOG_INFO(logger, "maxDynamicStorageBuffersPerPipelineLayout %u", device_limits.maxDynamicStorageBuffersPerPipelineLayout);
457 LOG_INFO(logger, "maxSampledTexturesPerShaderStage %u", device_limits.maxSampledTexturesPerShaderStage);
458 LOG_INFO(logger, "maxSamplersPerShaderStage %u", device_limits.maxSamplersPerShaderStage);
459 LOG_INFO(logger, "maxStorageBuffersPerShaderStage %u", device_limits.maxStorageBuffersPerShaderStage);
460 LOG_INFO(logger, "maxStorageTexturesPerShaderStage %u", device_limits.maxStorageTexturesPerShaderStage);
461 LOG_INFO(logger, "maxUniformBuffersPerShaderStage %u", device_limits.maxUniformBuffersPerShaderStage);
462 LOG_INFO(logger, "maxUniformBufferBindingSize %llu", device_limits.maxUniformBufferBindingSize);
463 LOG_INFO(logger, "maxStorageBufferBindingSize %llu", device_limits.maxStorageBufferBindingSize);
464 LOG_INFO(logger, "minUniformBufferOffsetAlignment %u", device_limits.minUniformBufferOffsetAlignment);
465 LOG_INFO(logger, "minStorageBufferOffsetAlignment %u", device_limits.minStorageBufferOffsetAlignment);
466 LOG_INFO(logger, "maxVertexBuffers %u", device_limits.maxVertexBuffers);
467 LOG_INFO(logger, "maxBufferSize %llu", device_limits.maxBufferSize);
468 LOG_INFO(logger, "maxVertexAttributes %u", device_limits.maxVertexAttributes);
469 LOG_INFO(logger, "maxVertexBufferArrayStride %u", device_limits.maxVertexBufferArrayStride);
470 LOG_INFO(logger, "maxInterStageShaderVariables %u", device_limits.maxInterStageShaderVariables);
471 LOG_INFO(logger, "maxColorAttachments %u", device_limits.maxColorAttachments);
472 LOG_INFO(logger, "maxColorAttachmentBytesPerSample %u", device_limits.maxColorAttachmentBytesPerSample);
473 LOG_INFO(logger, "maxComputeWorkgroupStorageSize %u", device_limits.maxComputeWorkgroupStorageSize);
474 LOG_INFO(logger, "maxComputeInvocationsPerWorkgroup %u", device_limits.maxComputeInvocationsPerWorkgroup);
475 LOG_INFO(logger, "maxComputeWorkgroupSizeX %u", device_limits.maxComputeWorkgroupSizeX);
476 LOG_INFO(logger, "maxComputeWorkgroupSizeY %u", device_limits.maxComputeWorkgroupSizeY);
477 LOG_INFO(logger, "maxComputeWorkgroupSizeZ %u", device_limits.maxComputeWorkgroupSizeZ);
478 LOG_INFO(logger, "maxComputeWorkgroupsPerDimension %u", device_limits.maxComputeWorkgroupsPerDimension);
479 LOG_INFO(logger, "maxImmediateSize %u", device_limits.maxImmediateSize);
480 }
481
482 // Update capabilities
483 capabilities.capabilities.RenderPass = true;
484 capabilities.capabilities.SyncObjects = false; // TODO
485 capabilities.capabilities.GeometryShaders = false;
486 capabilities.capabilities.TessellationShaders = false;
487 capabilities.capabilities.ComputeShaders = false; // TODO
488 capabilities.capabilities.SupportsHlsl = false;
489 capabilities.capabilities.SupportsMultipleThreads = false;
490 capabilities.capabilities.ConstantBufferOffsetAlignment = device_limits.minUniformBufferOffsetAlignment;
491 capabilities.capabilities.ConstantBufferRange = true;
492 capabilities.capabilities.MaxTexture2DSize = device_limits.maxTextureDimension2D;
493 capabilities.capabilities.MaxTexture3DSize = device_limits.maxTextureDimension3D;
494 capabilities.capabilities.MaxTextureArrayLayers = device_limits.maxTextureArrayLayers;
495
496 defaultSwapChain.initialize(device, surface);
497
498 queue = wgpuDeviceGetQueue(device);
499
500 LOG_INFO(logger, "Has WebGPU Device");
501 has_device = true;
502 }
503
504 void GraphicsDeviceWebGPU::destroy()
505 {
506 wgpuInstanceRelease(instance);
507 LOG_INFO(logger, "WebGPU destroy");
508 if(commandEncoder){
509 wgpuCommandEncoderRelease(commandEncoder);
510 commandEncoder = nullptr;
511 }
512 wgpuQueueRelease(queue);
513 defaultSwapChain.destroy();
514 wgpuSurfaceRelease(surface);
515
516 wgpuDeviceRelease(device);
517 wgpuAdapterRelease(adapter);
518 }
519
521 {
522 buffers.releaseResources();
523 effects.releaseResources();
524 textures.releaseResources();
525 renderTargets.releaseResources();
526 }
527
529 {
530 if(commandEncoder){
531 WGPUCommandBufferDescriptor command_buffer_desc = {};
532 command_buffer_desc.label = {"Upload Command Buffer", WGPU_STRLEN};
533 WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(commandEncoder, &command_buffer_desc);
534 wgpuCommandEncoderRelease(commandEncoder);
535 commandEncoder = nullptr;
536 wgpuQueueSubmit(queue, 1, &command_buffer);
537 buffers.resetInstances();
538 }
539
540#ifndef EMSCRIPTEN
541 // Emscripten: wgpuInstanceProcessEvents is unsupported (use requestAnimationFrame via html5.h instead)
542 wgpuInstanceProcessEvents(instance);
543 wgpuDeviceTick(device);
544#endif
545
546 defaultSwapChain.beginFrame();
547
548 WGPUCommandEncoderDescriptor command_encoder_desc = {};
549 command_encoder_desc.label = {"Default Command Encoder", WGPU_STRLEN};
550 commandEncoder = wgpuDeviceCreateCommandEncoder(device, &command_encoder_desc);
551 context.setDefaults();
552 }
553
554 void GraphicsDeviceWebGPU::endFrame(uint32_t syncInterval, PresentFlags presentFlags)
555 {
556 context.updateRenderPass();
557 context.endRenderPassInt();
558
559#ifndef EMSCRIPTEN
560 WGPUTexelCopyTextureInfo src = {};
561 src.texture = defaultSwapChain.resolveTexture;
562 src.mipLevel = 0;
563 src.origin = {0, 0, 0};
564 src.aspect = WGPUTextureAspect_All;
565 WGPUTexelCopyTextureInfo dst = {};
566 WGPUSurfaceTexture surfaceTexture = context.graphicsDevice->defaultSwapChain.getTextureData();
567 dst.texture = surfaceTexture.texture;
568 dst.mipLevel = 0;
569 dst.origin = {0, 0, 0};
570 dst.aspect = WGPUTextureAspect_All;
571 WGPUExtent3D copy_size = {(uint32_t)defaultSwapChain.set_width, (uint32_t)defaultSwapChain.set_height, 1};
572 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &src, &dst, &copy_size);
573#endif
574
575 WGPUCommandBufferDescriptor command_buffer_desc = {};
576 command_buffer_desc.label = {"Default Command Buffer", WGPU_STRLEN};
577 WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(commandEncoder, &command_buffer_desc);
578 wgpuCommandEncoderRelease(commandEncoder);
579 commandEncoder = nullptr;
580 wgpuQueueSubmit(queue, 1, &command_buffer);
581 buffers.resetInstances();
582
583 // wgpuQueueOnSubmittedWorkDone
584
585 defaultSwapChain.endFrame(syncInterval, presentFlags);
586 }
587}
virtual void releaseResources() override
Releases all allocated buffer resources.
Definition: BuffersWebGPU.h:68
virtual void releaseResources() override
Release all allocated effect resources.
virtual void beginFrame() override
Signal the beginning of a new frame to the graphics device.
virtual void releaseResources() override
Release all resources allocated.
virtual bool initialize() override
Initializes the graphics device with the settings previous set through calling setSettings.
virtual void endFrame(uint32_t=0, PresentFlags=PresentFlags::None) override
Signal the end of a frame to the graphics device.
Log implementation class.
Definition: LogManager.h:140
virtual void releaseResources() override
Release all allocated render target resources.
virtual void beginFrame() override
Signal the beginning of a new frame to the graphics device.
virtual void endFrame(uint32_t syncInterval=0, PresentFlags presentFlags=PresentFlags::None) override
Signal the end of a frame to the graphics device.
virtual void releaseResources() override
Release all allocated texture resources.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
PresentFlags
Flags controlling presentation.
Definition: Common.h:166
void setIOHandler(IIOHandler *handler) override
Sets an external I/O handler to use for I/O operations.
uint32_t MaxTexture3DSize
Using D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION as default.
Definition: ICapabilities.h:81
uint32_t MaxTexture2DSize
Using D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION as default.
Definition: ICapabilities.h:80
bool SyncObjects
Support for syncronization objects.
Definition: ICapabilities.h:86
uint32_t MaxTextureArrayLayers
Using D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as default.
Definition: ICapabilities.h:83
unsigned ConstantBufferOffsetAlignment
Minimum offset alignment when binding constant buffers.
Definition: ICapabilities.h:78
bool ConstantBufferRange
supports binding a range of a constant buffer.
Definition: ICapabilities.h:90
struct WindowData * windowData
Native window handle used to initialize the graphics device.
IIOHandler * ioHandler
Optional pointer to an IO handler.
@ HD
Intel HD.
Definition: ICapabilities.h:52
@ QuadroFX
nVidia Quadro FX professional graphics adapters.
Definition: ICapabilities.h:50
@ Iris
Intel Iris.
Definition: ICapabilities.h:54
@ IrisPro
Intel Iris Pro.
Definition: ICapabilities.h:56
@ FireGL
AMD FireGL series.
Definition: ICapabilities.h:43
@ geForce
nVidia geForce consumer adapters.
Definition: ICapabilities.h:46
@ RadeonX
AMD Radeon X series.
Definition: ICapabilities.h:39
@ RadeonHD
AMD Radeon HD series.
Definition: ICapabilities.h:41
@ Quadro
nVidia Quadro professional graphics adapters.
Definition: ICapabilities.h:48
@ Apple
Apple silicon.
Definition: ICapabilities.h:24
@ nVidia
nVidia Corporation.
Definition: ICapabilities.h:20