1#include "ShaderBuilder.h"
2#include "ShaderBuilderHelpersWebGPU.h"
4#include "Utilities/Strings.h"
5#include "Utilities/Preprocessor.h"
6#include "ResourceStore.h"
7#include "Renderer/EnginePermutations.h"
8#include "Rendering/IGraphicsDevice.h"
10#include "Foundation/Logging/Logger.h"
20 constexpr size_t InitialBufferCapasity = 4096u;
22 constexpr std::array semanticNames
34 std::string_view getSemanticName(
size_t semantic_ind) {
35 std::string_view name;
36 if (semantic_ind < semanticNames.size()) {
37 name = semanticNames[semantic_ind];
46 using Cogs::BindingResourceType;
47 using Cogs::ResourceDimensions;
50 enum ShaderInterface { None = 0, VertexIn = 1, VertexOut = 2, FragmentIn = 4, FragmentOut = 8 };
53 struct BuiltinAttributeDescription {
54 std::string builtinName;
56 ShaderInterface stage = ShaderInterface::None;
59 struct BuiltinAttributes {
60 ShaderInterfaceMemberDefinition::SemanticName semanticName;
61 BuiltinAttributeDescription desc;
64 const std::array<BuiltinAttributes, 5> builtinAttributes{
65 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
66 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID, {
"vertex_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
67 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
68 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
69 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
72 struct BuiltinDataType {
74 BuiltinAttributeDescription desc;
77 const std::array builtinDataTypes {
78 BuiltinDataType{MaterialDataType::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn} },
79 BuiltinDataType{MaterialDataType::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
80 BuiltinDataType{MaterialDataType::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn} },
81 BuiltinDataType{MaterialDataType::VFACE, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
88 if (layoutSet.numGroups <= groupIndex) {
89 layoutSet.numGroups = groupIndex + 1;
91 return layoutSet.groups[groupIndex];
97 for (uint16_t i = 0; i < group.numEntries; ++i) {
98 if (group.entries[i].nameHash == nameHash) {
99 return &group.entries[i];
114 size_t nextBinding = 0;
115 for (uint16_t i = 0; i < group.numEntries; ++i) {
116 nextBinding = std::max(nextBinding,
size_t(group.entries[i].binding) + 1);
125 if (group.numEntries >= Cogs::MaxBindGroupEntries) {
126 LOG_ERROR(logger,
"Bind group is full (%d entries), dropping binding %s",
int(Cogs::MaxBindGroupEntries), std::string(name).c_str());
129 const uint32_t binding =
static_cast<uint32_t
>(nextBindingIndex(group));
132 entry.binding = binding;
140 switch (dimensions) {
141 case Cogs::Core::TextureDimensions::Texture2D:
return ResourceDimensions::Texture2D;
142 case Cogs::Core::TextureDimensions::Texture2DArray:
return ResourceDimensions::Texture2DArray;
143 case Cogs::Core::TextureDimensions::Texture3D:
return ResourceDimensions::Texture3D;
144 case Cogs::Core::TextureDimensions::TexureCube:
return ResourceDimensions::TextureCube;
145 default:
return ResourceDimensions::Unknown;
152 std::string convertDefinesToConstExpressions(
const std::string& s) {
153 std::map<std::string, std::string> addedDefines;
155 result.reserve(s.size());
157 std::istringstream iss(s);
159 std::string identifier;
160 std::string replacement;
161 for (std::string line; std::getline(iss, line); )
166 std::string_view sv(line);
167 auto pos = sv.find_first_not_of(
" \t");
168 if (pos == std::string_view::npos || sv.substr(pos, 7) !=
"#define") {
169 result += line +
"\n";
172 sv = sv.substr(pos + 7);
174 pos = sv.find_first_not_of(
" \t");
175 if (pos == std::string_view::npos) {
176 result += line +
"\n";
181 auto end = sv.find_first_of(
" \t");
182 if (end == std::string_view::npos) {
186 identifier = sv.substr(0, end);
188 pos = sv.find_first_not_of(
" \t");
189 if (pos == std::string_view::npos) {
192 auto last = sv.find_last_not_of(
" \t");
193 replacement = sv.substr(pos, last - pos + 1);
197 auto it = addedDefines.find(identifier);
198 if (it != addedDefines.end()) {
199 if (replacement != (*it).second) {
200 LOG_WARNING(logger,
"Shader generation with inconsistent preprosessor define %s set to %s conflicts with previous define %s.", identifier.c_str(), replacement.c_str(), (*it).second.c_str());
204 result +=
"const " + identifier +
" = " + replacement +
";\n";
205 addedDefines.try_emplace(identifier, replacement);
210 void addInclude(std::string& content, std::string_view prefix, std::string_view path)
212 content.append(
"#include \"");
213 content.append(prefix);
214 content.append(path);
215 content.append(
"\"\n");
218 void changeSuffix(std::string& dst, std::string_view from, std::string_view to)
220 if (dst.ends_with(from)) {
221 dst.replace(dst.size() - from.length(), from.length(), to);
229 case MaterialDataType::Float:
return "f32 ";
break;
230 case MaterialDataType::Float2:
return "vec2f ";
break;
231 case MaterialDataType::Float3:
return "vec3f ";
break;
232 case MaterialDataType::Float4:
return "vec4f ";
break;
233 case MaterialDataType::Float4x4:
return "mat4x4f ";
break;
234 case MaterialDataType::Int:
return "i32 ";
break;
235 case MaterialDataType::Int2:
return "vec4i ";
break;
236 case MaterialDataType::Int3:
return "vec3i ";
break;
237 case MaterialDataType::Int4:
return "vec4i ";
break;
238 case MaterialDataType::UInt:
return "u32 ";
break;
239 case MaterialDataType::UInt2:
return "vec4u ";
break;
240 case MaterialDataType::UInt3:
return "vec3u ";
break;
241 case MaterialDataType::UInt4:
return "vec4u ";
break;
242 case MaterialDataType::Bool:
return "bool ";
break;
243 case MaterialDataType::SV_IsFrontFace:
return "bool ";
break;
244 case MaterialDataType::VFACE:
return "f32 ";
break;
245 case MaterialDataType::Position:
return "vec4f ";
break;
247 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
253 void addEffectDefinesAndStuff(std::string& output,
const std::vector<std::pair<std::string, std::string>>& definitions, uint32_t multiViewCount) {
254 if (multiViewCount) {
255 std::string multiViewCountString = std::to_string(multiViewCount);
256 output.append(
"#extension GL_OVR_multiview : require\nlayout(num_views=");
257 output.append(multiViewCountString);
258 output.append(
") in;\n");
259 output.append(
"#define COGS_MULTIVIEW ");
260 output.append(multiViewCountString);
264 std::unordered_set<std::string> addedDefines;
266 for (
const std::pair<std::string, std::string>& define : definitions) {
267 if (addedDefines.contains(define.first)) {
270 output.append(
"#define ");
271 output.append(define.first);
273 output.append(define.second);
275 addedDefines.insert(define.first);
281 BuiltinAttributeDescription desc;
282 desc.stage = ShaderInterface::None;
283 for (
const auto& builtin : builtinDataTypes)
285 if (builtin.type == attribute.type) {
289 for (
const auto& attr : builtinAttributes) {
290 if (attr.semanticName == attribute.semantic.name) {
297 void addInterfaceStruct(std::string& defines, std::string& source, std::string_view name,
const ShaderInterfaceDefinition& iface, ShaderInterface shaderInterface)
300 source.append(
"struct ");
302 source.append(
" {\n");
304 if (shaderInterface & ShaderInterface::VertexOut) {
305 source.append(
" @builtin(position) Position: vec4f,\n");
307 for (
const auto& attribute : iface.members) {
308 BuiltinAttributeDescription builtinAttributeDescription = getBuiltinAttributeDescription(attribute);
309 if (shaderInterface & ShaderInterface::VertexOut &&
310 (builtinAttributeDescription.stage & ShaderInterface::FragmentIn) != 0) {
313 if (shaderInterface & ShaderInterface::FragmentIn && attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::None && attribute.type == MaterialDataType::Position) {
317 if ((builtinAttributeDescription.stage & shaderInterface) != 0) {
318 source.append(
" @builtin(" + builtinAttributeDescription.builtinName +
") ");
319 source.append(attribute.name);
320 source.append(
" : ");
321 source.append(attributeVaryingType(builtinAttributeDescription.type));
322 source.append(
",\n");
325 if (shaderInterface & ShaderInterface::VertexIn) {
326 size_t nameInd = size_t (attribute.semantic.name) - 1;
327 std::string_view semanticName = getSemanticName(nameInd);
328 if (!semanticName.empty()) {
329 if(attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::InstanceMatrix){
330 std::string defineName;
331 defineName.append(semanticName);
332 int loc = attribute.semantic.slot;
333 defineName.append(std::to_string(loc) +
"_LOC");
334 defines.append(
"#define ");
335 defines.append(defineName +
" " + std::to_string(next_loc) +
"\n");
337 for(
int i=0; i<4; i++){
338 source.append(
" @location(" + defineName +
" + " + std::to_string(i) +
") ");
339 source.append(attribute.name +
"_" + std::to_string(i));
340 source.append(
" : vec4f,\n");
345 std::string defineName;
346 defineName.append(semanticName);
347 defineName.append(std::to_string(attribute.semantic.slot) +
"_LOC");
348 defines.append(
"#define ");
349 defines.append(defineName +
" " + std::to_string(next_loc++) +
"\n");
350 source.append(
" @location(" + defineName +
") ");
351 source.append(attribute.name);
352 source.append(
" : ");
353 source.append(attributeVaryingType(attribute.type));
354 source.append(
",\n");
359 if (attribute.modifiers & ShaderInterfaceMemberDefinition::NointerpolationModifier) {
360 source.append(
" @interpolate(flat)");
362 source.append(
" @location(" + std::to_string(next_loc++) +
") ");
363 source.append(attribute.name);
364 source.append(
" : ");
365 source.append(attributeVaryingType(attribute.type));
366 source.append(
",\n");
370 source.append(
"};\n\n");
375 shaderSource.append(
"fn create");
376 shaderSource.append(name);
377 shaderSource.append(
"() -> ");
378 shaderSource.append(name);
379 shaderSource.append(
" {\n");
380 shaderSource.append(
" var t : ");
381 shaderSource.append(name);
382 shaderSource.append(
";\n");
383 for (
const auto& attribute : iface.members) {
384 const char* initializer =
nullptr;
385 switch (attribute.type) {
386 case MaterialDataType::Float: initializer =
"0.0;\n";
break;
387 case MaterialDataType::Float2: initializer =
"vec2f(0);\n";
break;
388 case MaterialDataType::Float3: initializer =
"vec3f(0);\n";
break;
389 case MaterialDataType::Float4: initializer =
"vec4f(0);\n";
break;
390 case MaterialDataType::Float4x4: initializer =
"mat4x4f(0);\n";
break;
395 shaderSource.append(
" t.");
396 shaderSource.append(attribute.name);
397 shaderSource.append(
" = ");
398 shaderSource.append(initializer);
401 shaderSource.append(
" return t;\n}\n\n");
404 void addUniform(std::string& shaderSource,
408 std::string_view name,
409 std::string_view type,
410 bool useTemplate =
false,
411 BindingResourceType resourceType = BindingResourceType::UniformBuffer,
412 ResourceDimensions textureDimension = ResourceDimensions::Unknown,
413 bool isDepthTexture =
false) {
417 entry = claimEntry(bindings, name);
419 entry->resourceType = resourceType;
420 entry->textureDimension = textureDimension;
421 entry->isDepthTexture = isDepthTexture;
424 entry->visibility |= visibility;
426 shaderSource.append(
"@group(");
427 shaderSource.append(std::to_string(group));
428 shaderSource.append(
") @binding(");
429 shaderSource.append(std::to_string(entry->binding));
430 shaderSource.append(
") var");
432 shaderSource.append(
"<uniform>");
434 shaderSource.append(
" ");
435 shaderSource.append(name);
436 shaderSource.append(
" : ");
437 shaderSource.append(type);
438 shaderSource.append(
";\n");
443 if (!identifiersSeen.contains(Strings::add(definition.name))) {
446 if (definition.values.empty())
return;
447 shaderSource.append(
"struct ");
448 shaderSource.append(definition.name);
449 shaderSource.append(
"_t {\n");
451 shaderSource.append(member.name);
452 shaderSource.append(
" : ");
454 switch (member.type) {
455 case MaterialDataType::Float: shaderSource.append(
"f32");
break;
456 case MaterialDataType::Float2: shaderSource.append(
"vec2f");
break;
457 case MaterialDataType::Float3: shaderSource.append(
"vec3f");
break;
458 case MaterialDataType::Float4Array:
459 shaderSource.append(
"array<vec4f, " + std::to_string(member.dimension) +
">");
460 assert(member.dimension !=
static_cast<size_t>(-1));
462 case MaterialDataType::Float4: shaderSource.append(
"vec4f");
break;
463 case MaterialDataType::Float4x4Array:
464 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f");
break;
465 case MaterialDataType::Int: shaderSource.append(
"i32");
break;
466 case MaterialDataType::Int2: shaderSource.append(
"vec2i");
break;
467 case MaterialDataType::Int3: shaderSource.append(
"vec3i");
break;
468 case MaterialDataType::Int4: shaderSource.append(
"vec4i");
break;
469 case MaterialDataType::UInt: shaderSource.append(
"u32");
break;
470 case MaterialDataType::UInt2: shaderSource.append(
"vec2u");
break;
471 case MaterialDataType::UInt3: shaderSource.append(
"vec3u");
break;
472 case MaterialDataType::UInt4: shaderSource.append(
"vec4u");
break;
473 case MaterialDataType::Bool: shaderSource.append(
"u32");
break;
475 LOG_ERROR(logger,
"Invalid type for buffer varable %s in buffer %s.", member.name.c_str(), definition.name.c_str());
476 shaderSource.append(
"<invalid type>");
479 shaderSource.append(
",\n");
481 shaderSource.append(
"};\n");
483 addUniform(shaderSource, layoutSet, group, visibility, definition.name, definition.name +
"_t",
true);
488 shaderSource.append(
"fn transferAttributes(vertexIn : VertexIn, vertexOut : ptr<function, VertexOut>) {\n");
490 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
492 if (dMember.name == member.name) {
493 shaderSource.append(
" (*vertexOut).");
494 shaderSource.append(member.name);
495 shaderSource.append(
" = ");
496 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
497 shaderSource.append(
"octDecode(vertexIn.");
498 shaderSource.append(member.name);
499 shaderSource.append(
"); \n");
502 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
503 shaderSource.append(
"vec4f(vertexIn.");
504 shaderSource.append(member.name);
505 shaderSource.append(
", 1.0);\n");
508 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
509 shaderSource.append(
"vec4f(vertexIn.");
510 shaderSource.append(member.name);
511 shaderSource.append(
", 0.0, 1.0);\n");
515 if (dMember.type != member.type) {
516 switch (dMember.type) {
517 case MaterialDataType::Float: shaderSource.append(
"f32("); close =
true;
break;
518 case MaterialDataType::Float2: shaderSource.append(
"vec2f("); close =
true;
break;
519 case MaterialDataType::Float3: shaderSource.append(
"vec3f("); close =
true;
break;
520 case MaterialDataType::Float4: shaderSource.append(
"vec4f("); close =
true;
break;
521 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f("); close =
true;
break;
522 case MaterialDataType::Int: shaderSource.append(
"i32("); close =
true;
break;
523 case MaterialDataType::Int2: shaderSource.append(
"vec2i("); close =
true;
break;
524 case MaterialDataType::Int3: shaderSource.append(
"vec3i("); close =
true;
break;
525 case MaterialDataType::Int4: shaderSource.append(
"vec4i("); close =
true;
break;
526 case MaterialDataType::UInt: shaderSource.append(
"u32("); close =
true;
break;
527 case MaterialDataType::UInt2: shaderSource.append(
"vec2u("); close =
true;
break;
528 case MaterialDataType::UInt3: shaderSource.append(
"vec3u("); close =
true;
break;
529 case MaterialDataType::UInt4: shaderSource.append(
"vec4u("); close =
true;
break;
534 if (dMember.type == member.type) {
535 shaderSource.append(
"vertexIn.");
536 shaderSource.append(member.name);
539 LOG_WARNING(logger,
"%s Skip transfer of %s. (Different types).", sourceDefinition.loadPath.c_str(), member.name.c_str());
541 if (close) shaderSource.append(1,
')');
542 shaderSource.append(
";\n");
547 shaderSource.append(
"}\n");
550 bool addOutputStruct(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly) {
551 bool outputDepth =
false;
552 bool hasColorAttachments = !outputDefinition.empty() && !depthOnly;
554 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
555 auto it = std::find_if(definitions.begin(), definitions.end(),
556 [&targetString](
const std::pair<std::string, std::string>& p){
557 return p.first == targetString;
560 if (it != definitions.end()) {
561 outputDepth = it->second !=
"0";
564 if (!outputDepth && !hasColorAttachments) {
568 source.append(
"struct FragmentOut {\n");
570 if (hasColorAttachments) {
571 for (
auto member : outputDefinition) {
572 source.append(
" @location(");
573 source.append(std::to_string(member.target));
575 source.append(member.name +
" : ");
577 switch (member.dataType) {
578 case MaterialDataType::Float: source.append(
"f32");
break;
579 case MaterialDataType::Float2: source.append(
"vec2f");
break;
580 case MaterialDataType::Float3: source.append(
"vec3f");
break;
581 case MaterialDataType::Float4: source.append(
"vec4f");
break;
582 case MaterialDataType::Float4x4: source.append(
"mat4x4f");
break;
583 case MaterialDataType::Int: source.append(
"i32");
break;
584 case MaterialDataType::Int2: source.append(
"vec2i");
break;
585 case MaterialDataType::Int3: source.append(
"vec3i");
break;
586 case MaterialDataType::Int4: source.append(
"vec4i");
break;
587 case MaterialDataType::UInt: source.append(
"u32");
break;
588 case MaterialDataType::UInt2: source.append(
"vec2u");
break;
589 case MaterialDataType::UInt3: source.append(
"vec3u");
break;
590 case MaterialDataType::UInt4: source.append(
"vec4u");
break;
594 source.append(
",\n");
598 source.append(
"@builtin(frag_depth) depth : f32\n");
600 source.append(
"};\n");
605 void addCallFunction(std::string& source, std::string_view name, std::string_view functionName, std::string_view inType, std::string_view outType) {
606 source.append(
"fn ");
608 source.append(
"(In : ");
609 source.append(inType);
610 source.append(
") ->");
611 source.append(outType);
612 source.append(
" { \n");
613 source.append(
" return ");
614 source.append(functionName);
615 source.append(
"(In);\n");
616 source.append(
"}\n\n");
623 case MaterialDataType::Unknown:
624 case MaterialDataType::Float:;
625 case MaterialDataType::Float2:
626 case MaterialDataType::Float3:
627 case MaterialDataType::Float4:
629 case MaterialDataType::Int:
630 case MaterialDataType::Int2:
631 case MaterialDataType::Int3:
632 case MaterialDataType::Int4:
634 case MaterialDataType::UInt:
635 case MaterialDataType::UInt2:
636 case MaterialDataType::UInt3:
637 case MaterialDataType::UInt4:
640 LOG_ERROR(logger,
"Unsupported texture datatype %d",
int(type));
647 Cogs::BindingTextureSampleType deduceTextureSampleType(
const MaterialDataType type,
const bool isDepthTexture,
const bool multisampled)
649 if (isDepthTexture) {
650 return Cogs::BindingTextureSampleType::Depth;
654 case MaterialDataType::Int:
655 case MaterialDataType::Int2:
656 case MaterialDataType::Int3:
657 case MaterialDataType::Int4:
658 return Cogs::BindingTextureSampleType::Sint;
659 case MaterialDataType::UInt:
660 case MaterialDataType::UInt2:
661 case MaterialDataType::UInt3:
662 case MaterialDataType::UInt4:
663 return Cogs::BindingTextureSampleType::Uint;
666 ? Cogs::BindingTextureSampleType::UnfilterableFloat
667 : Cogs::BindingTextureSampleType::Float;
672 Cogs::BindingSamplerBindingType deduceSamplerBindingType(
const MaterialDataType type,
const bool isDepthTexture,
const bool multisampled)
674 if (isDepthTexture) {
675 return Cogs::BindingSamplerBindingType::Comparison;
679 case MaterialDataType::Int:
680 case MaterialDataType::Int2:
681 case MaterialDataType::Int3:
682 case MaterialDataType::Int4:
683 case MaterialDataType::UInt:
684 case MaterialDataType::UInt2:
685 case MaterialDataType::UInt3:
686 case MaterialDataType::UInt4:
687 return Cogs::BindingSamplerBindingType::NonFiltering;
690 ? Cogs::BindingSamplerBindingType::NonFiltering
691 : Cogs::BindingSamplerBindingType::Filtering;
696 void addTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
BindGroupSetDescription& layoutSet,
int group, uint32_t visibility,
const std::vector<MaterialTextureDefinition>& definition,
bool ignoreIdentifiersSeen =
false)
698 for (
auto& texture : definition) {
699 if (!identifiersSeen.contains(Strings::add(texture.name)) && !ignoreIdentifiersSeen) {
703 std::string samplerType =
"sampler";
709 if (texture.isDepth) {
711 samplerType +=
"_comparison";
714 switch (texture.dimensions) {
715 case TextureDimensions::Texture2D:
718 case TextureDimensions::TexureCube:
721 case TextureDimensions::Texture2DArray:
724 case TextureDimensions::Texture3D:
728 LOG_ERROR(logger,
"Unsupported texture dimension %d",
int(texture.dimensions));
732 if (!texture.isDepth) {
733 std::string dataType = textureDataType(texture.format);
734 type +=
"<" + dataType +
">";
737 ResourceDimensions textureDimension = bindingLayoutTextureDimension(texture.dimensions);
738 const bool multisampled =
false;
739 addUniform(shaderSource, layoutSet, group, visibility, texture.name, type,
false, BindingResourceType::Texture, textureDimension, texture.isDepth);
744 textureEntry->textureSampleType = deduceTextureSampleType(texture.format, texture.isDepth, multisampled);
745 textureEntry->multisampled = multisampled;
748 std::string samplerName = texture.name +
"Sampler";
749 if (identifiersSeen.contains(Strings::add(samplerName)) && !ignoreIdentifiersSeen) {
750 addUniform(shaderSource, layoutSet, group, visibility, samplerName, samplerType,
false, BindingResourceType::Sampler, textureDimension, texture.isDepth);
754 samplerEntry->samplerBindingType = deduceSamplerBindingType(texture.format, texture.isDepth, multisampled);
761 out.members.reserve(a.members.size() + b.members.size());
763 for (
auto member : b.members) {
765 for (
auto existingMember : a.members) {
766 if (member.name == existingMember.name) {
772 out.members.push_back(member);
778bool Cogs::Core::buildEffectWebGPU(
Context* context,
779 std::vector<std::pair<std::string, std::string>>& definitions,
782 const uint32_t multiViewCount)
784 if (!materialDefinition.effect.geometryShader.entryPoint.empty()) {
785 LOG_ERROR(logger,
"%s: Geometry shader not allowed in WebGPU.", materialDefinition.name.c_str());
788 if (!materialDefinition.effect.hullShader.entryPoint.empty()) {
789 LOG_ERROR(logger,
"%s: Hull shader not allowed in WebGPU.", materialDefinition.name.c_str());
792 if (!materialDefinition.effect.domainShader.entryPoint.empty()) {
793 LOG_ERROR(logger,
"%s: Domain shader not allowed in WebGPU.", materialDefinition.name.c_str());
796 if (!materialDefinition.effect.computeShader.entryPoint.empty()) {
797 LOG_ERROR(logger,
"%s: Compute shader not allowed in WebGPU.", materialDefinition.name.c_str());
801 changeSuffix(materialDefinition.effect.vertexShader.customSourcePath,
".hlsl",
".wgsl");
802 changeSuffix(materialDefinition.effect.pixelShader.customSourcePath,
".hlsl",
".wgsl");
803 std::string prefix =
"" + materialDefinition.name;
806 bindings = getEngineBindGroupDescription();
807 std::vector<bool> bindGroupUsed(
static_cast<size_t>(Cogs::Core::BindGroup::Count),
false);
811 std::string vs_header;
812 const std::string shaderName = prefix +
"VertexShader" + permutation.getDefinition()->name +
".wgsl";
813 addEffectDefinesAndStuff(vs_header, definitions, multiViewCount);
814 if (!pp.
process(context, vs_header))
return false;
822 concatUniqueMembers(materialDefinition.effect.vertexShader.shaderInterface, permutation.getDefinition()->vertexInterface, vertexInterface);
823 addInterfaceStruct(vs_header, vs_body,
"VertexIn", vertexInterface, ShaderInterface::VertexIn);
827 concatUniqueMembers(materialDefinition.effect.pixelShader.shaderInterface, permutation.getDefinition()->surfaceInterface, surfaceInterface);
828 addInterfaceStruct(vs_header, vs_body,
"VertexOut", surfaceInterface, ShaderInterface::VertexOut);
830 addInterfaceConstructor(vs_body,
"VertexOut", materialDefinition.effect.pixelShader.shaderInterface);
831 addTransferFunc(vs_body, materialDefinition.effect.vertexShader, materialDefinition.effect.pixelShader);
832 addInclude(vs_body, std::string_view(), materialDefinition.effect.vertexShader.customSourcePath);
833 std::string permutationVS = permutation.getDefinition()->vertexShader;
834 changeSuffix(permutationVS,
".hlsl",
".wgsl");
836 addCallFunction(vs_body,
"callMaterialVertexFunction",
837 materialDefinition.effect.vertexShader.entryPoint.empty() ?
"vertexFunction" : materialDefinition.effect.vertexShader.entryPoint,
838 "VertexIn",
"VertexOut");
839 addInclude(vs_body, std::string_view(),
"Engine/EngineVS.wgsl");
840 addCallFunction(vs_body,
"callVertexFunction",
842 "VertexIn",
"VertexOut");
843 addInclude(vs_body, std::string_view(), permutationVS);
844 if (!pp.
process(context, vs_body))
return false;
848 std::string vs_uniforms;
849 addTextures(vs_uniforms, pp.
identifiersSeen, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityVertex, materialDefinition.properties.textures,
false);
852 addUniformBuffer(vs_uniforms, pp.
identifiersSeen, buffer, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityVertex);
855 addUniformBuffer(vs_uniforms, pp.
identifiersSeen, buffer, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityVertex);
857 addEngineUniformsToSourceWebGPU(vs_uniforms, pp.
identifiersSeen, bindGroupUsed);
864 addInclude(vs_uniforms, std::string_view(),
"Engine/AnimationBuffer.wgsl");
865 addUniform(vs_uniforms, bindings,
static_cast<int>(Cogs::Core::BindGroup::Object), Cogs::BindingVisibilityVertex,
"AnimationBuffer",
"AnimationBuffer_t",
true);
866 bindGroupUsed[
static_cast<size_t>(Cogs::Core::BindGroup::Object)] =
true;
869 addInclude(vs_uniforms, std::string_view(),
"Engine/Common.wgsl");
871 if (!pp.
process(context, vs_uniforms))
return false;
875 std::string all = vs_header + vs_uniforms + vs_body;
876 all = convertDefinesToConstExpressions(all);
878 std::string vspath =
"Shaders/" + shaderName;
883 std::string fs_header;
884 const std::string shaderName = prefix +
"PixelShader" + permutation.getDefinition()->name +
".wgsl";
885 addEffectDefinesAndStuff(fs_header, definitions, 0 );
888 bool fs_returnsStruct =
false;
891 surfaceInterface.members.insert(surfaceInterface.members.end(), permutation.getDefinition()->surfaceInterface.members.begin(),
892 permutation.getDefinition()->surfaceInterface.members.end());
893 addInterfaceStruct(fs_header, fs_body,
"VertexIn", surfaceInterface, ShaderInterface::FragmentIn);
894 fs_returnsStruct = addOutputStruct(fs_header, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly());
897 addInclude(fs_header, std::string_view(), materialDefinition.effect.pixelShader.customSourcePath);
898 std::string permutationFS = permutation.getDefinition()->pixelShader;
899 changeSuffix(permutationFS,
".hlsl",
".wgsl");
901 addCallFunction(fs_header,
"callMaterialSurfaceFunction",
902 materialDefinition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : materialDefinition.effect.pixelShader.entryPoint,
903 "VertexIn",
"SurfaceOut");
904 addInclude(fs_header, std::string_view(),
"Engine/EnginePS.wgsl");
905 addCallFunction(fs_header,
"callSurfaceFunction",
907 "VertexIn",
"SurfaceOut");
908 addInclude(fs_header, std::string_view(), permutationFS);
909 if (fs_returnsStruct) {
913fn main(In : VertexIn) -> FragmentOut {
914 return permutationMain(In);
921fn main(In : VertexIn) {
927 if (!pp.
process(context, fs_header))
return false;
931 std::string fs_uniforms;
932 fs_uniforms.reserve(InitialBufferCapasity);
933 addTextures(fs_uniforms, pp.
identifiersSeen, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityFragment, materialDefinition.properties.textures,
false);
934 addEngineUniformsToSourceWebGPU(fs_uniforms, pp.
identifiersSeen, bindGroupUsed);
936 addUniformBuffer(fs_uniforms, pp.
identifiersSeen, buffer, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityFragment);
939 addUniformBuffer(fs_uniforms, pp.
identifiersSeen, buffer, bindings,
static_cast<int>(Cogs::Core::BindGroup::Default), Cogs::BindingVisibilityFragment);
941 addInclude(fs_uniforms, std::string_view(),
"Engine/Common.wgsl");
942 if (!pp.
process(context, fs_uniforms))
return false;
946 std::string all = fs_header + fs_uniforms + fs_body;
947 all = convertDefinesToConstExpressions(all);
949 std::string fspath =
"Shaders/" + shaderName;
955 bindGroupUsed[
static_cast<size_t>(Cogs::Core::BindGroup::Default)] = bindings.groups[0].numEntries > 0;
957 for (
size_t g = 0; g < bindGroupUsed.size(); g++) {
959 target.numEntries = 0;
960 if (!bindGroupUsed[g])
continue;
965 target = bindings.groups[g];
966 materialDefinition.effect.
bindGroupLayouts.numGroups =
static_cast<uint16_t
>(g + 1);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
TextureDimensions
Texture dimensions.
MaterialDataType
Defines available data types for material properties.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
BindGroupSetDescription bindGroupLayouts
Optional backend-neutral bind-group layout metadata, typically emitted by shader builders.
bool process(Context *context, const StringView input)
Run a text block through the preprocessor.
std::unordered_set< StringRef > identifiersSeen
Set of identifiers encountered in active text.
std::string processed
Resulting processed text.