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 = WGPU_LIMITS_INIT;
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 = WGPU_INSTANCE_DESCRIPTOR_INIT;
146 instance = wgpuCreateInstance(&instance_desc);
147
148 // Instance features
149 // WGPUSupportedInstanceFeatures instance_features = WGPU_SUPPORTED_INSTANCE_FEATURES_INIT;
150 // wgpuGetInstanceFeatures(&instance_features);
151 // wgpuSupportedInstanceFeaturesFreeMembers(instance_features);
152 if(wgpuHasInstanceFeature(WGPUInstanceFeatureName_TimedWaitAny) != 0){
153 LOG_INFO(logger, "Has Instance Features: TimedWaitAny");
154 }
155 if(wgpuHasInstanceFeature(WGPUInstanceFeatureName_ShaderSourceSPIRV) != 0){
156 LOG_INFO(logger, "Has Instance Features: ShaderSourceSPIRV");
157 }
158 if(wgpuHasInstanceFeature(WGPUInstanceFeatureName_MultipleDevicesPerAdapter) != 0){
159 LOG_INFO(logger, "Has Instance Features: MultipleDevicesPerAdapter");
160 }
161
162 // Instance limits
163 WGPUInstanceLimits instance_limits = WGPU_INSTANCE_LIMITS_INIT;
164 if(wgpuGetInstanceLimits(&instance_limits) == WGPUStatus_Success){
165 LOG_INFO(logger, "Instance timedWaitAnyMaxCount %zu", instance_limits.timedWaitAnyMaxCount);
166 }
167
168 // Create surface
169 WGPUSurfaceDescriptor surface_desc = WGPU_SURFACE_DESCRIPTOR_INIT;
170 surface_desc.label = {"WebGPU Surface", WGPU_STRLEN};
171#if defined(_WIN32)
172 WGPUSurfaceSourceWindowsHWND hwnd_window = {};
173 hwnd_window.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
174 hwnd_window.hinstance = ::GetModuleHandle(nullptr);
175 hwnd_window.hwnd = settings.windowData->windowHandle;
176 surface_desc.nextInChain = (WGPUChainedStruct*)&hwnd_window;
177 // WGPUSurfaceDescriptorFromWindowsCoreWindow windows_core_window = {};
178 // WGPUSType_SurfaceDescriptorFromWindowsCoreWindow;
179 // void * coreWindow;
180 // WGPUSurfaceDescriptorFromWindowsSwapChainPanel windows_swap_chain_panel = {};
181 // WGPUSType_SurfaceDescriptorFromWindowsSwapChainPanel;
182 // void * swapChainPanel;
183#elif defined(__EMSCRIPTEN__)
184 WGPUEmscriptenSurfaceSourceCanvasHTMLSelector html_canvas = WGPU_EMSCRIPTEN_SURFACE_SOURCE_CANVAS_HTML_SELECTOR_INIT;
185 html_canvas.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
186 html_canvas.selector = {"canvas", WGPU_STRLEN};
187 surface_desc.nextInChain = (WGPUChainedStruct*)&html_canvas;
188#elif defined(__APPLE__)
189 // WGPUSurfaceDescriptorFromMetalLayer metal_layer = {};
190 // metal_layer.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
191 // void * layer;
192 static_assert(false, "Implement WebGPU Apple surface");
193#elif defined(__linux__)
194 WGPUSurfaceDescriptorFromXlibWindow x11_window = {};
195 x11_window.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
196 x11_window.display = settings.windowData->display;
197 x11_window.window = settings.windowData->windowHandle;
198 surface_desc.nextInChain = (WGPUChainedStruct*)&x11_window;
199 // WGPUSurfaceDescriptorFromWaylandSurface wayland_surface = {};
200 // wayland_surface.chain.sType = WGPUSType_SurfaceDescriptorFromWaylandSurface;
201 // wayland_surface.display = settings.windowData->display;
202 // void * surface;
203#elif defined(__ANDROID_API__)
204 // WGPUSurfaceDescriptorFromAndroidNativeWindow android_window = {};
205 // android_window.chain.sType = WGPUSType_SurfaceDescriptorFromAndroidNativeWindow;
206 // void * window;
207 static_assert(false, "Implement WebGPU Android surface");
208#endif
209 surface = wgpuInstanceCreateSurface(instance, &surface_desc);
210
211 // Get adapter
212 WGPURequestAdapterOptions adapter_options = WGPU_REQUEST_ADAPTER_OPTIONS_INIT;
213 adapter_options.featureLevel = WGPUFeatureLevel_Core;
214 adapter_options.powerPreference = WGPUPowerPreference_HighPerformance;
215 adapter_options.compatibleSurface = surface;
216 has_device = false;
217 WGPURequestAdapterCallbackInfo callbackInfo = WGPU_REQUEST_ADAPTER_CALLBACK_INFO_INIT;
218 callbackInfo.nextInChain = nullptr;
219 callbackInfo.callback = request_adapter;
220 callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
221 callbackInfo.userdata1 = this;
222
223 WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, callbackInfo);
224
225 WGPUFutureWaitInfo waitInfo = WGPU_FUTURE_WAIT_INFO_INIT;
226 waitInfo.future = future;
227 wgpuInstanceWaitAny(instance, 1, &waitInfo, 0);
228
229 return true;
230 }
231
232 const char *FeatureNameStr(WGPUFeatureName name)
233 {
234 switch(name){
235 case WGPUFeatureName_CoreFeaturesAndLimits:
236 return "CoreFeaturesAndLimits";
237 case WGPUFeatureName_DepthClipControl:
238 return "DepthClipControl";
239 case WGPUFeatureName_Depth32FloatStencil8:
240 return "Depth32FloatStencil8";
241 case WGPUFeatureName_TextureCompressionBC:
242 return "TextureCompressionBC";
243 case WGPUFeatureName_TextureCompressionBCSliced3D:
244 return "TextureCompressionBCSliced3D";
245 case WGPUFeatureName_TextureCompressionETC2:
246 return "TextureCompressionETC2";
247 case WGPUFeatureName_TextureCompressionASTC:
248 return "TextureCompressionASTC";
249 case WGPUFeatureName_TextureCompressionASTCSliced3D:
250 return "TextureCompressionASTCSliced3D";
251 case WGPUFeatureName_TimestampQuery:
252 return "TimestampQuery";
253 case WGPUFeatureName_IndirectFirstInstance:
254 return "IndirectFirstInstance";
255 case WGPUFeatureName_ShaderF16:
256 return "ShaderF16";
257 case WGPUFeatureName_RG11B10UfloatRenderable:
258 return "RG11B10UfloatRenderable";
259 case WGPUFeatureName_BGRA8UnormStorage:
260 return "BGRA8UnormStorage";
261 case WGPUFeatureName_Float32Filterable:
262 return "Float32Filterable";
263 case WGPUFeatureName_Float32Blendable:
264 return "Float32Blendable";
265 case WGPUFeatureName_ClipDistances:
266 return "ClipDistances";
267 case WGPUFeatureName_DualSourceBlending:
268 return "DualSourceBlending";
269 case WGPUFeatureName_Subgroups:
270 return "Subgroups";
271 case WGPUFeatureName_TextureFormatsTier1:
272 return "TextureFormatsTier1";
273 case WGPUFeatureName_TextureFormatsTier2:
274 return "TextureFormatsTier2";
275 case WGPUFeatureName_PrimitiveIndex:
276 return "PrimitiveIndex";
277 case WGPUFeatureName_Unorm16TextureFormats:
278 return "Unorm16TextureFormats";
279 case WGPUFeatureName_Snorm16TextureFormats:
280 return "Snorm16TextureFormats";
281 case WGPUFeatureName_MultiDrawIndirect:
282 return "MultiDrawIndirect";
283 case WGPUFeatureName_Force32:
284 break;
285 }
286 return "";
287 }
288
289 void GraphicsDeviceWebGPU::initialize_adapter(WGPUAdapter adapter_in)
290 {
291 adapter = adapter_in;
292
293 // Supported features
294 WGPUSupportedFeatures supportedFeatures = WGPU_SUPPORTED_FEATURES_INIT;
295 wgpuAdapterGetFeatures(adapter, &supportedFeatures);
296 for(size_t i=0; i<supportedFeatures.featureCount; i++){
297 WGPUFeatureName name = supportedFeatures.features[i];
298 LOG_INFO(logger, "Feature: %u %s", name, FeatureNameStr(name));
299 }
300 wgpuSupportedFeaturesFreeMembers(supportedFeatures);
301
302 WGPUAdapterInfo properties = WGPU_ADAPTER_INFO_INIT;
303 wgpuAdapterGetInfo(adapter, &properties);
304 LOG_INFO(logger, "vendorID %u", properties.vendorID);
305 LOG_INFO(logger, "vendor %.*s", WGPUStringViewFormat(properties.vendor));
306 LOG_INFO(logger, "architecture %.*s", WGPUStringViewFormat(properties.architecture));
307 LOG_INFO(logger, "deviceID %u", properties.deviceID);
308 LOG_INFO(logger, "device %.*s", WGPUStringViewFormat(properties.device));
309 LOG_INFO(logger, "description %.*s", WGPUStringViewFormat(properties.description));
310 LOG_INFO(logger, "adapterType %d", properties.adapterType);
311 LOG_INFO(logger, "backendType %d", properties.backendType);
312 LOG_INFO(logger, "subgroupMinSize %u", properties.subgroupMinSize);
313 LOG_INFO(logger, "subgroupMaxSize %u", properties.subgroupMaxSize);
314
315 if(properties.vendorID == 4130)
316 capabilities.vendor = Vendors::AMD;
317 else if(properties.vendorID == 4318)
318 capabilities.vendor = Vendors::nVidia;
319 else if(properties.vendorID == 32902)
320 capabilities.vendor = Vendors::Intel;
321 else if(properties.vendorID == 4203)
322 capabilities.vendor = Vendors::Apple;
323
324 if(properties.vendorID == 4130){ // AMD
325 if(strstr(properties.device.data, "FireGL") != nullptr){
326 capabilities.series = Series::FireGL;
327 }
328 else if(strstr(properties.device.data, "RadeonX") != nullptr){
329 capabilities.series = Series::RadeonX;
330 }
331 else if(strstr(properties.device.data, "RadeonHD") != nullptr){
332 capabilities.series = Series::RadeonHD;
333 }
334 }
335 else if(properties.vendorID == 4318){ // nVidia
336 if(strstr(properties.device.data, "QuadroFX") != nullptr){
337 capabilities.series = Series::QuadroFX;
338 }
339 else if(strstr(properties.device.data, "Quadro") != nullptr){
340 capabilities.series = Series::Quadro;
341 }
342 else if(strstr(properties.device.data, "GeForce") != nullptr){
343 capabilities.series = Series::geForce;
344 }
345 }
346 else if(properties.vendorID == 32902){ // Intel
347 if(strstr(properties.device.data, "IrisPro") != nullptr){
348 capabilities.series = Series::IrisPro;
349 }
350 else if(strstr(properties.device.data, "Iris") != nullptr){
351 capabilities.series = Series::Iris;
352 }
353 else if(strstr(properties.device.data, "HD") != nullptr){
354 capabilities.series = Series::HD;
355 }
356 }
357
358 capabilities.model = properties.deviceID;
359
360 wgpuAdapterInfoFreeMembers(properties);
361
362 WGPULimits adapter_limits = WGPU_LIMITS_INIT;
363 if(wgpuAdapterGetLimits(adapter, &adapter_limits)){
364 LOG_INFO(logger, "adapter_limits ");
365 LOG_INFO(logger, "maxTextureDimension1D %u", adapter_limits.maxTextureDimension1D);
366 LOG_INFO(logger, "maxTextureDimension2D %u", adapter_limits.maxTextureDimension2D);
367 LOG_INFO(logger, "maxTextureDimension3D %u", adapter_limits.maxTextureDimension3D);
368 LOG_INFO(logger, "maxTextureArrayLayers %u", adapter_limits.maxTextureArrayLayers);
369 LOG_INFO(logger, "maxBindGroups %u", adapter_limits.maxBindGroups);
370 LOG_INFO(logger, "maxBindGroupsPlusVertexBuffers %u", adapter_limits.maxBindGroupsPlusVertexBuffers);
371 LOG_INFO(logger, "maxBindingsPerBindGroup %u", adapter_limits.maxBindingsPerBindGroup);
372 LOG_INFO(logger, "maxDynamicUniformBuffersPerPipelineLayout %u", adapter_limits.maxDynamicUniformBuffersPerPipelineLayout);
373 LOG_INFO(logger, "maxDynamicStorageBuffersPerPipelineLayout %u", adapter_limits.maxDynamicStorageBuffersPerPipelineLayout);
374 LOG_INFO(logger, "maxSampledTexturesPerShaderStage %u", adapter_limits.maxSampledTexturesPerShaderStage);
375 LOG_INFO(logger, "maxSamplersPerShaderStage %u", adapter_limits.maxSamplersPerShaderStage);
376 LOG_INFO(logger, "maxStorageBuffersPerShaderStage %u", adapter_limits.maxStorageBuffersPerShaderStage);
377 LOG_INFO(logger, "maxStorageTexturesPerShaderStage %u", adapter_limits.maxStorageTexturesPerShaderStage);
378 LOG_INFO(logger, "maxUniformBuffersPerShaderStage %u", adapter_limits.maxUniformBuffersPerShaderStage);
379 LOG_INFO(logger, "maxUniformBufferBindingSize %llu", adapter_limits.maxUniformBufferBindingSize);
380 LOG_INFO(logger, "maxStorageBufferBindingSize %llu", adapter_limits.maxStorageBufferBindingSize);
381 LOG_INFO(logger, "minUniformBufferOffsetAlignment %u", adapter_limits.minUniformBufferOffsetAlignment);
382 LOG_INFO(logger, "minStorageBufferOffsetAlignment %u", adapter_limits.minStorageBufferOffsetAlignment);
383 LOG_INFO(logger, "maxVertexBuffers %u", adapter_limits.maxVertexBuffers);
384 LOG_INFO(logger, "maxBufferSize %llu", adapter_limits.maxBufferSize);
385 LOG_INFO(logger, "maxVertexAttributes %u", adapter_limits.maxVertexAttributes);
386 LOG_INFO(logger, "maxVertexBufferArrayStride %u", adapter_limits.maxVertexBufferArrayStride);
387 LOG_INFO(logger, "maxInterStageShaderVariables %u", adapter_limits.maxInterStageShaderVariables);
388 LOG_INFO(logger, "maxColorAttachments %u", adapter_limits.maxColorAttachments);
389 LOG_INFO(logger, "maxColorAttachmentBytesPerSample %u", adapter_limits.maxColorAttachmentBytesPerSample);
390 LOG_INFO(logger, "maxComputeWorkgroupStorageSize %u", adapter_limits.maxComputeWorkgroupStorageSize);
391 LOG_INFO(logger, "maxComputeInvocationsPerWorkgroup %u", adapter_limits.maxComputeInvocationsPerWorkgroup);
392 LOG_INFO(logger, "maxComputeWorkgroupSizeX %u", adapter_limits.maxComputeWorkgroupSizeX);
393 LOG_INFO(logger, "maxComputeWorkgroupSizeY %u", adapter_limits.maxComputeWorkgroupSizeY);
394 LOG_INFO(logger, "maxComputeWorkgroupSizeZ %u", adapter_limits.maxComputeWorkgroupSizeZ);
395 LOG_INFO(logger, "maxComputeWorkgroupsPerDimension %u", adapter_limits.maxComputeWorkgroupsPerDimension);
396 LOG_INFO(logger, "maxImmediateSize %u", adapter_limits.maxImmediateSize);
397 }
398
399 // Sample adapter_limits (GTX 1070)
400 // maxTextureDimension1D 16384
401 // maxTextureDimension2D 16384
402 // maxTextureDimension3D 2048
403 // maxTextureArrayLayers 2048
404 // maxBindGroups 4
405 // maxBindingsPerBindGroup 1000
406 // maxDynamicUniformBuffersPerPipelineLayout 0
407 // maxDynamicStorageBuffersPerPipelineLayout 0
408 // maxSampledTexturesPerShaderStage 16
409 // maxSamplersPerShaderStage 16
410 // maxStorageBuffersPerShaderStage 8
411 // maxStorageTexturesPerShaderStage 8
412 // maxUniformBuffersPerShaderStage 12
413 // maxUniformBufferBindingSize 65536
414 // maxStorageBufferBindingSize 134217728
415 // minUniformBufferOffsetAlignment 256
416 // minStorageBufferOffsetAlignment 256
417 // maxVertexBuffers 8
418 // maxBufferSize 2147483648
419 // maxVertexAttributes 16
420 // maxVertexBufferArrayStride 2048
421 // maxInterStageShaderVariables 16
422 // maxColorAttachments 8
423 // maxColorAttachmentBytesPerSample 32
424 // maxComputeWorkgroupStorageSize 32768
425 // maxComputeInvocationsPerWorkgroup 1024
426 // maxComputeWorkgroupSizeX 1024
427 // maxComputeWorkgroupSizeY 1024
428 // maxComputeWorkgroupSizeZ 64
429 // maxComputeWorkgroupsPerDimension 65535
430 // maxImmediateSize 0
431
432 // Required limits
433 // WGPULimits required_limits = WGPU_LIMITS_INIT; // Request limits undefined
434 // WGPULimits required_limits = WebGPUDefaultLimits(); // Request WebGPU default limits
435 WGPULimits required_limits = adapter_limits; // Request adapter limits
436
437 std::vector<WGPUFeatureName> features;
438
439 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionBC)) {
440 features.push_back(WGPUFeatureName_TextureCompressionBC);
441 capabilities.capabilities.TextureCompressionBPTC = true;
442 }
443 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionASTC)) {
444 features.push_back(WGPUFeatureName_TextureCompressionASTC);
445 capabilities.capabilities.TextureCompressionASTC = true;
446 }
447 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) {
448 features.push_back(WGPUFeatureName_TextureCompressionETC2);
449 capabilities.capabilities.TextureCompressionETC = true;
450 }
451 if(wgpuAdapterHasFeature(adapter, WGPUFeatureName_Float32Filterable)) {
452 features.push_back(WGPUFeatureName_Float32Filterable);
453 }
454
455 // Get device
456 WGPUDeviceDescriptor device_desc = WGPU_DEVICE_DESCRIPTOR_INIT;
457 device_desc.label = {"WebGPU device", WGPU_STRLEN};
458
459 device_desc.requiredFeatureCount = features.size();
460 device_desc.requiredFeatures = features.data();
461 device_desc.requiredLimits = &required_limits;
462 device_desc.defaultQueue.label = {"Default WebGPU queue", WGPU_STRLEN};
463
464 WGPUDeviceLostCallbackInfo deviceLostCallbackInfo = WGPU_DEVICE_LOST_CALLBACK_INFO_INIT;
465 deviceLostCallbackInfo.nextInChain = nullptr;
466 deviceLostCallbackInfo.callback = device_lost;
467 deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
468 deviceLostCallbackInfo.userdata1 = this;
469 device_desc.deviceLostCallbackInfo = deviceLostCallbackInfo;
470
471 WGPUUncapturedErrorCallbackInfo uncapturedErrorCallbackInfo = WGPU_UNCAPTURED_ERROR_CALLBACK_INFO_INIT;
472 uncapturedErrorCallbackInfo.nextInChain = nullptr;
473 uncapturedErrorCallbackInfo.callback = error_callback;
474 uncapturedErrorCallbackInfo.userdata1 = this;
475 device_desc.uncapturedErrorCallbackInfo = uncapturedErrorCallbackInfo;
476 // WGPUDawnTogglesDescriptor toggles_desc = {};
477 // toggles_desc.chain;
478 // toggles_desc.enabledTogglesCount;
479 // toggles_desc.enabledToggles;
480 // toggles_desc.disabledTogglesCount;
481 // toggles_desc.disabledToggles;
482 // WGPUDawnCacheDeviceDescriptor dawn_cache_desc = {};
483 // dawn_cache_desc.chain;
484 // dawn_cache_desc.isolationKey;
485
486 WGPURequestDeviceCallbackInfo requestDeviceCallbackInfo = WGPU_REQUEST_DEVICE_CALLBACK_INFO_INIT;
487 requestDeviceCallbackInfo.nextInChain = nullptr;
488 requestDeviceCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
489 requestDeviceCallbackInfo.userdata1 = this;
490 requestDeviceCallbackInfo.callback = request_device;
491 WGPUFuture future = wgpuAdapterRequestDevice(adapter, &device_desc, requestDeviceCallbackInfo);
492
493 WGPUFutureWaitInfo waitInfo = WGPU_FUTURE_WAIT_INFO_INIT;
494 waitInfo.future = future;
495 wgpuInstanceWaitAny(instance, 1, &waitInfo, 0);
496 }
497
498 void GraphicsDeviceWebGPU::maybeCreateUploadCommandEncoder()
499 {
500 if(commandEncoder) return;
501 WGPUCommandEncoderDescriptor command_encoder_desc = WGPU_COMMAND_ENCODER_DESCRIPTOR_INIT;
502 command_encoder_desc.label = {"Upload Command Encoder", WGPU_STRLEN};
503 commandEncoder = wgpuDeviceCreateCommandEncoder(device, &command_encoder_desc);
504 }
505 void GraphicsDeviceWebGPU::initialize_device(WGPUDevice device_in)
506 {
507 device = device_in;
508
509 // Setup logging
510#ifndef __EMSCRIPTEN__
511 WGPULoggingCallbackInfo loggingCallbackInfo = {};
512 loggingCallbackInfo.nextInChain = nullptr;
513 loggingCallbackInfo.callback = logging_callback;
514 loggingCallbackInfo.userdata1 = this;
515 wgpuDeviceSetLoggingCallback(device, loggingCallbackInfo);
516#endif
517
518 WGPULimits device_limits = WGPU_LIMITS_INIT;
519 if(wgpuDeviceGetLimits(device, &device_limits)){
520 LOG_INFO(logger, "device_limits ");
521 LOG_INFO(logger, "maxTextureDimension1D %u", device_limits.maxTextureDimension1D);
522 LOG_INFO(logger, "maxTextureDimension2D %u", device_limits.maxTextureDimension2D);
523 LOG_INFO(logger, "maxTextureDimension3D %u", device_limits.maxTextureDimension3D);
524 LOG_INFO(logger, "maxTextureArrayLayers %u", device_limits.maxTextureArrayLayers);
525 LOG_INFO(logger, "maxBindGroups %u", device_limits.maxBindGroups);
526 LOG_INFO(logger, "maxBindGroupsPlusVertexBuffers %u", device_limits.maxBindGroupsPlusVertexBuffers);
527 LOG_INFO(logger, "maxBindingsPerBindGroup %u", device_limits.maxBindingsPerBindGroup);
528 LOG_INFO(logger, "maxDynamicUniformBuffersPerPipelineLayout %u", device_limits.maxDynamicUniformBuffersPerPipelineLayout);
529 LOG_INFO(logger, "maxDynamicStorageBuffersPerPipelineLayout %u", device_limits.maxDynamicStorageBuffersPerPipelineLayout);
530 LOG_INFO(logger, "maxSampledTexturesPerShaderStage %u", device_limits.maxSampledTexturesPerShaderStage);
531 LOG_INFO(logger, "maxSamplersPerShaderStage %u", device_limits.maxSamplersPerShaderStage);
532 LOG_INFO(logger, "maxStorageBuffersPerShaderStage %u", device_limits.maxStorageBuffersPerShaderStage);
533 LOG_INFO(logger, "maxStorageTexturesPerShaderStage %u", device_limits.maxStorageTexturesPerShaderStage);
534 LOG_INFO(logger, "maxUniformBuffersPerShaderStage %u", device_limits.maxUniformBuffersPerShaderStage);
535 LOG_INFO(logger, "maxUniformBufferBindingSize %llu", device_limits.maxUniformBufferBindingSize);
536 LOG_INFO(logger, "maxStorageBufferBindingSize %llu", device_limits.maxStorageBufferBindingSize);
537 LOG_INFO(logger, "minUniformBufferOffsetAlignment %u", device_limits.minUniformBufferOffsetAlignment);
538 LOG_INFO(logger, "minStorageBufferOffsetAlignment %u", device_limits.minStorageBufferOffsetAlignment);
539 LOG_INFO(logger, "maxVertexBuffers %u", device_limits.maxVertexBuffers);
540 LOG_INFO(logger, "maxBufferSize %llu", device_limits.maxBufferSize);
541 LOG_INFO(logger, "maxVertexAttributes %u", device_limits.maxVertexAttributes);
542 LOG_INFO(logger, "maxVertexBufferArrayStride %u", device_limits.maxVertexBufferArrayStride);
543 LOG_INFO(logger, "maxInterStageShaderVariables %u", device_limits.maxInterStageShaderVariables);
544 LOG_INFO(logger, "maxColorAttachments %u", device_limits.maxColorAttachments);
545 LOG_INFO(logger, "maxColorAttachmentBytesPerSample %u", device_limits.maxColorAttachmentBytesPerSample);
546 LOG_INFO(logger, "maxComputeWorkgroupStorageSize %u", device_limits.maxComputeWorkgroupStorageSize);
547 LOG_INFO(logger, "maxComputeInvocationsPerWorkgroup %u", device_limits.maxComputeInvocationsPerWorkgroup);
548 LOG_INFO(logger, "maxComputeWorkgroupSizeX %u", device_limits.maxComputeWorkgroupSizeX);
549 LOG_INFO(logger, "maxComputeWorkgroupSizeY %u", device_limits.maxComputeWorkgroupSizeY);
550 LOG_INFO(logger, "maxComputeWorkgroupSizeZ %u", device_limits.maxComputeWorkgroupSizeZ);
551 LOG_INFO(logger, "maxComputeWorkgroupsPerDimension %u", device_limits.maxComputeWorkgroupsPerDimension);
552 LOG_INFO(logger, "maxImmediateSize %u", device_limits.maxImmediateSize);
553 }
554
555 // Update capabilities
556 capabilities.capabilities.RenderPass = true;
557 capabilities.capabilities.SyncObjects = false; // TODO
558 capabilities.capabilities.GeometryShaders = false;
559 capabilities.capabilities.TessellationShaders = false;
560 capabilities.capabilities.ComputeShaders = false; // TODO
561 capabilities.capabilities.SupportsHlsl = false;
562 capabilities.capabilities.SupportsMultipleThreads = false;
563 capabilities.capabilities.ConstantBufferOffsetAlignment = device_limits.minUniformBufferOffsetAlignment;
564 capabilities.capabilities.ConstantBufferRange = true;
565 capabilities.capabilities.MaxTexture2DSize = device_limits.maxTextureDimension2D;
566 capabilities.capabilities.MaxTexture3DSize = device_limits.maxTextureDimension3D;
567 capabilities.capabilities.MaxTextureArrayLayers = device_limits.maxTextureArrayLayers;
568
569 defaultSwapChain.initialize(device, surface);
570
571 queue = wgpuDeviceGetQueue(device);
572
573 LOG_INFO(logger, "Has WebGPU Device");
574 has_device = true;
575 }
576
577 void GraphicsDeviceWebGPU::destroy()
578 {
580
581 context.ClearBindGroups();
582 context.SwapBindGroups();
583 context.ClearBindGroups();
584
585 wgpuInstanceRelease(instance);
586 LOG_INFO(logger, "WebGPU destroy");
587 if(commandEncoder){
588 wgpuCommandEncoderRelease(commandEncoder);
589 commandEncoder = nullptr;
590 }
591 wgpuQueueRelease(queue);
592 defaultSwapChain.destroy();
593 wgpuSurfaceRelease(surface);
594
595 wgpuDeviceDestroy(device);
596 wgpuDeviceRelease(device);
597
598 wgpuAdapterRelease(adapter);
599 }
600
602 {
603 pipeline_states.releaseResources();
604 renderTargets.releaseResources();
605 textures.releaseResources();
606 buffers.releaseResources();
607 effects.releaseResources();
608 }
609
611 {
612 context.beginFrame();
613
614 if(commandEncoder){
615 WGPUCommandBufferDescriptor command_buffer_desc = WGPU_COMMAND_BUFFER_DESCRIPTOR_INIT;
616 command_buffer_desc.label = {"Upload Command Buffer", WGPU_STRLEN};
617 WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(commandEncoder, &command_buffer_desc);
618 wgpuCommandEncoderRelease(commandEncoder);
619 commandEncoder = nullptr;
620 wgpuQueueSubmit(queue, 1, &command_buffer);
621 wgpuCommandBufferRelease(command_buffer);
622 buffers.resetInstances();
623 }
624
625 context.ClearBindGroups();
626
627#ifndef __EMSCRIPTEN__
628 // Emscripten: wgpuInstanceProcessEvents is unsupported (use requestAnimationFrame via html5.h instead)
629 wgpuInstanceProcessEvents(instance);
630 wgpuDeviceTick(device);
631#endif
632
633 defaultSwapChain.beginFrame();
634
635 WGPUCommandEncoderDescriptor command_encoder_desc = WGPU_COMMAND_ENCODER_DESCRIPTOR_INIT;
636 command_encoder_desc.label = {"Default Command Encoder", WGPU_STRLEN};
637 commandEncoder = wgpuDeviceCreateCommandEncoder(device, &command_encoder_desc);
638 context.setDefaults();
639 }
640
641 void GraphicsDeviceWebGPU::endFrame(uint32_t syncInterval, PresentFlags presentFlags)
642 {
643 context.updateRenderPass();
644 context.endRenderPassInt();
645
646#ifndef __EMSCRIPTEN__
647 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
648 src.texture = defaultSwapChain.resolveTexture;
649 src.mipLevel = 0;
650 src.origin = {0, 0, 0};
651 src.aspect = WGPUTextureAspect_All;
652 WGPUTexelCopyTextureInfo dst = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
653 WGPUSurfaceTexture surfaceTexture = context.graphicsDevice->defaultSwapChain.getTextureData();
654 dst.texture = surfaceTexture.texture;
655 dst.mipLevel = 0;
656 dst.origin = {0, 0, 0};
657 dst.aspect = WGPUTextureAspect_All;
658 WGPUExtent3D copy_size = {(uint32_t)defaultSwapChain.set_width, (uint32_t)defaultSwapChain.set_height, 1};
659 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &src, &dst, &copy_size);
660 wgpuTextureRelease(surfaceTexture.texture);
661#endif
662
663 WGPUCommandBufferDescriptor command_buffer_desc = WGPU_COMMAND_BUFFER_DESCRIPTOR_INIT;
664 command_buffer_desc.label = {"Default Command Buffer", WGPU_STRLEN};
665 WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(commandEncoder, &command_buffer_desc);
666 wgpuCommandEncoderRelease(commandEncoder);
667 commandEncoder = nullptr;
668 wgpuQueueSubmit(queue, 1, &command_buffer);
669 wgpuCommandBufferRelease(command_buffer);
670 buffers.resetInstances();
671
672 // wgpuQueueOnSubmittedWorkDone
673
674 defaultSwapChain.endFrame(syncInterval, presentFlags);
675
676 context.SwapBindGroups();
677 }
678
679 Cogs::ResourceStatistics Cogs::GraphicsDeviceWebGPU::getResourceStatistics()
680 {
681 ResourceStatistics stats{};
682
683 stats.bufferMemoryConsumption = buffers.bufferMemoryConsumption;
684 stats.textureMemoryConsumption = textures.textureMemoryConsumption;
685 stats.bufferCount = static_cast<uint32_t>(buffers.buffers.size());
686 stats.vertexArrayObjectCount = 0;
687 stats.inputLayoutCount = static_cast<uint32_t>(buffers.inputLayouts.size());
688 stats.textureCount = static_cast<uint32_t>(textures.textures.size());
689 stats.samplerStateCount = static_cast<uint32_t>(textures.samplerStates.size());
690 stats.effectCount = static_cast<uint32_t>(effects.effects.size());
691 stats.blendStateCount = 0;
692 stats.rasterizerStateCount = 0;
693 stats.depthStencilStateCount = 0;
694 stats.rendertargetsCount = static_cast<uint32_t>(renderTargets.render_targets.size());
695 stats.framebufferCount = 0;
696
697 return stats;
698 }
699}
virtual void releaseResources() override
Releases all allocated buffer resources.
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