1#include "ShaderBuilder.h"
3#include "Utilities/Strings.h"
4#include "Utilities/Preprocessor.h"
5#include "ResourceStore.h"
6#include "Renderer/EnginePermutations.h"
7#include "Rendering/IGraphicsDevice.h"
9#include "Foundation/Logging/Logger.h"
18 constexpr size_t InitialBufferCapasity = 4096u;
20 constexpr std::array semanticNames
33 std::string_view getSemanticName(
size_t semantic_ind) {
34 std::string_view name;
35 if (semantic_ind < semanticNames.size()) {
36 name = semanticNames[semantic_ind];
44 enum ShaderInterface { None = 0, VertexIn = 1, VertexOut = 2, FragmentIn = 4, FragmentOut = 8 };
46 struct BuiltinAttributeDescription {
47 std::string builtinName;
49 ShaderInterface stage = ShaderInterface::None;
52 struct BuiltinAttributes {
53 ShaderInterfaceMemberDefinition::SemanticName semanticName;
54 BuiltinAttributeDescription desc;
57 const std::array<BuiltinAttributes, 5> builtinAttributes{
58 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
59 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID, {
"vertex_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
60 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
61 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
62 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
65 struct BuiltinDataType {
67 BuiltinAttributeDescription desc;
70 const std::array builtinDataTypes {
71 BuiltinDataType{MaterialDataType::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn} },
72 BuiltinDataType{MaterialDataType::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
73 BuiltinDataType{MaterialDataType::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn} },
74 BuiltinDataType{MaterialDataType::VFACE, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
77 const std::array optionalEngineBuffers = {
83 struct EngineTexture {
86 bool isDepthTexture =
false;
89 const std::array engineTextures = {
90 EngineTexture{.name =
"environmentSky", .dimensions = TextureDimensions::TexureCube},
91 EngineTexture{.name =
"environmentRadiance", .dimensions = TextureDimensions::TexureCube},
92 EngineTexture{.name =
"environmentIrradiance", .dimensions = TextureDimensions::TexureCube},
93 EngineTexture{.name =
"ambientIrradiance", .dimensions = TextureDimensions::TexureCube},
94 EngineTexture{.name =
"brdfLUT", .dimensions = TextureDimensions::Texture2D},
95 EngineTexture{.name =
"cascadedShadowMap", .dimensions = TextureDimensions::Texture2DArray, .isDepthTexture =
true},
96 EngineTexture{.name =
"cubeShadowMap", .dimensions = TextureDimensions::TexureCube, .isDepthTexture =
true},
99 struct WebGPULocation {
103 bool isDepthTexture =
false;
104 WebGPULocation(
size_t location,
const std::string &name,
Cogs::Core::TextureDimensions dimensions = Cogs::Core::TextureDimensions::Texture2D,
bool isDepthTexture =
false) :
105 location(location), name(name), dimensions(dimensions), isDepthTexture(isDepthTexture) { }
106 WebGPULocation() =
default;
110 using WebGPUBindingGroup = std::vector<WebGPULocation>;
111 using WebGPUBindingGroupVector = std::vector<WebGPUBindingGroup>;
114 bool hasBinding(
const WebGPUBindingGroupVector& bindingGroups, std::string_view name) {
115 for (
const WebGPUBindingGroup& bindings : bindingGroups) {
116 for (
const WebGPULocation& location : bindings) {
117 if (location.name == name) {
125 void createBufferBinding(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
126 if (bindingGroups.empty()) {
127 bindingGroups.emplace_back();
129 WebGPUBindingGroup& locations = bindingGroups[0];
130 locations.emplace_back(0,
"BLOCKED");
132 for (
auto& buffer : optionalEngineBuffers) {
133 locations.emplace_back(locations.size(), buffer);
136 for (
auto& buffer : materialDefinition.properties.buffers) {
137 if (std::find(std::begin(optionalEngineBuffers), std::end(optionalEngineBuffers), buffer.name) == std::end(optionalEngineBuffers)) {
138 if (!hasBinding(bindingGroups, buffer.name)) {
139 locations.emplace_back(locations.size(), buffer.name);
146 std::string convertDefinesToConstExpressions(
const std::string& s) {
147 std::map<std::string, std::string> addedDefines;
149 result.reserve(s.size());
151 std::istringstream iss(s);
153 std::string identifier;
154 std::string replacement;
155 for (std::string line; std::getline(iss, line); )
160 std::string_view sv(line);
161 auto pos = sv.find_first_not_of(
" \t");
162 if (pos == std::string_view::npos || sv.substr(pos, 7) !=
"#define") {
163 result += line +
"\n";
166 sv = sv.substr(pos + 7);
168 pos = sv.find_first_not_of(
" \t");
169 if (pos == std::string_view::npos) {
170 result += line +
"\n";
175 auto end = sv.find_first_of(
" \t");
176 if (end == std::string_view::npos) {
180 identifier = sv.substr(0, end);
182 pos = sv.find_first_not_of(
" \t");
183 if (pos == std::string_view::npos) {
186 auto last = sv.find_last_not_of(
" \t");
187 replacement = sv.substr(pos, last - pos + 1);
191 auto it = addedDefines.find(identifier);
192 if (it != addedDefines.end()) {
193 if (replacement != (*it).second) {
194 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());
198 result +=
"const " + identifier +
" = " + replacement +
";\n";
199 addedDefines.try_emplace(identifier, replacement);
204 void addInclude(std::string& content, std::string_view prefix, std::string_view path)
206 content.append(
"#include \"");
207 content.append(prefix);
208 content.append(path);
209 content.append(
"\"\n");
212 void changeSuffix(std::string& dst, std::string_view from, std::string_view to)
214 if (dst.ends_with(from)) {
215 dst.replace(dst.size() - from.length(), from.length(), to);
223 case MaterialDataType::Float:
return "f32 ";
break;
224 case MaterialDataType::Float2:
return "vec2f ";
break;
225 case MaterialDataType::Float3:
return "vec3f ";
break;
226 case MaterialDataType::Float4:
return "vec4f ";
break;
227 case MaterialDataType::Float4x4:
return "mat4x4f ";
break;
228 case MaterialDataType::Int:
return "i32 ";
break;
229 case MaterialDataType::Int2:
return "vec4i ";
break;
230 case MaterialDataType::Int3:
return "vec3i ";
break;
231 case MaterialDataType::Int4:
return "vec4i ";
break;
232 case MaterialDataType::UInt:
return "u32 ";
break;
233 case MaterialDataType::UInt2:
return "vec4u ";
break;
234 case MaterialDataType::UInt3:
return "vec3u ";
break;
235 case MaterialDataType::UInt4:
return "vec4u ";
break;
236 case MaterialDataType::Bool:
return "bool ";
break;
237 case MaterialDataType::SV_IsFrontFace:
return "bool ";
break;
238 case MaterialDataType::VFACE:
return "f32 ";
break;
239 case MaterialDataType::Position:
return "vec4f ";
break;
241 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
247 void createTextureBindings(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
248 if (bindingGroups.empty()) {
249 bindingGroups.emplace_back();
251 WebGPUBindingGroup& locations = bindingGroups[0];
253 for (
auto& texture : materialDefinition.properties.textures) {
254 if (!hasBinding(bindingGroups, texture.name)) {
255 std::string name = texture.name;
256 locations.emplace_back(locations.size(), name, texture.dimensions);
257 locations.emplace_back(locations.size(), name +
"Sampler", texture.dimensions, texture.isDepth);
262 void createEngineTextureBindings(WebGPUBindingGroupVector& bindingGroups) {
263 if (bindingGroups.empty()) {
264 bindingGroups.emplace_back();
266 WebGPUBindingGroup& locations = bindingGroups[0];
268 for (
auto& tex : engineTextures) {
269 if (!hasBinding(bindingGroups, tex.name)) {
270 std::string name = tex.name;
271 locations.emplace_back(locations.size(), name, tex.dimensions, tex.isDepthTexture);
272 locations.emplace_back(locations.size(), name +
"Sampler", tex.dimensions, tex.isDepthTexture);
277 void addEffectDefinesAndStuff(std::string& output,
const std::vector<std::pair<std::string, std::string>>& definitions, uint32_t multiViewCount) {
278 if (multiViewCount) {
279 std::string multiViewCountString = std::to_string(multiViewCount);
280 output.append(
"#extension GL_OVR_multiview : require\nlayout(num_views=");
281 output.append(multiViewCountString);
282 output.append(
") in;\n");
283 output.append(
"#define COGS_MULTIVIEW ");
284 output.append(multiViewCountString);
288 std::unordered_set<std::string> addedDefines;
290 for (
const std::pair<std::string, std::string>& define : definitions) {
291 if (addedDefines.contains(define.first)) {
294 output.append(
"#define ");
295 output.append(define.first);
297 output.append(define.second);
299 addedDefines.insert(define.first);
305 BuiltinAttributeDescription desc;
306 desc.stage = ShaderInterface::None;
307 for (
const auto& builtin : builtinDataTypes)
309 if (builtin.type == attribute.type) {
313 for (
const auto& attr : builtinAttributes) {
314 if (attr.semanticName == attribute.semantic.name) {
321 void addInterfaceStruct(std::string& defines, std::string& source, std::string_view name,
const ShaderInterfaceDefinition& iface, ShaderInterface shaderInterface)
324 source.append(
"struct ");
326 source.append(
" {\n");
328 if (shaderInterface & ShaderInterface::VertexOut) {
329 source.append(
" @builtin(position) Position: vec4f,\n");
331 for (
const auto& attribute : iface.members) {
332 BuiltinAttributeDescription builtinAttributeDescription = getBuiltinAttributeDescription(attribute);
333 if (shaderInterface & ShaderInterface::VertexOut &&
334 (builtinAttributeDescription.stage & ShaderInterface::FragmentIn) != 0) {
337 if (shaderInterface & ShaderInterface::FragmentIn && attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::None && attribute.type == MaterialDataType::Position) {
341 if ((builtinAttributeDescription.stage & shaderInterface) != 0) {
342 source.append(
" @builtin(" + builtinAttributeDescription.builtinName +
") ");
343 source.append(attribute.name);
344 source.append(
" : ");
345 source.append(attributeVaryingType(builtinAttributeDescription.type));
346 source.append(
",\n");
349 if (shaderInterface & ShaderInterface::VertexIn) {
350 size_t nameInd = size_t (attribute.semantic.name) - 1;
351 std::string_view semanticName = getSemanticName(nameInd);
352 if (!semanticName.empty()) {
353 if(attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::InstanceMatrix){
354 std::string defineName;
355 defineName.append(semanticName);
356 int loc = attribute.semantic.slot;
357 defineName.append(std::to_string(loc) +
"_LOC");
358 defines.append(
"#define ");
359 defines.append(defineName +
" " + std::to_string(next_loc) +
"\n");
361 for(
int i=0; i<4; i++){
362 source.append(
" @location(" + defineName +
" + " + std::to_string(i) +
") ");
363 source.append(attribute.name +
"_" + std::to_string(i));
364 source.append(
" : vec4f,\n");
369 std::string defineName;
370 defineName.append(semanticName);
371 defineName.append(std::to_string(attribute.semantic.slot) +
"_LOC");
372 defines.append(
"#define ");
373 defines.append(defineName +
" " + std::to_string(next_loc++) +
"\n");
374 source.append(
" @location(" + defineName +
") ");
375 source.append(attribute.name);
376 source.append(
" : ");
377 source.append(attributeVaryingType(attribute.type));
378 source.append(
",\n");
383 source.append(
" @location(" + std::to_string(next_loc++) +
") ");
384 source.append(attribute.name);
385 source.append(
" : ");
386 source.append(attributeVaryingType(attribute.type));
387 source.append(
",\n");
391 source.append(
"};\n\n");
396 shaderSource.append(
"fn create");
397 shaderSource.append(name);
398 shaderSource.append(
"() -> ");
399 shaderSource.append(name);
400 shaderSource.append(
" {\n");
401 shaderSource.append(
" var t : ");
402 shaderSource.append(name);
403 shaderSource.append(
";\n");
404 for (
const auto& attribute : iface.members) {
405 const char* initializer =
nullptr;
406 switch (attribute.type) {
407 case MaterialDataType::Float: initializer =
"0.0;\n";
break;
408 case MaterialDataType::Float2: initializer =
"vec2f(0);\n";
break;
409 case MaterialDataType::Float3: initializer =
"vec3f(0);\n";
break;
410 case MaterialDataType::Float4: initializer =
"vec4f(0);\n";
break;
411 case MaterialDataType::Float4x4: initializer =
"mat4x4f(0);\n";
break;
416 shaderSource.append(
" t.");
417 shaderSource.append(attribute.name);
418 shaderSource.append(
" = ");
419 shaderSource.append(initializer);
422 shaderSource.append(
" return t;\n}\n\n");
425 void addUniform(std::string& shaderSource, WebGPUBindingGroupVector& bindingGroups, std::string_view name, std::string_view type,
bool useTemplate =
false) {
426 WebGPUBindingGroup& bindings = bindingGroups[0];
427 WebGPULocation location;
428 for (
const WebGPULocation& curr_location : bindings) {
429 if (curr_location.name == name) {
430 location = curr_location;
434 if (location.name != name) {
435 LOG_WARNING(logger,
"adding to bindgroup %s", std::string(name).c_str());
436 location = WebGPULocation(bindings.size(), std::string(name));
437 bindings.push_back(location);
439 shaderSource.append(
"@group(");
440 shaderSource.append(std::to_string(0));
441 shaderSource.append(
") @binding(");
442 shaderSource.append(std::to_string(location.location));
443 shaderSource.append(
") var");
445 shaderSource.append(
"<uniform>");
447 shaderSource.append(
" ");
448 shaderSource.append(name);
449 shaderSource.append(
" : ");
450 shaderSource.append(type);
451 shaderSource.append(
";\n");
454 void addUniformBuffer(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
const ConstantBufferDefinition& definition, WebGPUBindingGroupVector& bindingGroups)
456 if (!identifiersSeen.contains(Strings::add(definition.name))) {
459 if (definition.values.empty())
return;
460 shaderSource.append(
"struct ");
461 shaderSource.append(definition.name);
462 shaderSource.append(
"_t {\n");
464 shaderSource.append(member.name);
465 shaderSource.append(
" : ");
467 switch (member.type) {
468 case MaterialDataType::Float: shaderSource.append(
"f32");
break;
469 case MaterialDataType::Float2: shaderSource.append(
"vec2f");
break;
470 case MaterialDataType::Float3: shaderSource.append(
"vec3f");
break;
471 case MaterialDataType::Float4Array:
472 shaderSource.append(
"array<vec4f, " + std::to_string(member.dimension) +
">");
473 assert(member.dimension !=
static_cast<size_t>(-1));
475 case MaterialDataType::Float4: shaderSource.append(
"vec4f");
break;
476 case MaterialDataType::Float4x4Array:
477 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f");
break;
478 case MaterialDataType::Int: shaderSource.append(
"i32");
break;
479 case MaterialDataType::Int2: shaderSource.append(
"vec2i");
break;
480 case MaterialDataType::Int3: shaderSource.append(
"vec3i");
break;
481 case MaterialDataType::Int4: shaderSource.append(
"vec4i");
break;
482 case MaterialDataType::UInt: shaderSource.append(
"u32");
break;
483 case MaterialDataType::UInt2: shaderSource.append(
"vec2u");
break;
484 case MaterialDataType::UInt3: shaderSource.append(
"vec3u");
break;
485 case MaterialDataType::UInt4: shaderSource.append(
"vec4u");
break;
486 case MaterialDataType::Bool: shaderSource.append(
"u32");
break;
488 LOG_ERROR(logger,
"Invalid type for buffer varable %s in buffer %s.", member.name.c_str(), definition.name.c_str());
489 shaderSource.append(
"<invalid type>");
492 shaderSource.append(
",\n");
494 shaderSource.append(
"};\n");
496 addUniform(shaderSource, bindingGroups, definition.name, definition.name +
"_t",
true);
499 void addEngineBuffers(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups) {
500 for (
const std::string& name : optionalEngineBuffers) {
502 if (identifiersSeen.contains(Strings::add(name))){
505 if (name ==
"SceneBuffer") {
506 const char *getters[] = {
507 "getClipFromViewMatrix",
508 "getClipFromWorldMatrix",
509 "getViewFromWorldMatrix",
510 "getViewFromClipMatrix",
511 "getWorldFromViewMatrix",
512 "getViewFromViewportMatrix",
513 "getPeriodicWorldPosAndCell",
514 "getPeriodicWorldPos"
516 for(
auto &get : getters){
517 if (identifiersSeen.contains(Strings::add(get))){
523 addUniform(shaderSource, bindingGroups, name, name +
"_t",
true);
524 if (name ==
"SceneBuffer") {
525 shaderSource.append(
"#define COGS_VIEWGETTERS_REFERENCED 1\n");
533 shaderSource.append(
"fn transferAttributes(vertexIn : VertexIn, vertexOut : ptr<function, VertexOut>) {\n");
535 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
537 if (dMember.name == member.name) {
538 shaderSource.append(
" (*vertexOut).");
539 shaderSource.append(member.name);
540 shaderSource.append(
" = ");
541 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
542 shaderSource.append(
"octDecode(vertexIn.");
543 shaderSource.append(member.name);
544 shaderSource.append(
"); \n");
547 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
548 shaderSource.append(
"vec4f(vertexIn.");
549 shaderSource.append(member.name);
550 shaderSource.append(
", 1.0);\n");
553 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
554 shaderSource.append(
"vec4f(vertexIn.");
555 shaderSource.append(member.name);
556 shaderSource.append(
", 0.0, 1.0);\n");
560 if (dMember.type != member.type) {
561 switch (dMember.type) {
562 case MaterialDataType::Float: shaderSource.append(
"f32("); close =
true;
break;
563 case MaterialDataType::Float2: shaderSource.append(
"vec2f("); close =
true;
break;
564 case MaterialDataType::Float3: shaderSource.append(
"vec3f("); close =
true;
break;
565 case MaterialDataType::Float4: shaderSource.append(
"vec4f("); close =
true;
break;
566 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f("); close =
true;
break;
567 case MaterialDataType::Int: shaderSource.append(
"i32("); close =
true;
break;
568 case MaterialDataType::Int2: shaderSource.append(
"vec2i("); close =
true;
break;
569 case MaterialDataType::Int3: shaderSource.append(
"vec3i("); close =
true;
break;
570 case MaterialDataType::Int4: shaderSource.append(
"vec4i("); close =
true;
break;
571 case MaterialDataType::UInt: shaderSource.append(
"u32("); close =
true;
break;
572 case MaterialDataType::UInt2: shaderSource.append(
"vec2u("); close =
true;
break;
573 case MaterialDataType::UInt3: shaderSource.append(
"vec3u("); close =
true;
break;
574 case MaterialDataType::UInt4: shaderSource.append(
"vec4u("); close =
true;
break;
579 if (dMember.type == member.type) {
580 shaderSource.append(
"vertexIn.");
581 shaderSource.append(member.name);
584 LOG_WARNING(logger,
"%s Skip transfer of %s. (Different types).", sourceDefinition.loadPath.c_str(), member.name.c_str());
586 if (close) shaderSource.append(1,
')');
587 shaderSource.append(
";\n");
592 shaderSource.append(
"}\n");
595 bool addOutputStruct(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly) {
596 bool outputDepth =
false;
597 bool hasColorAttachments = !outputDefinition.empty() && !depthOnly;
599 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
600 auto it = std::find_if(definitions.begin(), definitions.end(),
601 [&targetString](
const std::pair<std::string, std::string>& p){
602 return p.first == targetString;
605 if (it != definitions.end()) {
606 outputDepth = it->second !=
"0";
609 if (!outputDepth && !hasColorAttachments) {
613 source.append(
"struct FragmentOut {\n");
615 if (hasColorAttachments) {
616 for (
auto member : outputDefinition) {
617 source.append(
" @location(");
618 source.append(std::to_string(member.target));
620 source.append(member.name +
" : ");
622 switch (member.dataType) {
623 case MaterialDataType::Float: source.append(
"f32");
break;
624 case MaterialDataType::Float2: source.append(
"vec2f");
break;
625 case MaterialDataType::Float3: source.append(
"vec3f");
break;
626 case MaterialDataType::Float4: source.append(
"vec4f");
break;
627 case MaterialDataType::Float4x4: source.append(
"mat4x4f");
break;
628 case MaterialDataType::Int: source.append(
"i32");
break;
629 case MaterialDataType::Int2: source.append(
"vec2i");
break;
630 case MaterialDataType::Int3: source.append(
"vec3i");
break;
631 case MaterialDataType::Int4: source.append(
"vec4i");
break;
632 case MaterialDataType::UInt: source.append(
"u32");
break;
633 case MaterialDataType::UInt2: source.append(
"vec2u");
break;
634 case MaterialDataType::UInt3: source.append(
"vec3u");
break;
635 case MaterialDataType::UInt4: source.append(
"vec4u");
break;
639 source.append(
",\n");
643 source.append(
"@builtin(frag_depth) depth : f32\n");
645 source.append(
"};\n");
650 void addCallFunction(std::string& source, std::string_view name, std::string_view functionName, std::string_view inType, std::string_view outType) {
651 source.append(
"fn ");
653 source.append(
"(In : ");
654 source.append(inType);
655 source.append(
") ->");
656 source.append(outType);
657 source.append(
" { \n");
658 source.append(
" return ");
659 source.append(functionName);
660 source.append(
"(In);\n");
661 source.append(
"}\n\n");
668 case MaterialDataType::Unknown:
669 case MaterialDataType::Float:;
670 case MaterialDataType::Float2:
671 case MaterialDataType::Float3:
672 case MaterialDataType::Float4:
674 case MaterialDataType::Int:
675 case MaterialDataType::Int2:
676 case MaterialDataType::Int3:
677 case MaterialDataType::Int4:
679 case MaterialDataType::UInt:
680 case MaterialDataType::UInt2:
681 case MaterialDataType::UInt3:
682 case MaterialDataType::UInt4:
685 LOG_ERROR(logger,
"Unsupported texture datatype %d",
int(type));
692 void addTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups,
const std::vector<MaterialTextureDefinition>& definition,
bool ignoreIdentifiersSeen =
false)
694 for (
auto& texture : definition) {
695 if (!identifiersSeen.contains(Strings::add(texture.name)) && !ignoreIdentifiersSeen) {
699 std::string samplerType =
"sampler";
705 if (texture.isDepth) {
707 samplerType +=
"_comparison";
710 switch (texture.dimensions) {
711 case TextureDimensions::Texture2D:
714 case TextureDimensions::TexureCube:
717 case TextureDimensions::Texture2DArray:
720 case TextureDimensions::Texture3D:
724 LOG_ERROR(logger,
"Unsupported texture dimension %d",
int(texture.dimensions));
728 if (!texture.isDepth) {
729 std::string dataType = textureDataType(texture.format);
730 type +=
"<" + dataType +
">";
733 addUniform(shaderSource, bindingGroups, texture.name, type);
734 std::string samplerName = texture.name +
"Sampler";
735 if (identifiersSeen.contains(Strings::add(samplerName)) && !ignoreIdentifiersSeen) {
736 addUniform(shaderSource, bindingGroups, samplerName, samplerType);
741 void addEngineTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups)
743 for (
auto& texture : engineTextures) {
744 if (!identifiersSeen.contains(Strings::add(texture.name))) {
749 std::string samplerType =
"sampler";
752 if (texture.isDepthTexture) {
754 samplerType +=
"_comparison";
757 switch (texture.dimensions) {
758 case TextureDimensions::Texture2D:
761 case TextureDimensions::TexureCube:
764 case TextureDimensions::Texture2DArray:
767 case TextureDimensions::Texture3D:
771 LOG_ERROR(logger,
"Unsupported texture type %d",
int(texture.dimensions));
774 if (!texture.isDepthTexture) {
777 addUniform(shaderSource, bindingGroups, texture.name, type);
778 addUniform(shaderSource, bindingGroups, texture.name +
"Sampler", samplerType);
783 out.members.reserve(a.members.size() + b.members.size());
785 for (
auto member : b.members) {
787 for (
auto existingMember : a.members) {
788 if (member.name == existingMember.name) {
794 out.members.push_back(member);
800bool Cogs::Core::buildEffectWebGPU(
Context* context,
801 std::vector<std::pair<std::string, std::string>>& definitions,
804 const uint32_t multiViewCount)
806 if (!materialDefinition.effect.geometryShader.entryPoint.empty()) {
807 LOG_ERROR(logger,
"%s: Geometry shader not allowed in WebGPU.", materialDefinition.name.c_str());
810 if (!materialDefinition.effect.hullShader.entryPoint.empty()) {
811 LOG_ERROR(logger,
"%s: Hull shader not allowed in WebGPU.", materialDefinition.name.c_str());
814 if (!materialDefinition.effect.domainShader.entryPoint.empty()) {
815 LOG_ERROR(logger,
"%s: Domain shader not allowed in WebGPU.", materialDefinition.name.c_str());
818 if (!materialDefinition.effect.computeShader.entryPoint.empty()) {
819 LOG_ERROR(logger,
"%s: Compute shader not allowed in WebGPU.", materialDefinition.name.c_str());
823 changeSuffix(materialDefinition.effect.vertexShader.customSourcePath,
".hlsl",
".wgsl");
824 changeSuffix(materialDefinition.effect.pixelShader.customSourcePath,
".hlsl",
".wgsl");
825 std::string prefix =
"" + materialDefinition.name;
827 WebGPUBindingGroupVector bindings;
828 createBufferBinding(bindings, materialDefinition);
829 createTextureBindings(bindings, materialDefinition);
830 createEngineTextureBindings(bindings);
834 std::string vs_header;
835 const std::string shaderName = prefix +
"VertexShader" + permutation.getDefinition()->name +
".wgsl";
836 addEffectDefinesAndStuff(vs_header, definitions, multiViewCount);
837 if (!pp.
process(context, vs_header))
return false;
845 concatUniqueMembers(materialDefinition.effect.vertexShader.shaderInterface, permutation.getDefinition()->vertexInterface, vertexInterface);
846 addInterfaceStruct(vs_header, vs_body,
"VertexIn", vertexInterface, ShaderInterface::VertexIn);
850 concatUniqueMembers(materialDefinition.effect.pixelShader.shaderInterface, permutation.getDefinition()->surfaceInterface, surfaceInterface);
851 addInterfaceStruct(vs_header, vs_body,
"VertexOut", surfaceInterface, ShaderInterface::VertexOut);
853 addInterfaceConstructor(vs_body,
"VertexOut", materialDefinition.effect.pixelShader.shaderInterface);
854 addTransferFunc(vs_body, materialDefinition.effect.vertexShader, materialDefinition.effect.pixelShader);
855 addInclude(vs_body, std::string_view(), materialDefinition.effect.vertexShader.customSourcePath);
856 std::string permutationVS = permutation.getDefinition()->vertexShader;
857 changeSuffix(permutationVS,
".hlsl",
".wgsl");
859 addCallFunction(vs_body,
"callMaterialVertexFunction",
860 materialDefinition.effect.vertexShader.entryPoint.empty() ?
"vertexFunction" : materialDefinition.effect.vertexShader.entryPoint,
861 "VertexIn",
"VertexOut");
862 addInclude(vs_body, std::string_view(),
"Engine/EngineVS.wgsl");
863 addCallFunction(vs_body,
"callVertexFunction",
865 "VertexIn",
"VertexOut");
866 addInclude(vs_body, std::string_view(), permutationVS);
867 if (!pp.
process(context, vs_body))
return false;
871 std::string vs_uniforms;
872 addTextures(vs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
881 addInclude(vs_uniforms, std::string_view(),
"Engine/Common.wgsl");
883 if (!pp.
process(context, vs_uniforms))
return false;
887 std::string all = vs_header + vs_uniforms + vs_body;
888 all = convertDefinesToConstExpressions(all);
890 std::string vspath =
"Shaders/" + shaderName;
895 std::string fs_header;
896 const std::string shaderName = prefix +
"PixelShader" + permutation.getDefinition()->name +
".wgsl";
897 addEffectDefinesAndStuff(fs_header, definitions, 0 );
900 bool fs_returnsStruct =
false;
903 surfaceInterface.members.insert(surfaceInterface.members.end(), permutation.getDefinition()->surfaceInterface.members.begin(),
904 permutation.getDefinition()->surfaceInterface.members.end());
905 addInterfaceStruct(fs_header, fs_body,
"VertexIn", surfaceInterface, ShaderInterface::FragmentIn);
906 fs_returnsStruct = addOutputStruct(fs_header, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly());
909 addInclude(fs_header, std::string_view(), materialDefinition.effect.pixelShader.customSourcePath);
910 std::string permutationFS = permutation.getDefinition()->pixelShader;
911 changeSuffix(permutationFS,
".hlsl",
".wgsl");
913 addCallFunction(fs_header,
"callMaterialSurfaceFunction",
914 materialDefinition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : materialDefinition.effect.pixelShader.entryPoint,
915 "VertexIn",
"SurfaceOut");
916 addInclude(fs_header, std::string_view(),
"Engine/EnginePS.wgsl");
917 addCallFunction(fs_header,
"callSurfaceFunction",
919 "VertexIn",
"SurfaceOut");
920 addInclude(fs_header, std::string_view(), permutationFS);
921 if (fs_returnsStruct) {
925fn main(In : VertexIn) -> FragmentOut {
926 return permutationMain(In);
933fn main(In : VertexIn) {
939 if (!pp.
process(context, fs_header))
return false;
943 std::string fs_uniforms;
944 fs_uniforms.reserve(InitialBufferCapasity);
945 addTextures(fs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
954 addInclude(fs_uniforms, std::string_view(),
"Engine/Common.wgsl");
955 if (!pp.
process(context, fs_uniforms))
return false;
959 std::string all = fs_header + fs_uniforms + fs_body;
960 all = convertDefinesToConstExpressions(all);
962 std::string fspath =
"Shaders/" + shaderName;
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
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.