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