1#include "BindGroupsWebGPU.h"
2#include "GraphicsDeviceWebGPU.h"
4#include "Foundation/Logging/Logger.h"
9 void BindGroupsWebGPU::initialize(GraphicsDeviceWebGPU* device_in) {
10 graphicsDevice = device_in;
14 WGPUShaderStage bindingVisibilityToShaderStage(
const uint32_t visibility)
16 uint32_t effectiveVisibility = visibility;
17 if (effectiveVisibility == Cogs::BindingVisibilityNone) {
18 effectiveVisibility = Cogs::BindingVisibilityVertex | Cogs::BindingVisibilityFragment;
21 uint32_t shaderStage = 0;
22 if ((effectiveVisibility & Cogs::BindingVisibilityVertex) != 0) {
23 shaderStage |= WGPUShaderStage_Vertex;
25 if ((effectiveVisibility & Cogs::BindingVisibilityFragment) != 0) {
26 shaderStage |= WGPUShaderStage_Fragment;
28 if ((effectiveVisibility & Cogs::BindingVisibilityCompute) != 0) {
29 shaderStage |= WGPUShaderStage_Compute;
32 return static_cast<WGPUShaderStage
>(shaderStage);
36 WGPUTextureViewDimension ResourceDimensionsToViewDimension(
const Cogs::ResourceDimensions 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;
50 return WGPUTextureViewDimension_Undefined;
55 WGPUTextureSampleType bindingTextureSampleTypeToWebGPU(
56 const Cogs::BindingTextureSampleType sampleType,
57 const bool isDepthTexture,
58 const bool multisampled)
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;
72 return isDepthTexture ? WGPUTextureSampleType_Depth : WGPUTextureSampleType_Float;
77 WGPUSamplerBindingType bindingSamplerTypeToWebGPU(
78 const Cogs::BindingSamplerBindingType samplerType,
79 const bool isDepthTexture,
80 const size_t nameHash)
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;
90 return (isDepthTexture || nameHash ==
Cogs::hash(
"shadowSampler"))
91 ? WGPUSamplerBindingType_Comparison
92 : WGPUSamplerBindingType_Filtering;
98 WGPUStorageTextureAccess bindingStorageTextureAccessToWebGPU(Cogs::BindingStorageTextureAccess access) {
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;
108 return WGPUStorageTextureAccess_WriteOnly;
113 WGPUTextureFormat textureFormatToWebGPU(Cogs::Format 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;
150 return WGPUTextureFormat_Undefined;
154 WGPUBindGroupLayout BindGroupsWebGPU::createBindGroupLayout(GraphicsDeviceWebGPU* device,
const BindGroupDescription& desc) {
155 if (desc.numEntries == 0)
return nullptr;
156 assert(desc.numEntries <= MaxBindGroupEntries);
158 WGPUBindGroupLayoutEntry la_ents[MaxBindGroupEntries];
159 for (uint16_t entryIdx = 0; entryIdx < desc.numEntries; 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);
166 switch (entry.resourceType) {
167 case Cogs::BindingResourceType::UniformBuffer:
168 la_ent.buffer.type = WGPUBufferBindingType_Uniform;
170 case Cogs::BindingResourceType::StorageBuffer:
171 la_ent.buffer.type = WGPUBufferBindingType_Storage;
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,
180 case Cogs::BindingResourceType::Sampler:
181 la_ent.sampler.type = bindingSamplerTypeToWebGPU(entry.samplerBindingType,
182 entry.isDepthTexture,
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);
192 "Unsupported bind-group resource type %d for entry '%d'.",
193 int(entry.resourceType),
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);
204 BindGroupHandle BindGroupsWebGPU::createBindGroup(
const BindGroupDescription* desc) {
205 if (!desc || desc->numEntries > MaxBindGroupEntries) {
208 BindGroupWebGPU bindGroup = {};
209 bindGroup.numBindings = desc->numEntries;
210 for (
size_t i = 0; i < desc->numEntries; ++i) {
211 BindingWebGPU& binding = bindGroup.bindings[i];
213 binding.description = desc->entries[i];
214 binding.entry = WGPU_BIND_GROUP_ENTRY_INIT;
215 binding.state = BindingState::BindingState_Invalid;
218 bindGroup.descHash = desc->hash();
219 return bind_groups.addResource(std::move(bindGroup));
222 uint32_t bindGroupBindingHandleFromBinding(uint32_t binding) {
226 uint32_t bindingFromBindGroupBindingHandle(int64_t handle) {
227 return static_cast<uint32_t
>(handle - 1);
231 BindGroupConstantBufferBindingHandle BindGroupsWebGPU::getConstantBufferBinding(BindGroupHandle handle,
const StringView& 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);
244 return static_cast<BindGroupConstantBufferBindingHandle
>(bindGroupBindingHandleFromBinding(
static_cast<uint32_t
>(i)));
250 BindGroupTextureBindingHandle BindGroupsWebGPU::getTextureBinding(BindGroupHandle handle,
const StringView& 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);
264 return static_cast<BindGroupTextureBindingHandle
>(bindGroupBindingHandleFromBinding(
static_cast<uint32_t
>(i)));
270 BindGroupSamplerStateBindingHandle BindGroupsWebGPU::getSamplerBinding(BindGroupHandle handle,
const StringView& 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);
283 return static_cast<BindGroupSamplerStateBindingHandle
>(bindGroupBindingHandleFromBinding(
static_cast<uint32_t
>(i)));
289 bool BindGroupsWebGPU::isCompatable(BindGroupHandle handle,
const BindGroupDescription &desc) {
290 return isCompatable(handle, desc.hash());
294 if (!HandleIsValid(handle)) {
298 return bind_groups[handle].descHash == descHash;
303 if (!HandleIsValid(handle) || !HandleIsValid(bindingHandle)) {
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);
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);
319 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
320 bind_group.bindings[decoded_binding].entry = WGPU_BIND_GROUP_ENTRY_INIT;
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;
331 bg_ent.sampler =
nullptr;
332 bg_ent.textureView = texture.texture_view;
333 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
338 bool BindGroupsWebGPU::setTexture(BindGroupHandle handle, BindGroupTextureBindingHandle bindingHandle,
const TextureViewHandle textureViewHandle) {
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);
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);
353 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
355 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
356 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
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;
366 bg_ent.sampler =
nullptr;
367 bg_ent.textureView = texture_view.texture_view;
368 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
373 bool BindGroupsWebGPU::setSamplerState(BindGroupHandle handle, BindGroupSamplerStateBindingHandle bindingHandle, SamplerStateHandle samplerStateHandle)
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);
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);
389 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
391 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
392 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
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;
402 bg_ent.sampler = sampler.sampler;
403 bg_ent.textureView =
nullptr;
404 bind_group.bindings[decoded_binding].state = BindingState::BindingState_NeedsUpdate;
408 bool BindGroupsWebGPU::setConstantBuffer(BindGroupHandle handle, BindGroupConstantBufferBindingHandle bindingHandle, BufferHandle bufferHandle,
const uint32_t offset,
const uint32_t size)
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);
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);
424 WGPUBindGroupEntry& bg_ent = bind_group.bindings[decoded_binding].entry;
426 bind_group.bindings[decoded_binding].state = BindingState::BindingState_Invalid;
427 bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
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;
449 void Cogs::BindGroupsWebGPU::releaseBindGroup(BindGroupHandle handle)
452 BindGroupWebGPU& target = bind_groups[handle];
454 if (target.bindGroup !=
nullptr) {
455 wgpuBindGroupRelease(target.bindGroup);
456 target.bindGroup =
nullptr;
457 graphicsDevice->counters.bind_group--;
459 if (target.layout !=
nullptr) {
460 wgpuBindGroupLayoutRelease(target.layout);
461 target.layout =
nullptr;
462 graphicsDevice->counters.bind_group_layout--;
464 bind_groups.removeResource(handle);
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;
478 case BindingResourceType::StorageBuffer:
479 layoutEntry.buffer.type = WGPUBufferBindingType_Storage;
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);
488 case BindingResourceType::Sampler:
489 layoutEntry.sampler.type = bindingSamplerTypeToWebGPU(binding.description.samplerBindingType,
490 binding.description.isDepthTexture,
491 binding.description.nameHash);
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);
499 LOG_ERROR(logger,
"Unsupported bind-group resource type %d for entry '%d'.",
500 int(binding.description.resourceType),
501 binding.description.binding);
504 layoutEntries.push_back(layoutEntry);
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);
512 WGPUBindGroup BindGroupsWebGPU::getNativeBindGroup(BindGroupHandle handle) {
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++;
522 if (bind_group.layout ==
nullptr) {
523 LOG_ERROR(logger,
"Failed to create bind group layout.");
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;
536 if (recreateBindGroup) {
543 WGPUBindGroup previous = bind_group.bindGroup;
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);
551 bg_ents[i] = bind_group.bindings[i].entry;
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;
558 WGPUBindGroup created = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bindGroupDesc);
559 if (created ==
nullptr) {
560 LOG_ERROR(logger,
"Failed to create bind group.");
563 if (previous !=
nullptr) {
564 wgpuBindGroupRelease(previous);
565 graphicsDevice->counters.bind_group--;
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;
576 return bind_group.bindGroup;
Log implementation class.
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
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
static const Handle_t NoHandle
Represents a handle to nothing.
handle_type handle
Internal resource handle.