Cogs.Core
BindGroupsWebGPU.cpp
1#include "BindGroupsWebGPU.h"
2#include "GraphicsDeviceWebGPU.h"
3
4#include "Foundation/Logging/Logger.h"
5
6namespace Cogs {
7 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BindGroupsWebGPU");
8
9 void BindGroupsWebGPU::initialize(GraphicsDeviceWebGPU* device_in) {
10 graphicsDevice = device_in;
11 }
12
13 [[nodiscard]]
14 WGPUShaderStage bindingVisibilityToShaderStage(const uint32_t visibility)
15 {
16 uint32_t effectiveVisibility = visibility;
17 if (effectiveVisibility == Cogs::BindingVisibilityNone) {
18 effectiveVisibility = Cogs::BindingVisibilityVertex | Cogs::BindingVisibilityFragment;
19 }
20
21 uint32_t shaderStage = 0;
22 if ((effectiveVisibility & Cogs::BindingVisibilityVertex) != 0) {
23 shaderStage |= WGPUShaderStage_Vertex;
24 }
25 if ((effectiveVisibility & Cogs::BindingVisibilityFragment) != 0) {
26 shaderStage |= WGPUShaderStage_Fragment;
27 }
28 if ((effectiveVisibility & Cogs::BindingVisibilityCompute) != 0) {
29 shaderStage |= WGPUShaderStage_Compute;
30 }
31
32 return static_cast<WGPUShaderStage>(shaderStage);
33 }
34
35 [[nodiscard]]
36 WGPUTextureViewDimension ResourceDimensionsToViewDimension(const Cogs::ResourceDimensions dimension)
37 {
38 switch (dimension) {
39 case Cogs::ResourceDimensions::Texture1D:
40 return WGPUTextureViewDimension_1D;
41 case Cogs::ResourceDimensions::Texture2D:
42 return WGPUTextureViewDimension_2D;
43 case Cogs::ResourceDimensions::Texture2DArray:
44 return WGPUTextureViewDimension_2DArray;
45 case Cogs::ResourceDimensions::Texture3D:
46 return WGPUTextureViewDimension_3D;
47 case Cogs::ResourceDimensions::TextureCube:
48 return WGPUTextureViewDimension_Cube;
49 default:
50 return WGPUTextureViewDimension_Undefined;
51 }
52 }
53
54 [[nodiscard]]
55 WGPUTextureSampleType bindingTextureSampleTypeToWebGPU(
56 const Cogs::BindingTextureSampleType sampleType,
57 const bool isDepthTexture,
58 const bool multisampled)
59 {
60 switch (sampleType) {
61 case Cogs::BindingTextureSampleType::Float:
62 return multisampled ? WGPUTextureSampleType_UnfilterableFloat : WGPUTextureSampleType_Float;
63 case Cogs::BindingTextureSampleType::UnfilterableFloat:
64 return WGPUTextureSampleType_UnfilterableFloat;
65 case Cogs::BindingTextureSampleType::Depth:
66 return WGPUTextureSampleType_Depth;
67 case Cogs::BindingTextureSampleType::Sint:
68 return WGPUTextureSampleType_Sint;
69 case Cogs::BindingTextureSampleType::Uint:
70 return WGPUTextureSampleType_Uint;
71 default:
72 return isDepthTexture ? WGPUTextureSampleType_Depth : WGPUTextureSampleType_Float;
73 }
74 }
75
76 [[nodiscard]]
77 WGPUSamplerBindingType bindingSamplerTypeToWebGPU(
78 const Cogs::BindingSamplerBindingType samplerType,
79 const bool isDepthTexture,
80 const size_t nameHash)
81 {
82 switch (samplerType) {
83 case Cogs::BindingSamplerBindingType::Filtering:
84 return WGPUSamplerBindingType_Filtering;
85 case Cogs::BindingSamplerBindingType::NonFiltering:
86 return WGPUSamplerBindingType_NonFiltering;
87 case Cogs::BindingSamplerBindingType::Comparison:
88 return WGPUSamplerBindingType_Comparison;
89 default:
90 return (isDepthTexture || nameHash == Cogs::hash("shadowSampler"))
91 ? WGPUSamplerBindingType_Comparison
92 : WGPUSamplerBindingType_Filtering;
93 }
94 }
95
96
97 [[nodiscard]]
98 WGPUStorageTextureAccess bindingStorageTextureAccessToWebGPU(Cogs::BindingStorageTextureAccess access) {
99 switch (access)
100 {
101 case Cogs::BindingStorageTextureAccess::WriteOnly:
102 return WGPUStorageTextureAccess_WriteOnly;
103 case Cogs::BindingStorageTextureAccess::ReadOnly:
104 return WGPUStorageTextureAccess_ReadOnly;
105 case Cogs::BindingStorageTextureAccess::ReadWrite:
106 return WGPUStorageTextureAccess_ReadWrite;
107 default:
108 return WGPUStorageTextureAccess_WriteOnly;
109 }
110 }
111
112 [[nodiscard]]
113 WGPUTextureFormat textureFormatToWebGPU(Cogs::Format format) {
114 switch (format) {
115 case Cogs::Format::R8G8B8A8_UNORM:
116 return WGPUTextureFormat_RGBA8Unorm;
117 case Cogs::Format::R8G8B8A8_SNORM:
118 return WGPUTextureFormat_RGBA8Snorm;
119 case Cogs::Format::R8G8B8A8_UINT:
120 return WGPUTextureFormat_RGBA8Uint;
121 case Cogs::Format::R8G8B8A8_SINT:
122 return WGPUTextureFormat_RGBA8Sint;
123 case Cogs::Format::R16G16B16A16_UINT:
124 return WGPUTextureFormat_RGBA16Uint;
125 case Cogs::Format::R16G16B16A16_SINT:
126 return WGPUTextureFormat_RGBA16Sint;
127 case Cogs::Format::R16G16B16A16_FLOAT:
128 return WGPUTextureFormat_RGBA16Float;
129 case Cogs::Format::R32_UINT:
130 return WGPUTextureFormat_R32Uint;
131 case Cogs::Format::R32_SINT:
132 return WGPUTextureFormat_R32Sint;
133 case Cogs::Format::R32_FLOAT:
134 return WGPUTextureFormat_R32Float;
135 case Cogs::Format::R32G32_UINT:
136 return WGPUTextureFormat_RG32Uint;
137 case Cogs::Format::R32G32_SINT:
138 return WGPUTextureFormat_RG32Sint;
139 case Cogs::Format::R32G32_FLOAT:
140 return WGPUTextureFormat_RG32Float;
141 case Cogs::Format::R32G32B32A32_UINT:
142 return WGPUTextureFormat_RGBA32Uint;
143 case Cogs::Format::R32G32B32A32_SINT:
144 return WGPUTextureFormat_RGBA32Sint;
145 case Cogs::Format::R32G32B32A32_FLOAT:
146 return WGPUTextureFormat_RGBA32Float;
147 case Cogs::Format::B8G8R8A8:
148 return WGPUTextureFormat_BGRA8Unorm;
149 default:
150 return WGPUTextureFormat_Undefined;
151 }
152 }
153
154 WGPUBindGroupLayout BindGroupsWebGPU::createBindGroupLayout(GraphicsDeviceWebGPU* device, const BindGroupDescription& desc) {
155 if (desc.numEntries == 0) return nullptr;
156 assert(desc.numEntries <= MaxBindGroupEntries);
157
158 WGPUBindGroupLayoutEntry la_ents[MaxBindGroupEntries];
159 for (uint16_t entryIdx = 0; entryIdx < desc.numEntries; entryIdx++) {
160 const Cogs::BindGroupEntryDescription& entry = desc.entries[entryIdx];
161 WGPUBindGroupLayoutEntry& la_ent = la_ents[entryIdx];
162 la_ent = WGPU_BIND_GROUP_LAYOUT_ENTRY_INIT;
163 la_ent.binding = entry.binding;
164 la_ent.visibility = bindingVisibilityToShaderStage(entry.visibility);
165
166 switch (entry.resourceType) {
167 case Cogs::BindingResourceType::UniformBuffer:
168 la_ent.buffer.type = WGPUBufferBindingType_Uniform;
169 break;
170 case Cogs::BindingResourceType::StorageBuffer:
171 la_ent.buffer.type = WGPUBufferBindingType_Storage;
172 break;
173 case Cogs::BindingResourceType::Texture:
174 la_ent.texture.viewDimension = ResourceDimensionsToViewDimension(entry.textureDimension);
175 la_ent.texture.multisampled = entry.multisampled ? 1 : 0;
176 la_ent.texture.sampleType = bindingTextureSampleTypeToWebGPU(entry.textureSampleType,
177 entry.isDepthTexture,
178 entry.multisampled);
179 break;
180 case Cogs::BindingResourceType::Sampler:
181 la_ent.sampler.type = bindingSamplerTypeToWebGPU(entry.samplerBindingType,
182 entry.isDepthTexture,
183 entry.nameHash);
184 break;
185 case Cogs::BindingResourceType::StorageTexture:
186 la_ent.storageTexture.viewDimension = ResourceDimensionsToViewDimension(entry.textureDimension);
187 la_ent.storageTexture.access = bindingStorageTextureAccessToWebGPU(entry.storageTextureAccess);
188 la_ent.storageTexture.format = textureFormatToWebGPU(entry.format);
189 break;
190 default:
191 LOG_ERROR(logger,
192 "Unsupported bind-group resource type %d for entry '%d'.",
193 int(entry.resourceType),
194 entry.binding);
195 return nullptr;
196 }
197 }
198 WGPUBindGroupLayoutDescriptor descriptor = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
199 descriptor.entries = la_ents;
200 descriptor.entryCount = desc.numEntries;
201 return wgpuDeviceCreateBindGroupLayout(device->device, &descriptor);
202 }
203
204 BindGroupHandle BindGroupsWebGPU::createBindGroup(const BindGroupDescription* desc) {
205 if (!desc || desc->numEntries > MaxBindGroupEntries) {
207 }
208 BindGroupWebGPU bindGroup = {};
209 bindGroup.numBindings = desc->numEntries;
210 for (size_t i = 0; i < desc->numEntries; ++i) {
211 BindingWebGPU& binding = bindGroup.bindings[i];
212 binding = {};
213 binding.description = desc->entries[i];
214 binding.entry = WGPU_BIND_GROUP_ENTRY_INIT;
215 binding.state = BindingState::BindingState_Invalid;
216 }
217
218 bindGroup.descHash = desc->hash();
219 return bind_groups.addResource(std::move(bindGroup));
220 }
221
222 uint32_t bindGroupBindingHandleFromBinding(uint32_t binding) {
223 return binding + 1; // Offset by 1 to avoid using 0 as a valid handle
224 }
225
226 uint32_t bindingFromBindGroupBindingHandle(int64_t handle) {
227 return static_cast<uint32_t>(handle - 1);
228 }
229
230
231 BindGroupConstantBufferBindingHandle BindGroupsWebGPU::getConstantBufferBinding(BindGroupHandle handle, const StringView& name) {
232 if (!HandleIsValid(handle)) {
234 }
235 const uint64_t nameHash = Cogs::hash(name);
236 const BindGroupWebGPU& bind_group = bind_groups[handle];
237 for (size_t i = 0; i < bind_group.numBindings; ++i) {
238 const BindingWebGPU& binding = bind_group.bindings[i];
239 if (binding.description.nameHash == nameHash) {
240 if (binding.description.resourceType != BindingResourceType::UniformBuffer) {
241 LOG_ERROR(logger, "Binding at %d is not a uniform buffer binding.", binding.description.binding);
243 }
244 return static_cast<BindGroupConstantBufferBindingHandle>(bindGroupBindingHandleFromBinding(static_cast<uint32_t>(i)));
245 }
246 }
248 }
249
250 BindGroupTextureBindingHandle BindGroupsWebGPU::getTextureBinding(BindGroupHandle handle, const StringView& name) {
251 if (!HandleIsValid(handle)) {
253 }
254 const uint64_t nameHash = Cogs::hash(name);
255 const BindGroupWebGPU& bind_group = bind_groups[handle];
256 for (size_t i = 0; i < bind_group.numBindings; ++i) {
257 const BindingWebGPU& binding = bind_group.bindings[i];
258 if (binding.description.nameHash == nameHash) {
259 if (binding.description.resourceType != BindingResourceType::Texture &&
260 binding.description.resourceType != BindingResourceType::StorageTexture) {
261 LOG_ERROR(logger, "Binding at %d is not a texture binding.", binding.description.binding);
263 }
264 return static_cast<BindGroupTextureBindingHandle>(bindGroupBindingHandleFromBinding(static_cast<uint32_t>(i)));
265 }
266 }
268 }
269
270 BindGroupSamplerStateBindingHandle BindGroupsWebGPU::getSamplerBinding(BindGroupHandle handle, const StringView& name) {
271 if (!HandleIsValid(handle)) {
273 }
274 const uint64_t nameHash = Cogs::hash(name);
275 const BindGroupWebGPU& bind_group = bind_groups[handle];
276 for (size_t i = 0; i < bind_group.numBindings; ++i) {
277 const BindingWebGPU& binding = bind_group.bindings[i];
278 if (binding.description.nameHash == nameHash) {
279 if (binding.description.resourceType != BindingResourceType::Sampler) {
280 LOG_ERROR(logger, "Binding at %d is not a sampler binding.", binding.description.binding);
282 }
283 return static_cast<BindGroupSamplerStateBindingHandle>(bindGroupBindingHandleFromBinding(static_cast<uint32_t>(i)));
284 }
285 }
287 }
288
289 bool BindGroupsWebGPU::isCompatable(BindGroupHandle handle, const BindGroupDescription &desc) {
290 return isCompatable(handle, desc.hash());
291 }
292
293 bool BindGroupsWebGPU::isCompatable(BindGroupHandle handle, size_t descHash) {
294 if (!HandleIsValid(handle)) {
295 return false;
296 }
297 // numEntries takes part in the hash, so this also covers differing binding counts.
298 return bind_groups[handle].descHash == descHash;
299 }
300
301
302 bool BindGroupsWebGPU::setTexture(BindGroupHandle handle, BindGroupTextureBindingHandle bindingHandle, const TextureHandle textureHandle) {
303 if (!HandleIsValid(handle) || !HandleIsValid(bindingHandle)) {
304 return false;
305 }
306 BindGroupWebGPU& bind_group = bind_groups[handle];
307 uint32_t decoded_binding = bindingFromBindGroupBindingHandle(bindingHandle.handle);
308 if (decoded_binding >= bind_group.numBindings) {
309 LOG_ERROR(logger, "Binding handle %lld is out of range.", bindingHandle.handle);
310 return false;
311 }
312 BindingWebGPU& binding = bind_group.bindings[decoded_binding];
313 if (binding.description.resourceType != BindingResourceType::Texture &&
314 binding.description.resourceType != BindingResourceType::StorageTexture) {
315 LOG_ERROR(logger, "Binding at %d is not a texture binding.", binding.description.binding);
316 return false;
317 }
318 if (!HandleIsValid(textureHandle)) {
319 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
320 bind_group.bindings[decoded_binding].entry = WGPU_BIND_GROUP_ENTRY_INIT;
321 return false;
322 }
323 WGPUBindGroupEntry & bg_ent = bind_group.bindings[decoded_binding].entry;
324 const TextureWebGPU& texture = graphicsDevice->textures.textures[textureHandle];
325 if (bind_group.bindings[decoded_binding].state == BindingState_Invalid || bg_ent.textureView != texture.texture_view) {
326 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
327 bg_ent.binding = binding.description.binding;
328 bg_ent.buffer = nullptr;
329 bg_ent.offset = 0;
330 bg_ent.size = 0;
331 bg_ent.sampler = nullptr;
332 bg_ent.textureView = texture.texture_view;
333 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
334 }
335 return true;
336 }
337
338 bool BindGroupsWebGPU::setTexture(BindGroupHandle handle, BindGroupTextureBindingHandle bindingHandle, const TextureViewHandle textureViewHandle) {
339 if (!HandleIsValid(handle) || !HandleIsValid(bindingHandle)) {
340 return false;
341 }
342 BindGroupWebGPU& bind_group = bind_groups[handle];
343 uint32_t decoded_binding = bindingFromBindGroupBindingHandle(bindingHandle.handle);
344 if (decoded_binding >= bind_group.numBindings) {
345 LOG_ERROR(logger, "Binding handle %lld is out of range.", bindingHandle.handle);
346 return false;
347 }
348 BindingWebGPU& binding = bind_group.bindings[decoded_binding];
349 if (binding.description.resourceType != BindingResourceType::Texture) {
350 LOG_ERROR(logger, "Binding at %d is not a texture binding.", binding.description.binding);
351 return false;
352 }
353 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
354 if (!HandleIsValid(textureViewHandle)) {
355 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
356 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
357 return false;
358 }
359 const TextureViewWebGPU& texture_view = graphicsDevice->textures.textureViews[textureViewHandle];
360 if (bind_group.bindings[decoded_binding].state == BindingState_Invalid || bg_ent.textureView != texture_view.texture_view) {
361 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
362 bg_ent.binding = binding.description.binding;
363 bg_ent.buffer = nullptr;
364 bg_ent.offset = 0;
365 bg_ent.size = 0;
366 bg_ent.sampler = nullptr;
367 bg_ent.textureView = texture_view.texture_view;
368 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
369 }
370 return true;
371 }
372
373 bool BindGroupsWebGPU::setSamplerState(BindGroupHandle handle, BindGroupSamplerStateBindingHandle bindingHandle, SamplerStateHandle samplerStateHandle)
374 {
375 if (!HandleIsValid(handle) || !HandleIsValid(bindingHandle)) {
376 return false;
377 }
378 BindGroupWebGPU& bind_group = bind_groups[handle];
379 uint32_t decoded_binding = bindingFromBindGroupBindingHandle(bindingHandle.handle);
380 if (decoded_binding >= bind_group.numBindings) {
381 LOG_ERROR(logger, "Binding handle %lld is out of range.", bindingHandle.handle);
382 return false;
383 }
384 BindingWebGPU& binding = bind_group.bindings[decoded_binding];
385 if (binding.description.resourceType != BindingResourceType::Sampler) {
386 LOG_ERROR(logger, "Binding at %d is not a sampler binding.", binding.description.binding);
387 return false;
388 }
389 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
390 if (!HandleIsValid(samplerStateHandle)) {
391 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
392 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
393 return false;
394 }
395 const SamplerStateWebGPU& sampler = graphicsDevice->textures.samplerStates[samplerStateHandle];
396 if (bind_group.bindings[decoded_binding].state == BindingState_Invalid || bg_ent.sampler != sampler.sampler) {
397 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
398 bg_ent.binding = binding.description.binding;
399 bg_ent.buffer = nullptr;
400 bg_ent.offset = 0;
401 bg_ent.size = 0;
402 bg_ent.sampler = sampler.sampler;
403 bg_ent.textureView = nullptr;
404 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
405 }
406 return true;
407 }
408 bool BindGroupsWebGPU::setConstantBuffer(BindGroupHandle handle, BindGroupConstantBufferBindingHandle bindingHandle, BufferHandle bufferHandle, const uint32_t offset, const uint32_t size)
409 {
410 if (!HandleIsValid(handle) || !HandleIsValid(bindingHandle)) {
411 return false;
412 }
413 BindGroupWebGPU& bind_group = bind_groups[handle];
414 uint32_t decoded_binding = bindingFromBindGroupBindingHandle(bindingHandle.handle);
415 if (decoded_binding >= bind_group.numBindings) {
416 LOG_ERROR(logger, "Binding handle %lld is out of range.", bindingHandle.handle);
417 return false;
418 }
419 BindingWebGPU& binding = bind_group.bindings[decoded_binding];
420 if (binding.description.resourceType != BindingResourceType::UniformBuffer) {
421 LOG_ERROR(logger, "Binding at %d is not a constant buffer binding.", binding.description.binding);
422 return false;
423 }
424 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
425 if (!HandleIsValid(bufferHandle)) {
426 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
427 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
428 return false;
429 }
430 BufferWebGPU& buffer = graphicsDevice->buffers.buffers[bufferHandle];
431 const uint64_t entrySize = (size == ~0u) ? WGPU_WHOLE_SIZE : size;
432 if (bind_group.bindings[decoded_binding].state == BindingState_Invalid ||
433 bg_ent.buffer != buffer.buffer ||
434 bg_ent.offset != offset ||
435 bg_ent.size != entrySize) {
436 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
437 bg_ent.binding = binding.description.binding;
438 bg_ent.buffer = buffer.buffer;
439 bg_ent.offset = offset;
440 bg_ent.size = entrySize;
441 bg_ent.sampler = nullptr;
442 bg_ent.textureView = nullptr;
443 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
444 }
445 return true;
446 }
447
448
449 void Cogs::BindGroupsWebGPU::releaseBindGroup(BindGroupHandle handle)
450 {
451 if (!HandleIsValid(handle)) return;
452 BindGroupWebGPU& target = bind_groups[handle];
453
454 if (target.bindGroup != nullptr) {
455 wgpuBindGroupRelease(target.bindGroup);
456 target.bindGroup = nullptr;
457 graphicsDevice->counters.bind_group--;
458 }
459 if (target.layout != nullptr) {
460 wgpuBindGroupLayoutRelease(target.layout);
461 target.layout = nullptr;
462 graphicsDevice->counters.bind_group_layout--;
463 }
464 bind_groups.removeResource(handle);
465 }
466
467 WGPUBindGroupLayout createBindGroupLayoutFromDescription(GraphicsDeviceWebGPU* graphicsDevice, const BindGroupWebGPU& bind_group) {
468 std::vector<WGPUBindGroupLayoutEntry> layoutEntries;
469 for (size_t i = 0; i < bind_group.numBindings; ++i) {
470 const BindingWebGPU& binding = bind_group.bindings[i];
471 WGPUBindGroupLayoutEntry layoutEntry = WGPU_BIND_GROUP_LAYOUT_ENTRY_INIT;
472 layoutEntry.binding = binding.description.binding;
473 layoutEntry.visibility = bindingVisibilityToShaderStage(binding.description.visibility);
474 switch (binding.description.resourceType) {
475 case BindingResourceType::UniformBuffer:
476 layoutEntry.buffer.type = WGPUBufferBindingType_Uniform;
477 break;
478 case BindingResourceType::StorageBuffer:
479 layoutEntry.buffer.type = WGPUBufferBindingType_Storage;
480 break;
481 case BindingResourceType::Texture:
482 layoutEntry.texture.viewDimension = ResourceDimensionsToViewDimension(binding.description.textureDimension);
483 layoutEntry.texture.multisampled = binding.description.multisampled ? 1 : 0;
484 layoutEntry.texture.sampleType = bindingTextureSampleTypeToWebGPU(binding.description.textureSampleType,
485 binding.description.isDepthTexture,
486 binding.description.multisampled);
487 break;
488 case BindingResourceType::Sampler:
489 layoutEntry.sampler.type = bindingSamplerTypeToWebGPU(binding.description.samplerBindingType,
490 binding.description.isDepthTexture,
491 binding.description.nameHash);
492 break;
493 case BindingResourceType::StorageTexture:
494 layoutEntry.storageTexture.viewDimension = ResourceDimensionsToViewDimension(binding.description.textureDimension);
495 layoutEntry.storageTexture.access = bindingStorageTextureAccessToWebGPU(binding.description.storageTextureAccess);
496 layoutEntry.storageTexture.format = textureFormatToWebGPU(binding.description.format);
497 break;
498 default:
499 LOG_ERROR(logger, "Unsupported bind-group resource type %d for entry '%d'.",
500 int(binding.description.resourceType),
501 binding.description.binding);
502 return nullptr;
503 }
504 layoutEntries.push_back(layoutEntry);
505 }
506 WGPUBindGroupLayoutDescriptor layoutDesc = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
507 layoutDesc.entryCount = static_cast<uint32_t>(layoutEntries.size());
508 layoutDesc.entries = layoutEntries.data();
509 return wgpuDeviceCreateBindGroupLayout(graphicsDevice->device, &layoutDesc);
510 }
511
512 WGPUBindGroup BindGroupsWebGPU::getNativeBindGroup(BindGroupHandle handle) {
513 if (!HandleIsValid(handle)) return nullptr;
514 BindGroupWebGPU& bind_group = bind_groups[handle];
515 if (bind_group.numBindings == 0) return nullptr;
516 if (bind_group.layout == nullptr) {
517 bind_group.layout = createBindGroupLayoutFromDescription(graphicsDevice, bind_group);
518 if (bind_group.layout != nullptr) {
519 graphicsDevice->counters.bind_group_layout++;
520 }
521 }
522 if (bind_group.layout == nullptr) {
523 LOG_ERROR(logger, "Failed to create bind group layout.");
524 return nullptr;
525 }
526
527 bool recreateBindGroup = bind_group.bindGroup == nullptr;
528 if (!recreateBindGroup) {
529 for (size_t i = 0; i < bind_group.numBindings; ++i) {
530 if (bind_group.bindings[i].state == BindingState::BindingState_NeedsUpdate) {
531 recreateBindGroup = true;
532 break;
533 }
534 }
535 }
536 if (recreateBindGroup) {
537 // Keep the previous bind group alive until the new one exists: releasing it first could drop
538 // Dawn's last internal ref on a view/buffer whose raw pointer our cached WGPUBindGroupEntry
539 // still names (see BindingWebGPU comment), causing an actual use-after-free here rather than
540 // a well-defined Dawn validation error. Does not make it legal for the application to release
541 // a resource that is still bound - that stays an application error either way. This ordering
542 // also leaves the previous group intact if anything below fails.
543 WGPUBindGroup previous = bind_group.bindGroup;
544
545 WGPUBindGroupEntry bg_ents[MaxBindGroupEntries];
546 for (size_t i = 0; i < bind_group.numBindings; ++i) {
547 if (bind_group.bindings[i].state == BindingState::BindingState_Invalid) {
548 LOG_ERROR(logger, "Binding at %d is invalid and cannot be used to create a bind group.", bind_group.bindings[i].description.binding);
549 return nullptr;
550 }
551 bg_ents[i] = bind_group.bindings[i].entry;
552 }
553 WGPUBindGroupDescriptor bindGroupDesc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
554 bindGroupDesc.layout = bind_group.layout;
555 bindGroupDesc.entryCount = bind_group.numBindings;
556 bindGroupDesc.entries = bg_ents;
557
558 WGPUBindGroup created = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bindGroupDesc);
559 if (created == nullptr) {
560 LOG_ERROR(logger, "Failed to create bind group.");
561 return nullptr;
562 }
563 if (previous != nullptr) {
564 wgpuBindGroupRelease(previous);
565 graphicsDevice->counters.bind_group--;
566 }
567 bind_group.bindGroup = created;
568 graphicsDevice->counters.bind_group++;
569 graphicsDevice->frame_descriptor_count += bind_group.numBindings;
570 for (size_t i = 0; i < bind_group.numBindings; ++i) {
571 bind_group.bindings[i].state = BindingState::BindingState_Updated;
572 }
573 }
574
575
576 return bind_group.bindGroup;
577 }
578
579
580
581}
Log implementation class.
Definition: LogManager.h:140
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
handle_type handle
Internal resource handle.
Definition: Common.h:75