1#include "EffectsWebGPU.h"
3#include "GraphicsDeviceWebGPU.h"
5#include "Foundation/Logging/Logger.h"
15 bool starts_with(std::string::const_iterator begin, std::string::const_iterator end,
const char* s, std::string::const_iterator& next) {
16 std::string::const_iterator it = begin;
18 while (it != end && *s !=
'\0') {
32 void eat_white(std::string::const_iterator& it, std::string::const_iterator end) {
33 while (it != end && std::isspace(*it)) {
38 WGPUTextureViewDimension extractViewDimention(std::string::const_iterator& type_it, std::string::const_iterator end) {
39 WGPUTextureViewDimension tvd = WGPUTextureViewDimension_Undefined;
40 if (starts_with(type_it, end,
"2d_array", type_it)) {
41 tvd = WGPUTextureViewDimension_2DArray;
43 else if (starts_with(type_it, end,
"2d", type_it)) {
44 tvd = WGPUTextureViewDimension_2D;
46 else if (starts_with(type_it, end,
"cube", type_it)) {
47 tvd = WGPUTextureViewDimension_Cube;
49 else if (starts_with(type_it, end,
"1d", type_it)) {
50 tvd = WGPUTextureViewDimension_1D;
52 else if (starts_with(type_it, end,
"cube_array", type_it)) {
53 tvd = WGPUTextureViewDimension_CubeArray;
55 else if (starts_with(type_it, end,
"3d", type_it)) {
56 tvd = WGPUTextureViewDimension_3D;
61 WGPUTextureFormat extractTextureFormat(std::string::const_iterator& type_it, std::string::const_iterator end) {
62 WGPUTextureFormat tf = WGPUTextureFormat_Undefined;
63 if (starts_with(type_it, end,
"rgba8unorm", type_it)) {
64 tf = WGPUTextureFormat_RGBA8Unorm;
66 else if (starts_with(type_it, end,
"rgba8snorm", type_it)) {
67 tf = WGPUTextureFormat_RGBA8Snorm;
69 else if (starts_with(type_it, end,
"rgba8uint", type_it)) {
70 tf = WGPUTextureFormat_RGBA8Uint;
72 else if (starts_with(type_it, end,
"rgba8sint", type_it)) {
73 tf = WGPUTextureFormat_RGBA8Sint;
75 else if (starts_with(type_it, end,
"rgba16uint", type_it)) {
76 tf = WGPUTextureFormat_RGBA16Uint;
78 else if (starts_with(type_it, end,
"rgba16sint", type_it)) {
79 tf = WGPUTextureFormat_RGBA16Sint;
81 else if (starts_with(type_it, end,
"rgba16float", type_it)) {
82 tf = WGPUTextureFormat_RGBA16Float;
84 else if (starts_with(type_it, end,
"r32uint", type_it)) {
85 tf = WGPUTextureFormat_R32Uint;
87 else if (starts_with(type_it, end,
"r32sint", type_it)) {
88 tf = WGPUTextureFormat_R32Sint;
90 else if (starts_with(type_it, end,
"r32float", type_it)) {
91 tf = WGPUTextureFormat_R32Float;
93 else if (starts_with(type_it, end,
"rg32uint", type_it)) {
94 tf = WGPUTextureFormat_RG32Uint;
96 else if (starts_with(type_it, end,
"rg32sint", type_it)) {
97 tf = WGPUTextureFormat_RG32Sint;
99 else if (starts_with(type_it, end,
"rg32float", type_it)) {
100 tf = WGPUTextureFormat_RG32Float;
102 else if (starts_with(type_it, end,
"rgba32uint", type_it)) {
103 tf = WGPUTextureFormat_RGBA32Uint;
105 else if (starts_with(type_it, end,
"rgba32sint", type_it)) {
106 tf = WGPUTextureFormat_RGBA32Sint;
108 else if (starts_with(type_it, end,
"rgba32float", type_it)) {
109 tf = WGPUTextureFormat_RGBA32Float;
111 else if (starts_with(type_it, end,
"bgra8unorm", type_it)) {
112 tf = WGPUTextureFormat_BGRA8Unorm;
117 WGPUStorageTextureAccess extractStorageTextureAccess(std::string::const_iterator& type_it, std::string::const_iterator end) {
118 WGPUStorageTextureAccess sta = WGPUStorageTextureAccess_Undefined;
119 if (starts_with(type_it, end,
"read", type_it)) {
120 sta = WGPUStorageTextureAccess_ReadOnly;
122 else if (starts_with(type_it, end,
"write", type_it)) {
123 sta = WGPUStorageTextureAccess_WriteOnly;
125 else if (starts_with(type_it, end,
"readwrite", type_it)) {
126 sta = WGPUStorageTextureAccess_ReadWrite;
131 std::vector<Cogs::WebGPUConstantBufferBinding> extractConstantBindingLayout(std::string shaderSource, WGPUShaderStage usage) {
132 std::vector<Cogs::WebGPUConstantBufferBinding> result;
133 std::istringstream iss(shaderSource);
134 std::string expr = R
"(^\s*@group\(([0-9]+)\) @binding\(([0-9]+)\)\s+var(<uniform>)?\s+([^\s]+)[\s]*:\s?(.*)\s?;)";
135 std::regex regex_expression(expr);
137 for (std::string line; std::getline(iss, line); )
140 if (std::regex_search(line, match, regex_expression))
142 size_t group = std::stoi(match.str(1));
143 unsigned int loc = std::stoi(match.str(2));
144 bool isUniform = match.str(3) ==
"<uniform>";
145 std::string name = match.str(4);
146 std::string type = match.str(5);
148 std::string::const_iterator type_it = type.begin();
152 bool alreadyInserted =
false;
153 for (
auto& e : result) {
154 if (e.group == group && e.bg_ent.binding == loc) {
155 e.bg_ent.visibility |= usage;
156 alreadyInserted =
true;
160 if (alreadyInserted) {
163 WGPUBindGroupLayoutEntry bg_ent = WGPU_BIND_GROUP_LAYOUT_ENTRY_INIT;
164 bg_ent.binding =
static_cast<uint32_t
>(loc);
165 bg_ent.visibility = (WGPUShaderStage)usage;
168 bg_ent.buffer.type = WGPUBufferBindingType_Uniform;
171 else if (starts_with(type_it, type.end(),
"texture_storage_", type_it)) {
172 bg_ent.storageTexture.viewDimension = extractViewDimention(type_it, type.end());
173 eat_white(type_it, type.end());
174 if (!starts_with(type_it, type.end(),
"<", type_it)) {
175 LOG_DEBUG(logger,
"Texture type %s not yet supported", type.c_str());
177 bg_ent.storageTexture.format = extractTextureFormat(type_it, type.end());
178 eat_white(type_it, type.end());
179 if (!starts_with(type_it, type.end(),
",", type_it)) {
180 LOG_DEBUG(logger,
"Texture type %s not yet supported", type.c_str());
182 eat_white(type_it, type.end());
183 bg_ent.storageTexture.access = extractStorageTextureAccess(type_it, type.end());
184 eat_white(type_it, type.end());
185 if (!starts_with(type_it, type.end(),
">", type_it)) {
186 LOG_DEBUG(logger,
"Texture type %s not yet supported", type.c_str());
189 else if (starts_with(type_it, type.end(),
"texture_", type_it)) {
190 bool isDepth =
false;
193 bg_ent.texture.sampleType = WGPUTextureSampleType_Float;
194 bg_ent.texture.viewDimension = WGPUTextureViewDimension_2D;
195 bg_ent.texture.multisampled = 0;
196 if (starts_with(type_it, type.end(),
"depth_", type_it)) {
199 if (starts_with(type_it, type.end(),
"multisampled_", type_it)) {
200 bg_ent.texture.multisampled = 1;
203 bg_ent.texture.viewDimension = extractViewDimention(type_it, type.end());
204 eat_white(type_it, type.end());
206 bg_ent.texture.sampleType = WGPUTextureSampleType_Depth;
207 }
else if (starts_with(type_it, type.end(),
"<f32>", type_it)) {
209 bg_ent.texture.sampleType = WGPUTextureSampleType_UnfilterableFloat;
211 bg_ent.texture.sampleType = WGPUTextureSampleType_Float;
214 else if (starts_with(type_it, type.end(),
"<i32>", type_it)) {
215 bg_ent.texture.sampleType = WGPUTextureSampleType_Sint;
217 else if (starts_with(type_it, type.end(),
"<u32>", type_it)) {
218 bg_ent.texture.sampleType = WGPUTextureSampleType_Uint;
221 LOG_DEBUG(logger,
"Texture type %s not yet supported", type.c_str());
224 else if (type ==
"sampler") {
226 bg_ent.sampler.type = WGPUSamplerBindingType_Filtering;
228 else if (type ==
"sampler_comparison") {
230 bg_ent.sampler.type = WGPUSamplerBindingType_Comparison;
233 LOG_DEBUG(logger,
"Unknown uniform type%s", type.c_str());
237 result.push_back(binding);
243 const char* semanticNames[]
255 WGPUVertexFormat format =
static_cast<WGPUVertexFormat
>(0);
258 case Cogs::hash(
"f32"): format = WGPUVertexFormat::WGPUVertexFormat_Float32;
break;
259 case Cogs::hash(
"vec2f"): format = WGPUVertexFormat::WGPUVertexFormat_Float32x2;
break;
260 case Cogs::hash(
"vec3f"): format = WGPUVertexFormat::WGPUVertexFormat_Float32x3;
break;
261 case Cogs::hash(
"vec4f"): format = WGPUVertexFormat::WGPUVertexFormat_Float32x4;
break;
262 case Cogs::hash(
"i32"): format = WGPUVertexFormat::WGPUVertexFormat_Sint32;
break;
263 case Cogs::hash(
"vec2i"): format = WGPUVertexFormat::WGPUVertexFormat_Sint32x2;
break;
264 case Cogs::hash(
"vec3i"): format = WGPUVertexFormat::WGPUVertexFormat_Sint32x3;
break;
265 case Cogs::hash(
"vec4i"): format = WGPUVertexFormat::WGPUVertexFormat_Sint32x4;
break;
266 case Cogs::hash(
"u32"): format = WGPUVertexFormat::WGPUVertexFormat_Uint32;
break;
267 case Cogs::hash(
"vec2u"): format = WGPUVertexFormat::WGPUVertexFormat_Uint32x2;
break;
268 case Cogs::hash(
"vec3u"): format = WGPUVertexFormat::WGPUVertexFormat_Uint32x3;
break;
269 case Cogs::hash(
"vec4u"): format = WGPUVertexFormat::WGPUVertexFormat_Uint32x4;
break;
271 LOG_ERROR(logger,
"Unsupported vertex attribute type %s", std::string(s).c_str());
305 std::istringstream iss(shaderSource);
306 std::string expr = R
"(\s*const ([^\s^0-9]+)([0-9]+)_LOC\s*=\s*([0-9]+))";
307 std::regex regex_expression(expr);
309 for (std::string line; std::getline(iss, line); )
312 if (std::regex_search(line, match, regex_expression))
314 std::string semanticName = match.str(1);
315 uint8_t slot =
static_cast<uint8_t
>(std::stoi(match.str(2)));
316 uint8_t loc =
static_cast<uint8_t
>(std::stoi(match.str(3)));
317 for (uint8_t i = 0; i < std::size(semanticNames); i++) {
318 if (strcmp(semanticName.c_str(), semanticNames[i]) == 0) {
330 iss.seekg(0, std::ios::beg);
331 std::string expr_location = R
"(@location\(\s*([^\s\)\d]+)([\d]+)_LOC\s*\)\s*([^\s:]+)\s*:\s*([\da-zA-Z]+)[,\s\n])";
332 std::regex regex_location(expr_location);
333 for (std::string line; std::getline(iss, line); )
336 if (std::regex_search(line, match, regex_location))
338 std::string semanticName = match.str(1);
339 uint8_t slot =
static_cast<uint8_t
>(std::stoi(match.str(2)));
340 std::string name = match.str(3);
341 std::string type = match.str(4);
342 uint8_t semantic = std::numeric_limits<uint8_t>::max();
343 for (uint8_t i = 0; i < std::size(semanticNames); i++) {
344 if (strcmp(semanticName.c_str(), semanticNames[i]) == 0) {
349 if (semantic == std::numeric_limits<uint8_t>::max()) {
350 LOG_DEBUG(logger,
"unknown semantic name for vertex attribute %s", semanticName.c_str());
353 for (
size_t i = 0; i < nAttribs; i++) {
354 if (bindings[i].semantic == semantic && bindings[i].slot == slot) {
366 size_t i = (binding.group << 16) + (binding.bg_ent.binding + 1 );
370 void dumpSource(
const std::string& source,
int firstLine = 1,
int lastLine = std::numeric_limits<int>::max())
372 const char* start = source.data();
373 const char* curr = start;
376 while ((*curr !=
'\0') && (line <= lastLine)) {
377 const char* p = curr;
378 while ((*p !=
'\0') && (*p !=
'\n') && (*p !=
'\r')) { p++; }
380 if (firstLine <= line) {
381 LOG_DEBUG(logger,
"%3d: %s", line, std::string(curr, p - curr).c_str());
387 if (*curr !=
'\0') { curr++; };
388 if ((*curr !=
'\0') && (*curr != *p) && ((*curr ==
'\n') || (*curr ==
'\r'))) { curr++; }
392 void printShaderError(
struct WGPUCompilationInfo
const* compilationInfo,
const std::string* source =
nullptr)
394 for (
size_t i = 0; i < compilationInfo->messageCount; i++) {
395 const WGPUCompilationMessage& message = compilationInfo->messages[i];
397 dumpSource(*source, ((
int)message.lineNum) - 3, ((
int)message.lineNum));
400 std::string category_str;
401 switch (message.type) {
402 case WGPUCompilationMessageType::WGPUCompilationMessageType_Info:
403 category = Cogs::Logging::Category::Info;
404 category_str =
"Info";
406 case WGPUCompilationMessageType::WGPUCompilationMessageType_Error:
407 category = Cogs::Logging::Category::Error;
408 category_str =
"Error";
410 case WGPUCompilationMessageType::WGPUCompilationMessageType_Force32:
411 category = Cogs::Logging::Category::Error;
412 category_str =
"Force32";
415 category = Cogs::Logging::Category::Error;
416 category_str =
"Unknown";
423 void compile_callback(WGPUCompilationInfoRequestStatus status,
struct WGPUCompilationInfo
const* compilationInfo,
void* userdata1,
void* )
425 const std::string* source =
reinterpret_cast<std::string*
>(userdata1);
426 if (status != WGPUCompilationInfoRequestStatus_Success || (compilationInfo !=
nullptr && compilationInfo->messageCount != 0))
428 if(status == WGPUCompilationInfoRequestStatus_CallbackCancelled){
429 LOG_INFO(logger,
"WGPUCompilationInfoRequestStatus_CallbackCancelled");
432 printShaderError(compilationInfo, source);
439 void EffectsWebGPU::initialize(GraphicsDeviceWebGPU *device_in, IBuffers * buffers_in)
441 EffectsCommon::initialize(buffers_in);
442 graphicsDevice = device_in;
451 if (!HandleIsValid(handle))
return;
454 wgpuShaderModuleRelease(effect.vs_module);
455 counters.shader_module--;
456 wgpuShaderModuleRelease(effect.fs_module);
457 counters.shader_module--;
458 this->effects.removeResource(handle);
469 WGPUDevice device = graphicsDevice->device;
473 Utilities::readFile(handler, fileName, csSource);
476 effect.cs_entry =
"main";
477 effect.name = std::string(fileName);
479 std::string cs_source;
480 for(
auto &def : definitions){
481 cs_source +=
"const " + def.first +
" = " + def.second +
";\n";
483 cs_source += csSource.content;
486 LOG_INFO(logger,
"Compiling WebGPU CS:\n%s", cs_source.c_str());
489 WGPUShaderModuleDescriptor descriptor = WGPU_SHADER_MODULE_DESCRIPTOR_INIT;
490 descriptor.label = {fileName.data(), WGPU_STRLEN};
491 WGPUShaderSourceWGSL wgsl_desc = WGPU_SHADER_SOURCE_WGSL_INIT;
492 wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
493 wgsl_desc.code = {cs_source.c_str(), WGPU_STRLEN};
494 descriptor.nextInChain = (WGPUChainedStruct*)&wgsl_desc;
496 effect.cs_module = wgpuDeviceCreateShaderModule(device, &descriptor);
497 counters.shader_module++;
499 std::vector<Cogs::WebGPUConstantBufferBinding> bindings = extractConstantBindingLayout(cs_source, WGPUShaderStage_Compute);
500 addConstantBufferBindings(effect, bindings);
502 WGPUCompilationInfoCallbackInfo callbackInfo = WGPU_COMPILATION_INFO_CALLBACK_INFO_INIT;
503 callbackInfo.nextInChain =
nullptr;
504 callbackInfo.callback = compile_callback;
505 callbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
506 callbackInfo.userdata1 =
static_cast<void*
>(&cs_source);
508 wgpuShaderModuleGetCompilationInfo(effect.cs_module, callbackInfo);
510 return this->effects.addResource(std::move(effect));
526 bool useSortedDefines =
false;
528 std::sort(unique_definitions.begin(), unique_definitions.end());
529 unique_definitions.erase(std::unique(unique_definitions.begin(), unique_definitions.end()), unique_definitions.end());
530 if (unique_definitions.size() != effect_desc.
definitions.size()) {
531 useSortedDefines =
true;
532 LOG_WARNING(logger,
"Redefinition of precompiler defines not supported in WebGPU backend");
536 assert(!hsSource.origin.size());
537 assert(!dsSource.origin.size());
538 assert(!gsSource.origin.size());
540 WGPUDevice device = graphicsDevice->device;
541 ResourceCountersWebGPU &counters = graphicsDevice->counters;
543 EffectWebGPU effect = {};
544 effect.vs_entry = std::string(vsEntryPoint);
545 effect.fs_entry = std::string(fsEntryPoint);
546 effect.name = std::string(effect_desc.
name);
548 LOG_INFO(logger,
"Compiling WebGPU Effect: %s", effect.name.c_str());
550 std::string definitions_source;
551 for (
auto& def : useSortedDefines ? unique_definitions : effect_desc.
definitions) {
552 definitions_source +=
"const " + def.first +
" = " + def.second +
";\n";
554 std::string vs_source = definitions_source + vsSource.content;
557 LOG_INFO(logger,
"Compiling WebGPU VS:\n%s", vs_source.c_str());
560 WGPUShaderModuleDescriptor descriptor = WGPU_SHADER_MODULE_DESCRIPTOR_INIT;
561 descriptor.label = {effect_desc.
name.
data(), WGPU_STRLEN};
562 WGPUShaderSourceWGSL wgsl_desc = WGPU_SHADER_SOURCE_WGSL_INIT;
563 wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
564 wgsl_desc.code = {vs_source.c_str(), WGPU_STRLEN};
565 descriptor.nextInChain = (WGPUChainedStruct*)&wgsl_desc;
567 effect.vs_module = wgpuDeviceCreateShaderModule(device, &descriptor);
568 counters.shader_module++;
570 WGPUCompilationInfoCallbackInfo callbackInfo = WGPU_COMPILATION_INFO_CALLBACK_INFO_INIT;
571 callbackInfo.nextInChain =
nullptr;
572 callbackInfo.callback = compile_callback;
573 callbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
574 callbackInfo.userdata1 =
static_cast<void*
>(& vs_source);
575 wgpuShaderModuleGetCompilationInfo(effect.vs_module, callbackInfo);
578 std::vector<Cogs::WebGPUConstantBufferBinding> bindings = extractConstantBindingLayout(vs_source, WGPUShaderStage_Vertex);
579 addConstantBufferBindings(effect, bindings);
581 effect.num_attribs = extractVertexAttribLocation(vs_source, effect.semanticSlotBindings, effect.maxVertexAttribs);
585 if (fsSource.content.size()) {
586 std::string fs_source;
587 fs_source = definitions_source + fsSource.content;
590 LOG_INFO(logger,
"Compiling WebGPU FS:\n%s", fs_source.c_str());
593 WGPUShaderModuleDescriptor descriptor = WGPU_SHADER_MODULE_DESCRIPTOR_INIT;
594 descriptor.label = {effect_desc.
name.
data(), WGPU_STRLEN};
595 WGPUShaderSourceWGSL wgsl_desc = WGPU_SHADER_SOURCE_WGSL_INIT;
596 wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
597 wgsl_desc.code = {fs_source.c_str(), WGPU_STRLEN};
598 descriptor.nextInChain = (WGPUChainedStruct*)&wgsl_desc;
600 effect.fs_module = wgpuDeviceCreateShaderModule(device, &descriptor);
601 counters.shader_module++;
603 WGPUCompilationInfoCallbackInfo callbackInfo = WGPU_COMPILATION_INFO_CALLBACK_INFO_INIT;
604 callbackInfo.nextInChain =
nullptr;
605 callbackInfo.callback = compile_callback;
606 callbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
607 callbackInfo.userdata1 =
static_cast<void*
>(& fs_source);
608 wgpuShaderModuleGetCompilationInfo(effect.fs_module, callbackInfo);
611 std::vector<Cogs::WebGPUConstantBufferBinding> bindings = extractConstantBindingLayout(fs_source, WGPUShaderStage_Fragment);
612 addConstantBufferBindings(effect, bindings);
614 return this->effects.addResource(std::move(effect));
621 for (
size_t i = 0; i < effect.num_bindings; i++) {
622 if (effect.constantBufferBindings[i].nameHash == nameHash) {
623 return encodeConstantBufferBindingHandle(effect.constantBufferBindings[i]);
633 if (HandleIsValid(constantBuffer)) {
639 bool EffectsWebGPU::addConstantBufferBindings(
EffectWebGPU& effect,
const std::vector<Cogs::WebGPUConstantBufferBinding>& bindings) {
640 for (
auto binding : bindings) {
643 for (slot = 0; slot < effect.num_bindings; slot++) {
644 auto& curr = effect.constantBufferBindings[slot];
645 if (curr.nameHash == binding.nameHash) {
646 if (curr.group == binding.group && curr.bg_ent.binding == binding.bg_ent.binding) {
647 curr.bg_ent.visibility = curr.bg_ent.visibility | binding.bg_ent.visibility;
651 LOG_ERROR(logger,
"Inconsistent binding location");
658 if (effect.num_bindings < EffectWebGPU::maxConstantBuffers) {
659 effect.constantBufferBindings[effect.num_bindings++] = binding;
662 LOG_ERROR(logger,
"Number of bindings exceed EffectWebGPU::maxConstantBuffers=%zu", EffectWebGPU::maxConstantBuffers);
670 const WebGPUConstantBufferBinding* EffectsWebGPU::getConstantBufferBindings(EffectHandle effectHandle,
size_t& num_bindings) {
671 const EffectWebGPU& effect = effects[effectHandle];
672 num_bindings = effect.num_bindings;
673 return effect.constantBufferBindings;
677 std::string constantBufferName = std::string(name);
679 if (HandleIsValid(constantBuffer)) {
686 std::string constantBufferName = std::string(name);
687 if (!constantBufferName.ends_with(
"Sampler")) {
688 constantBufferName +=
"Sampler";
692 if (HandleIsValid(constantBuffer)) {
696 if (constantBufferName.ends_with(
"TextureSampler")) {
697 constantBufferName.erase(constantBufferName.length() - strlen(
"TextureSampler"));
TextureBindingHandle getTextureBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot) override
Get a handle to a texture object binding, mapping how to bind textures to the given effect.
virtual void releaseEffect(EffectHandle effectHandle) override
Release the effect with the given handle, freeing all resources generated during program loading.
BufferBindingHandle getBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a buffer binding.
virtual EffectHandle loadComputeEffect(const StringView &, EffectFlags::EEffectFlags) override
Load the compute shader with the given file name and create an effect.
ConstantBufferBindingHandle getConstantBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a constant buffer binding, mapping how to bind a constant buffer to the given effect.
virtual void releaseResources() override
Release all allocated effect resources.
SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &, const unsigned int slot) override
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
Log implementation class.
void log(const Category category, uint32_t errorNumber, _Printf_format_string_ const char *fmt,...) const VALIDATE_ARGS(4)
Log a formatted message.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ Unspecified
The default error number for legacy logger usage.
Category
Logging categories used to filter log messages.
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
std::vector< PreprocessorDefinition > PreprocessorDefinitions
A set of preprocessor definitions.
Contains an effect description used to load a single effect.
EffectFlags::EEffectFlags flags
Effect loading flags.
PreprocessorDefinitions definitions
Definitions.
StringView name
Name of the effect. Used for tracking purposes, like naming shader dumps.
EEffectFlags
Effect source flags.
@ LogShaderSource
Log the contents of the shader on error.
static const Handle_t NoHandle
Represents a handle to nothing.
handle_type handle
Internal resource handle.