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)}},
74 BuiltinDataType{MaterialDataType::Position, {
"position", MaterialDataType::Float4, ShaderInterface::FragmentIn} },
75 BuiltinDataType{MaterialDataType::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn} },
76 BuiltinDataType{MaterialDataType::VFACE, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
79 const std::array optionalEngineBuffers = {
87 struct EngineTexture {
90 bool isDepthTexture =
false;
93 const std::array engineTextures = {
94 EngineTexture{.name =
"environmentSky", .dimensions = TextureDimensions::TexureCube},
95 EngineTexture{.name =
"environmentRadiance", .dimensions = TextureDimensions::TexureCube},
96 EngineTexture{.name =
"environmentIrradiance", .dimensions = TextureDimensions::TexureCube},
97 EngineTexture{.name =
"ambientIrradiance", .dimensions = TextureDimensions::TexureCube},
98 EngineTexture{.name =
"brdfLUT", .dimensions = TextureDimensions::Texture2D},
99 EngineTexture{.name =
"cascadedShadowMap", .dimensions = TextureDimensions::Texture2DArray, .isDepthTexture =
true},
100 EngineTexture{.name =
"cubeShadowMap", .dimensions = TextureDimensions::TexureCube, .isDepthTexture =
true},
103 struct WebGPULocation {
107 bool isDepthTexture =
false;
108 WebGPULocation(
size_t location,
const std::string &name,
Cogs::Core::TextureDimensions dimensions = Cogs::Core::TextureDimensions::Texture2D,
bool isDepthTexture =
false) :
109 location(location), name(name), dimensions(dimensions), isDepthTexture(isDepthTexture) { }
110 WebGPULocation() =
default;
114 using WebGPUBindingGroup = std::vector<WebGPULocation>;
115 using WebGPUBindingGroupVector = std::vector<WebGPUBindingGroup>;
118 bool hasBinding(
const WebGPUBindingGroupVector& bindingGroups, std::string_view name) {
119 for (
const WebGPUBindingGroup& bindings : bindingGroups) {
120 for (
const WebGPULocation& location : bindings) {
121 if (location.name == name) {
129 void createBufferBinding(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
130 if (bindingGroups.empty()) {
131 bindingGroups.emplace_back();
133 WebGPUBindingGroup& locations = bindingGroups[0];
134 locations.emplace_back(0,
"BLOCKED");
136 for (
auto& buffer : optionalEngineBuffers) {
137 locations.emplace_back(locations.size(), buffer);
140 for (
auto& buffer : materialDefinition.properties.buffers) {
141 if (std::find(std::begin(optionalEngineBuffers), std::end(optionalEngineBuffers), buffer.name) == std::end(optionalEngineBuffers)) {
142 if (!hasBinding(bindingGroups, buffer.name)) {
143 locations.emplace_back(locations.size(), buffer.name);
150 std::string convertDefinesToConstExpressions(
const std::string& s) {
151 std::map<std::string, std::string> addedDefines;
153 result.reserve(s.size());
155 std::istringstream iss(s);
157 std::string identifier;
158 std::string replacement;
159 for (std::string line; std::getline(iss, line); )
164 std::string_view sv(line);
165 auto pos = sv.find_first_not_of(
" \t");
166 if (pos == std::string_view::npos || sv.substr(pos, 7) !=
"#define") {
167 result += line +
"\n";
170 sv = sv.substr(pos + 7);
172 pos = sv.find_first_not_of(
" \t");
173 if (pos == std::string_view::npos) {
174 result += line +
"\n";
179 auto end = sv.find_first_of(
" \t");
180 if (end == std::string_view::npos) {
184 identifier = sv.substr(0, end);
186 pos = sv.find_first_not_of(
" \t");
187 if (pos == std::string_view::npos) {
190 auto last = sv.find_last_not_of(
" \t");
191 replacement = sv.substr(pos, last - pos + 1);
195 auto it = addedDefines.find(identifier);
196 if (it != addedDefines.end()) {
197 if (replacement != (*it).second) {
198 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());
202 result +=
"const " + identifier +
" = " + replacement +
";\n";
203 addedDefines.try_emplace(identifier, replacement);
208 void addInclude(std::string& content, std::string_view prefix, std::string_view path)
210 content.append(
"#include \"");
211 content.append(prefix);
212 content.append(path);
213 content.append(
"\"\n");
216 void changeSuffix(std::string& dst, std::string_view from, std::string_view to)
218 if (dst.ends_with(from)) {
219 dst.replace(dst.size() - from.length(), from.length(), to);
227 case MaterialDataType::Float:
return "f32 ";
break;
228 case MaterialDataType::Float2:
return "vec2f ";
break;
229 case MaterialDataType::Float3:
return "vec3f ";
break;
230 case MaterialDataType::Float4:
return "vec4f ";
break;
231 case MaterialDataType::Float4x4:
return "mat4x4f ";
break;
232 case MaterialDataType::Int:
return "i32 ";
break;
233 case MaterialDataType::Int2:
return "vec4i ";
break;
234 case MaterialDataType::Int3:
return "vec3i ";
break;
235 case MaterialDataType::Int4:
return "vec4i ";
break;
236 case MaterialDataType::UInt:
return "u32 ";
break;
237 case MaterialDataType::UInt2:
return "vec4u ";
break;
238 case MaterialDataType::UInt3:
return "vec3u ";
break;
239 case MaterialDataType::UInt4:
return "vec4u ";
break;
240 case MaterialDataType::Bool:
return "bool ";
break;
241 case MaterialDataType::SV_IsFrontFace:
return "bool ";
break;
242 case MaterialDataType::VFACE:
return "f32 ";
break;
243 case MaterialDataType::Position:
return "vec4f ";
break;
245 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
251 void createTextureBindings(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
252 if (bindingGroups.empty()) {
253 bindingGroups.emplace_back();
255 WebGPUBindingGroup& locations = bindingGroups[0];
257 for (
auto& texture : materialDefinition.properties.textures) {
258 if (!hasBinding(bindingGroups, texture.name)) {
259 std::string name = texture.name;
260 locations.emplace_back(locations.size(), name, texture.dimensions);
261 locations.emplace_back(locations.size(), name +
"Sampler", texture.dimensions, texture.isDepth);
266 void createEngineTextureBindings(WebGPUBindingGroupVector& bindingGroups) {
267 if (bindingGroups.empty()) {
268 bindingGroups.emplace_back();
270 WebGPUBindingGroup& locations = bindingGroups[0];
272 for (
auto& tex : engineTextures) {
273 if (!hasBinding(bindingGroups, tex.name)) {
274 std::string name = tex.name;
275 locations.emplace_back(locations.size(), name, tex.dimensions, tex.isDepthTexture);
276 locations.emplace_back(locations.size(), name +
"Sampler", tex.dimensions, tex.isDepthTexture);
281 void addEffectDefinesAndStuff(std::string& output,
const std::vector<std::pair<std::string, std::string>>& definitions, uint32_t multiViewCount) {
282 if (multiViewCount) {
283 std::string multiViewCountString = std::to_string(multiViewCount);
284 output.append(
"#extension GL_OVR_multiview : require\nlayout(num_views=");
285 output.append(multiViewCountString);
286 output.append(
") in;\n");
287 output.append(
"#define COGS_MULTIVIEW ");
288 output.append(multiViewCountString);
292 std::unordered_set<std::string> addedDefines;
294 for (
const std::pair<std::string, std::string>& define : definitions) {
295 if (addedDefines.contains(define.first)) {
298 output.append(
"#define ");
299 output.append(define.first);
301 output.append(define.second);
303 addedDefines.insert(define.first);
309 BuiltinAttributeDescription desc;
310 desc.stage = ShaderInterface::None;
311 for (
const auto& builtin : builtinDataTypes)
313 if (builtin.type == attribute.type) {
317 for (
const auto& attr : builtinAttributes) {
318 if (attr.semanticName == attribute.semantic.name) {
325 void addInterfaceStruct(std::string& defines, std::string& source, std::string_view name,
const ShaderInterfaceDefinition& iface, ShaderInterface shaderInterface)
328 source.append(
"struct ");
330 source.append(
" {\n");
332 if (shaderInterface & ShaderInterface::VertexOut) {
333 source.append(
" @builtin(position) Position: vec4f,\n");
335 for (
const auto& attribute : iface.members) {
336 BuiltinAttributeDescription builtinAttributeDescription = getBuiltinAttributeDescription(attribute);
337 if (shaderInterface & ShaderInterface::VertexOut &&
338 (builtinAttributeDescription.stage & ShaderInterface::FragmentIn) != 0) {
341 if (shaderInterface & ShaderInterface::FragmentIn && attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::None && attribute.type == MaterialDataType::Position) {
345 if ((builtinAttributeDescription.stage & shaderInterface) != 0) {
346 source.append(
" @builtin(" + builtinAttributeDescription.builtinName +
") ");
347 source.append(attribute.name);
348 source.append(
" : ");
349 source.append(attributeVaryingType(builtinAttributeDescription.type));
350 source.append(
",\n");
353 if (shaderInterface & ShaderInterface::VertexIn) {
354 size_t nameInd = size_t (attribute.semantic.name) - 1;
355 std::string_view semanticName = getSemanticName(nameInd);
356 if (!semanticName.empty()) {
357 if(attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::InstanceMatrix){
358 std::string defineName;
359 defineName.append(semanticName);
360 int loc = attribute.semantic.slot;
361 defineName.append(std::to_string(loc) +
"_LOC");
362 defines.append(
"#define ");
363 defines.append(defineName +
" " + std::to_string(next_loc) +
"\n");
365 for(
int i=0; i<4; i++){
366 source.append(
" @location(" + defineName +
" + " + std::to_string(i) +
") ");
367 source.append(attribute.name +
"_" + std::to_string(i));
368 source.append(
" : vec4f,\n");
373 std::string defineName;
374 defineName.append(semanticName);
375 defineName.append(std::to_string(attribute.semantic.slot) +
"_LOC");
376 defines.append(
"#define ");
377 defines.append(defineName +
" " + std::to_string(next_loc++) +
"\n");
378 source.append(
" @location(" + defineName +
") ");
379 source.append(attribute.name);
380 source.append(
" : ");
381 source.append(attributeVaryingType(attribute.type));
382 source.append(
",\n");
387 source.append(
" @location(" + std::to_string(next_loc++) +
") ");
388 source.append(attribute.name);
389 source.append(
" : ");
390 source.append(attributeVaryingType(attribute.type));
391 source.append(
",\n");
395 source.append(
"};\n\n");
400 shaderSource.append(
"fn create");
401 shaderSource.append(name);
402 shaderSource.append(
"() -> ");
403 shaderSource.append(name);
404 shaderSource.append(
" {\n");
405 shaderSource.append(
" var t : ");
406 shaderSource.append(name);
407 shaderSource.append(
";\n");
408 for (
const auto& attribute : iface.members) {
409 const char* initializer =
nullptr;
410 switch (attribute.type) {
411 case MaterialDataType::Float: initializer =
"0.0;\n";
break;
412 case MaterialDataType::Float2: initializer =
"vec2f(0);\n";
break;
413 case MaterialDataType::Float3: initializer =
"vec3f(0);\n";
break;
414 case MaterialDataType::Float4: initializer =
"vec4f(0);\n";
break;
415 case MaterialDataType::Float4x4: initializer =
"mat4x4f(0);\n";
break;
420 shaderSource.append(
" t.");
421 shaderSource.append(attribute.name);
422 shaderSource.append(
" = ");
423 shaderSource.append(initializer);
426 shaderSource.append(
" return t;\n}\n\n");
429 void addUniform(std::string& shaderSource, WebGPUBindingGroupVector& bindingGroups, std::string_view name, std::string_view type,
bool useTemplate =
false) {
430 WebGPUBindingGroup& bindings = bindingGroups[0];
431 WebGPULocation location;
432 for (
const WebGPULocation& curr_location : bindings) {
433 if (curr_location.name == name) {
434 location = curr_location;
438 if (location.name != name) {
439 LOG_WARNING(logger,
"adding to bindgroup %s", std::string(name).c_str());
440 location = WebGPULocation(bindings.size(), std::string(name));
441 bindings.push_back(location);
443 shaderSource.append(
"@group(");
444 shaderSource.append(std::to_string(0));
445 shaderSource.append(
") @binding(");
446 shaderSource.append(std::to_string(location.location));
447 shaderSource.append(
") var");
449 shaderSource.append(
"<uniform>");
451 shaderSource.append(
" ");
452 shaderSource.append(name);
453 shaderSource.append(
" : ");
454 shaderSource.append(type);
455 shaderSource.append(
";\n");
458 void addUniformBuffer(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
const ConstantBufferDefinition& definition, WebGPUBindingGroupVector& bindingGroups)
460 if (!identifiersSeen.contains(Strings::add(definition.name))) {
463 if (definition.values.empty())
return;
464 shaderSource.append(
"struct ");
465 shaderSource.append(definition.name);
466 shaderSource.append(
"_t {\n");
468 shaderSource.append(member.name);
469 shaderSource.append(
" : ");
471 switch (member.type) {
472 case MaterialDataType::Float: shaderSource.append(
"f32");
break;
473 case MaterialDataType::Float2: shaderSource.append(
"vec2f");
break;
474 case MaterialDataType::Float3: shaderSource.append(
"vec3f");
break;
475 case MaterialDataType::Float4Array:
476 shaderSource.append(
"array<vec4f, " + std::to_string(member.dimension) +
">");
477 assert(member.dimension !=
static_cast<size_t>(-1));
479 case MaterialDataType::Float4: shaderSource.append(
"vec4f");
break;
480 case MaterialDataType::Float4x4Array:
481 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f");
break;
482 case MaterialDataType::Int: shaderSource.append(
"i32");
break;
483 case MaterialDataType::Int2: shaderSource.append(
"vec2i");
break;
484 case MaterialDataType::Int3: shaderSource.append(
"vec3i");
break;
485 case MaterialDataType::Int4: shaderSource.append(
"vec4i");
break;
486 case MaterialDataType::UInt: shaderSource.append(
"u32");
break;
487 case MaterialDataType::UInt2: shaderSource.append(
"vec2u");
break;
488 case MaterialDataType::UInt3: shaderSource.append(
"vec3u");
break;
489 case MaterialDataType::UInt4: shaderSource.append(
"vec4u");
break;
490 case MaterialDataType::Bool: shaderSource.append(
"u32");
break;
492 LOG_ERROR(logger,
"Invalid type for buffer varable %s in buffer %s.", member.name.c_str(), definition.name.c_str());
493 shaderSource.append(
"<invalid type>");
496 shaderSource.append(
",\n");
498 shaderSource.append(
"};\n");
500 addUniform(shaderSource, bindingGroups, definition.name, definition.name +
"_t",
true);
503 void addEngineBuffers(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups) {
504 for (
const std::string& name : optionalEngineBuffers) {
506 if (identifiersSeen.contains(Strings::add(name))){
509 if (name ==
"SceneBuffer") {
510 const char *getters[] = {
511 "getClipFromViewMatrix",
512 "getClipFromWorldMatrix",
513 "getViewFromWorldMatrix",
514 "getViewFromClipMatrix",
515 "getWorldFromViewMatrix",
516 "getViewFromViewportMatrix",
517 "getPeriodicWorldPosAndCell",
518 "getPeriodicWorldPos"
520 for(
auto &get : getters){
521 if (identifiersSeen.contains(Strings::add(get))){
527 addUniform(shaderSource, bindingGroups, name, name +
"_t",
true);
528 if (name ==
"SceneBuffer") {
529 shaderSource.append(
"#define COGS_VIEWGETTERS_REFERENCED 1\n");
537 shaderSource.append(
"fn transferAttributes(vertexIn : VertexIn, vertexOut : ptr<function, VertexOut>) {\n");
539 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
541 if (dMember.name == member.name) {
542 shaderSource.append(
" (*vertexOut).");
543 shaderSource.append(member.name);
544 shaderSource.append(
" = ");
545 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
546 shaderSource.append(
"octDecode(vertexIn.");
547 shaderSource.append(member.name);
548 shaderSource.append(
"); \n");
551 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
552 shaderSource.append(
"vec4f(vertexIn.");
553 shaderSource.append(member.name);
554 shaderSource.append(
", 1.0);\n");
557 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
558 shaderSource.append(
"vec4f(vertexIn.");
559 shaderSource.append(member.name);
560 shaderSource.append(
", 0.0, 1.0);\n");
564 if (dMember.type != member.type) {
565 switch (dMember.type) {
566 case MaterialDataType::Float: shaderSource.append(
"f32("); close =
true;
break;
567 case MaterialDataType::Float2: shaderSource.append(
"vec2f("); close =
true;
break;
568 case MaterialDataType::Float3: shaderSource.append(
"vec3f("); close =
true;
break;
569 case MaterialDataType::Float4: shaderSource.append(
"vec4f("); close =
true;
break;
570 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f("); close =
true;
break;
571 case MaterialDataType::Int: shaderSource.append(
"i32("); close =
true;
break;
572 case MaterialDataType::Int2: shaderSource.append(
"vec2i("); close =
true;
break;
573 case MaterialDataType::Int3: shaderSource.append(
"vec3i("); close =
true;
break;
574 case MaterialDataType::Int4: shaderSource.append(
"vec4i("); close =
true;
break;
575 case MaterialDataType::UInt: shaderSource.append(
"u32("); close =
true;
break;
576 case MaterialDataType::UInt2: shaderSource.append(
"vec2u("); close =
true;
break;
577 case MaterialDataType::UInt3: shaderSource.append(
"vec3u("); close =
true;
break;
578 case MaterialDataType::UInt4: shaderSource.append(
"vec4u("); close =
true;
break;
583 if (dMember.type == member.type) {
584 shaderSource.append(
"vertexIn.");
585 shaderSource.append(member.name);
588 LOG_WARNING(logger,
"%s Skip transfer of %s. (Different types).", sourceDefinition.loadPath.c_str(), member.name.c_str());
590 if (close) shaderSource.append(1,
')');
591 shaderSource.append(
";\n");
596 shaderSource.append(
"}\n");
599 bool addOutputStruct(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly) {
600 bool outputDepth =
false;
601 bool hasColorAttachments = !outputDefinition.empty() && !depthOnly;
603 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
604 auto it = std::find_if(definitions.begin(), definitions.end(),
605 [&targetString](
const std::pair<std::string, std::string>& p){
606 return p.first == targetString;
609 if (it != definitions.end()) {
610 outputDepth = it->second !=
"0";
613 if (!outputDepth && !hasColorAttachments) {
617 source.append(
"struct FragmentOut {\n");
619 if (hasColorAttachments) {
620 for (
auto member : outputDefinition) {
621 source.append(
" @location(");
622 source.append(std::to_string(member.target));
624 source.append(member.name +
" : ");
626 switch (member.dataType) {
627 case MaterialDataType::Float: source.append(
"f32");
break;
628 case MaterialDataType::Float2: source.append(
"vec2f");
break;
629 case MaterialDataType::Float3: source.append(
"vec3f");
break;
630 case MaterialDataType::Float4: source.append(
"vec4f");
break;
631 case MaterialDataType::Float4x4: source.append(
"mat4x4f");
break;
632 case MaterialDataType::Int: source.append(
"i32");
break;
633 case MaterialDataType::Int2: source.append(
"vec2i");
break;
634 case MaterialDataType::Int3: source.append(
"vec3i");
break;
635 case MaterialDataType::Int4: source.append(
"vec4i");
break;
636 case MaterialDataType::UInt: source.append(
"u32");
break;
637 case MaterialDataType::UInt2: source.append(
"vec2u");
break;
638 case MaterialDataType::UInt3: source.append(
"vec3u");
break;
639 case MaterialDataType::UInt4: source.append(
"vec4u");
break;
643 source.append(
",\n");
647 source.append(
"@builtin(frag_depth) depth : f32\n");
649 source.append(
"};\n");
654 void addCallFunction(std::string& source, std::string_view name, std::string_view functionName, std::string_view inType, std::string_view outType) {
655 source.append(
"fn ");
657 source.append(
"(In : ");
658 source.append(inType);
659 source.append(
") ->");
660 source.append(outType);
661 source.append(
" { \n");
662 source.append(
" return ");
663 source.append(functionName);
664 source.append(
"(In);\n");
665 source.append(
"}\n\n");
672 case MaterialDataType::Unknown:
673 case MaterialDataType::Float:;
674 case MaterialDataType::Float2:
675 case MaterialDataType::Float3:
676 case MaterialDataType::Float4:
678 case MaterialDataType::Int:
679 case MaterialDataType::Int2:
680 case MaterialDataType::Int3:
681 case MaterialDataType::Int4:
683 case MaterialDataType::UInt:
684 case MaterialDataType::UInt2:
685 case MaterialDataType::UInt3:
686 case MaterialDataType::UInt4:
689 LOG_ERROR(logger,
"Unsupported texture datatype %d",
int(type));
696 void addTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups,
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 addUniform(shaderSource, bindingGroups, texture.name, type);
738 std::string samplerName = texture.name +
"Sampler";
739 if (identifiersSeen.contains(Strings::add(samplerName)) && !ignoreIdentifiersSeen) {
740 addUniform(shaderSource, bindingGroups, samplerName, samplerType);
745 void addEngineTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups)
747 for (
auto& texture : engineTextures) {
748 if (!identifiersSeen.contains(Strings::add(texture.name))) {
753 std::string samplerType =
"sampler";
756 if (texture.isDepthTexture) {
758 samplerType +=
"_comparison";
761 switch (texture.dimensions) {
762 case TextureDimensions::Texture2D:
765 case TextureDimensions::TexureCube:
768 case TextureDimensions::Texture2DArray:
771 case TextureDimensions::Texture3D:
775 LOG_ERROR(logger,
"Unsupported texture type %d",
int(texture.dimensions));
778 if (!texture.isDepthTexture) {
781 addUniform(shaderSource, bindingGroups, texture.name, type);
782 addUniform(shaderSource, bindingGroups, texture.name +
"Sampler", samplerType);
787 out.members.reserve(a.members.size() + b.members.size());
789 for (
auto member : b.members) {
791 for (
auto existingMember : a.members) {
792 if (member.name == existingMember.name) {
798 out.members.push_back(member);
804bool Cogs::Core::buildEffectWebGPU(
Context* context,
805 std::vector<std::pair<std::string, std::string>>& definitions,
808 const uint32_t multiViewCount)
810 if (!materialDefinition.effect.geometryShader.entryPoint.empty()) {
811 LOG_ERROR(logger,
"%s: Geometry shader not allowed in WebGPU.", materialDefinition.name.c_str());
814 if (!materialDefinition.effect.hullShader.entryPoint.empty()) {
815 LOG_ERROR(logger,
"%s: Hull shader not allowed in WebGPU.", materialDefinition.name.c_str());
818 if (!materialDefinition.effect.domainShader.entryPoint.empty()) {
819 LOG_ERROR(logger,
"%s: Domain shader not allowed in WebGPU.", materialDefinition.name.c_str());
822 if (!materialDefinition.effect.computeShader.entryPoint.empty()) {
823 LOG_ERROR(logger,
"%s: Compute shader not allowed in WebGPU.", materialDefinition.name.c_str());
827 changeSuffix(materialDefinition.effect.vertexShader.customSourcePath,
".hlsl",
".wgsl");
828 changeSuffix(materialDefinition.effect.pixelShader.customSourcePath,
".hlsl",
".wgsl");
829 std::string prefix =
"" + materialDefinition.name;
831 WebGPUBindingGroupVector bindings;
832 createBufferBinding(bindings, materialDefinition);
833 createTextureBindings(bindings, materialDefinition);
834 createEngineTextureBindings(bindings);
838 std::string vs_header;
839 const std::string shaderName = prefix +
"VertexShader" + permutation.getDefinition()->name +
".wgsl";
840 addEffectDefinesAndStuff(vs_header, definitions, multiViewCount);
841 if (!pp.
process(context, vs_header))
return false;
849 concatUniqueMembers(materialDefinition.effect.vertexShader.shaderInterface, permutation.getDefinition()->vertexInterface, vertexInterface);
850 addInterfaceStruct(vs_header, vs_body,
"VertexIn", vertexInterface, ShaderInterface::VertexIn);
854 concatUniqueMembers(materialDefinition.effect.pixelShader.shaderInterface, permutation.getDefinition()->surfaceInterface, surfaceInterface);
855 addInterfaceStruct(vs_header, vs_body,
"VertexOut", surfaceInterface, ShaderInterface::VertexOut);
857 addInterfaceConstructor(vs_body,
"VertexOut", materialDefinition.effect.pixelShader.shaderInterface);
858 addTransferFunc(vs_body, materialDefinition.effect.vertexShader, materialDefinition.effect.pixelShader);
859 addInclude(vs_body, std::string_view(), materialDefinition.effect.vertexShader.customSourcePath);
860 std::string permutationVS = permutation.getDefinition()->vertexShader;
861 changeSuffix(permutationVS,
".hlsl",
".wgsl");
863 addCallFunction(vs_body,
"callMaterialVertexFunction",
864 materialDefinition.effect.vertexShader.entryPoint.empty() ?
"vertexFunction" : materialDefinition.effect.vertexShader.entryPoint,
865 "VertexIn",
"VertexOut");
866 addInclude(vs_body, std::string_view(),
"Engine/EngineVS.wgsl");
867 addCallFunction(vs_body,
"callVertexFunction",
869 "VertexIn",
"VertexOut");
870 addInclude(vs_body, std::string_view(), permutationVS);
871 if (!pp.
process(context, vs_body))
return false;
875 std::string vs_uniforms;
876 addTextures(vs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
885 addInclude(vs_uniforms, std::string_view(),
"Engine/Common.wgsl");
887 if (!pp.
process(context, vs_uniforms))
return false;
891 std::string all = vs_header + vs_uniforms + vs_body;
892 all = convertDefinesToConstExpressions(all);
894 std::string vspath =
"Shaders/" + shaderName;
899 std::string fs_header;
900 const std::string shaderName = prefix +
"PixelShader" + permutation.getDefinition()->name +
".wgsl";
901 addEffectDefinesAndStuff(fs_header, definitions, 0 );
904 bool fs_returnsStruct =
false;
907 surfaceInterface.members.insert(surfaceInterface.members.end(), permutation.getDefinition()->surfaceInterface.members.begin(),
908 permutation.getDefinition()->surfaceInterface.members.end());
909 addInterfaceStruct(fs_header, fs_body,
"VertexIn", surfaceInterface, ShaderInterface::FragmentIn);
910 fs_returnsStruct = addOutputStruct(fs_header, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly());
913 addInclude(fs_header, std::string_view(), materialDefinition.effect.pixelShader.customSourcePath);
914 std::string permutationFS = permutation.getDefinition()->pixelShader;
915 changeSuffix(permutationFS,
".hlsl",
".wgsl");
917 addCallFunction(fs_header,
"callMaterialSurfaceFunction",
918 materialDefinition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : materialDefinition.effect.pixelShader.entryPoint,
919 "VertexIn",
"SurfaceOut");
920 addInclude(fs_header, std::string_view(),
"Engine/EnginePS.wgsl");
921 addCallFunction(fs_header,
"callSurfaceFunction",
923 "VertexIn",
"SurfaceOut");
924 addInclude(fs_header, std::string_view(), permutationFS);
925 if (fs_returnsStruct) {
929fn main(In : VertexIn) -> FragmentOut {
930 return permutationMain(In);
937fn main(In : VertexIn) {
943 if (!pp.
process(context, fs_header))
return false;
947 std::string fs_uniforms;
948 fs_uniforms.reserve(InitialBufferCapasity);
949 addTextures(fs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
958 addInclude(fs_uniforms, std::string_view(),
"Engine/Common.wgsl");
959 if (!pp.
process(context, fs_uniforms))
return false;
963 std::string all = fs_header + fs_uniforms + fs_body;
964 all = convertDefinesToConstExpressions(all);
966 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.