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"
19 constexpr size_t InitialBufferCapasity = 4096u;
21 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];
45 enum ShaderInterface { None = 0, VertexIn = 1, VertexOut = 2, FragmentIn = 4, FragmentOut = 8 };
47 struct BuiltinAttributeDescription {
48 std::string builtinName;
50 ShaderInterface stage = ShaderInterface::None;
53 struct BuiltinAttributes {
54 ShaderInterfaceMemberDefinition::SemanticName semanticName;
55 BuiltinAttributeDescription desc;
58 const std::array<BuiltinAttributes, 5> builtinAttributes{
59 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
60 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID, {
"vertex_index", MaterialDataType::UInt, ShaderInterface::VertexIn}},
61 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
62 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
63 BuiltinAttributes{ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
66 struct BuiltinDataType {
68 BuiltinAttributeDescription desc;
71 const std::array builtinDataTypes {
72 BuiltinDataType{MaterialDataType::SV_InstanceID, {
"instance_index", MaterialDataType::UInt, ShaderInterface::VertexIn} },
73 BuiltinDataType{MaterialDataType::Position, {
"position", MaterialDataType::Float4, ShaderInterface(ShaderInterface::VertexOut | ShaderInterface::FragmentIn)}},
75 BuiltinDataType{MaterialDataType::Position, {
"position", MaterialDataType::Float4, ShaderInterface::FragmentIn} },
76 BuiltinDataType{MaterialDataType::SV_IsFrontFace, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn} },
77 BuiltinDataType{MaterialDataType::VFACE, {
"front_facing", MaterialDataType::Bool, ShaderInterface::FragmentIn}},
80 const std::array requiredEngineBuffers = {
86 const std::array optionalEngineBuffers = {
91 struct EngineTexture {
94 bool isDepthTexture =
false;
97 const std::array engineTextures = {
98 EngineTexture{.name =
"environmentSky", .dimensions = TextureDimensions::TexureCube},
99 EngineTexture{.name =
"environmentRadiance", .dimensions = TextureDimensions::TexureCube},
100 EngineTexture{.name =
"environmentIrradiance", .dimensions = TextureDimensions::TexureCube},
101 EngineTexture{.name =
"ambientIrradiance", .dimensions = TextureDimensions::TexureCube},
102 EngineTexture{.name =
"brdfLUT", .dimensions = TextureDimensions::Texture2D},
103 EngineTexture{.name =
"cascadedShadowMap", .dimensions = TextureDimensions::Texture2DArray, .isDepthTexture =
true},
104 EngineTexture{.name =
"cubeShadowMap", .dimensions = TextureDimensions::TexureCube, .isDepthTexture =
true},
107 struct WebGPULocation {
111 bool isDepthTexture =
false;
112 WebGPULocation(
size_t location,
const std::string &name,
Cogs::Core::TextureDimensions dimensions = Cogs::Core::TextureDimensions::Texture2D,
bool isDepthTexture =
false) :
113 location(location), name(name), dimensions(dimensions), isDepthTexture(isDepthTexture) { }
114 WebGPULocation() =
default;
118 using WebGPUBindingGroup = std::vector<WebGPULocation>;
119 using WebGPUBindingGroupVector = std::vector<WebGPUBindingGroup>;
122 bool hasBinding(
const WebGPUBindingGroupVector& bindingGroups, std::string_view name) {
123 for (
const WebGPUBindingGroup& bindings : bindingGroups) {
124 for (
const WebGPULocation& location : bindings) {
125 if (location.name == name) {
133 void createBufferBinding(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
134 if (bindingGroups.empty()) {
135 bindingGroups.emplace_back();
137 WebGPUBindingGroup& locations = bindingGroups[0];
138 locations.emplace_back(0,
"BLOCKED");
139 for (
auto& buffer : requiredEngineBuffers) {
140 WebGPULocation loc(locations.size(), buffer);
141 locations.push_back(loc);
144 for (
auto& buffer : optionalEngineBuffers) {
145 locations.emplace_back(locations.size(), buffer);
149 for (
auto& buffer : materialDefinition.properties.buffers) {
150 if (std::find(std::begin(requiredEngineBuffers), std::end(requiredEngineBuffers), buffer.name) == std::end(requiredEngineBuffers)) {
151 if (!hasBinding(bindingGroups, buffer.name)) {
152 locations.emplace_back(locations.size(), buffer.name);
159 std::string convertDefinesToConstExpressions(
const std::string& s) {
160 std::map<std::string, std::string> addedDefines;
162 result.reserve(s.size());
164 std::istringstream iss(s);
166 std::regex e1(
"^\\s*#define\\s+([^\\s]+)\\s+([^\\s]+)");
167 std::regex e2(
"^\\s*#define\\s+([^\\s]+)\\s*$");
168 std::string identifier;
169 std::string replacement;
170 for (std::string line; std::getline(iss, line); )
176 if (std::regex_search(line, match, e1))
178 identifier += match.str(1);
179 replacement += match.str(2);
181 else if (std::regex_search(line, match, e2)) {
182 identifier += match.str(1);
185 if (identifier.empty()) {
186 result += line +
"\n";
189 auto it = addedDefines.find(identifier);
190 if (it != addedDefines.end()) {
191 if (replacement != (*it).second) {
192 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());
196 result +=
"const " + identifier +
" = " + replacement +
";\n";
197 addedDefines.try_emplace(identifier, replacement);
202 void addInclude(std::string& content, std::string_view prefix, std::string_view path)
204 content.append(
"#include \"");
205 content.append(prefix);
206 content.append(path);
207 content.append(
"\"\n");
210 void changeSuffix(std::string& dst, std::string_view from, std::string_view to)
212 if (dst.ends_with(from)) {
213 dst.replace(dst.size() - from.length(), from.length(), to);
221 case MaterialDataType::Float:
return "f32 ";
break;
222 case MaterialDataType::Float2:
return "vec2f ";
break;
223 case MaterialDataType::Float3:
return "vec3f ";
break;
224 case MaterialDataType::Float4:
return "vec4f ";
break;
225 case MaterialDataType::Float4x4:
return "mat4x4f ";
break;
226 case MaterialDataType::Int:
return "i32 ";
break;
227 case MaterialDataType::Int2:
return "vec4i ";
break;
228 case MaterialDataType::Int3:
return "vec3i ";
break;
229 case MaterialDataType::Int4:
return "vec4i ";
break;
230 case MaterialDataType::UInt:
return "u32 ";
break;
231 case MaterialDataType::UInt2:
return "vec4u ";
break;
232 case MaterialDataType::UInt3:
return "vec3u ";
break;
233 case MaterialDataType::UInt4:
return "vec4u ";
break;
234 case MaterialDataType::Bool:
return "bool ";
break;
235 case MaterialDataType::SV_IsFrontFace:
return "bool ";
break;
236 case MaterialDataType::VFACE:
return "f32 ";
break;
237 case MaterialDataType::Position:
return "vec4f ";
break;
239 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
245 void createTextureBindings(WebGPUBindingGroupVector& bindingGroups,
const MaterialDefinition& materialDefinition) {
246 if (bindingGroups.empty()) {
247 bindingGroups.emplace_back();
249 WebGPUBindingGroup& locations = bindingGroups[0];
251 for (
auto& texture : materialDefinition.properties.textures) {
252 if (!hasBinding(bindingGroups, texture.name)) {
253 std::string name = texture.name;
254 locations.emplace_back(locations.size(), name, texture.dimensions);
255 locations.emplace_back(locations.size(), name +
"Sampler", texture.dimensions);
260 void createEngineTextureBindings(WebGPUBindingGroupVector& bindingGroups) {
261 if (bindingGroups.empty()) {
262 bindingGroups.emplace_back();
264 WebGPUBindingGroup& locations = bindingGroups[0];
266 for (
auto& tex : engineTextures) {
267 if (!hasBinding(bindingGroups, tex.name)) {
268 std::string name = tex.name;
269 locations.emplace_back(locations.size(), name, tex.dimensions, tex.isDepthTexture);
270 locations.emplace_back(locations.size(), name +
"Sampler", tex.dimensions, tex.isDepthTexture);
275 void addEffectDefinesAndStuff(std::string& output,
const std::vector<std::pair<std::string, std::string>>& definitions, uint32_t multiViewCount) {
276 if (multiViewCount) {
277 std::string multiViewCountString = std::to_string(multiViewCount);
278 output.append(
"#extension GL_OVR_multiview : require\nlayout(num_views=");
279 output.append(multiViewCountString);
280 output.append(
") in;\n");
281 output.append(
"#define COGS_MULTIVIEW ");
282 output.append(multiViewCountString);
286 std::unordered_set<std::string> addedDefines;
288 for (
const std::pair<std::string, std::string>& define : definitions) {
289 if (addedDefines.contains(define.first)) {
292 output.append(
"#define ");
293 output.append(define.first);
295 output.append(define.second);
297 addedDefines.insert(define.first);
303 BuiltinAttributeDescription desc;
304 desc.stage = ShaderInterface::None;
305 for (
const auto& builtin : builtinDataTypes)
307 if (builtin.type == attribute.type) {
311 for (
const auto& attr : builtinAttributes) {
312 if (attr.semanticName == attribute.semantic.name) {
319 void addInterfaceStruct(std::string& defines, std::string& source, std::string_view name,
const ShaderInterfaceDefinition& iface, ShaderInterface shaderInterface)
322 source.append(
"struct ");
324 source.append(
" {\n");
326 if (shaderInterface & ShaderInterface::VertexOut) {
327 source.append(
" @builtin(position) Position: vec4f,\n");
329 for (
const auto& attribute : iface.members) {
330 BuiltinAttributeDescription builtinAttributeDescription = getBuiltinAttributeDescription(attribute);
331 if (shaderInterface & ShaderInterface::VertexOut &&
332 (builtinAttributeDescription.stage & ShaderInterface::FragmentIn) != 0) {
335 if (shaderInterface & ShaderInterface::FragmentIn && attribute.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::None && attribute.type == MaterialDataType::Position) {
339 if ((builtinAttributeDescription.stage & shaderInterface) != 0) {
340 source.append(
" @builtin(" + builtinAttributeDescription.builtinName +
") ");
341 source.append(attribute.name);
342 source.append(
" : ");
343 source.append(attributeVaryingType(builtinAttributeDescription.type));
344 source.append(
",\n");
347 if (shaderInterface & ShaderInterface::VertexIn) {
348 defines.append(
"#define ");
349 size_t nameInd = size_t (attribute.semantic.name) - 1;
350 std::string_view semanticName = getSemanticName(nameInd);
351 if (!semanticName.empty()) {
352 std::string defineName;
353 defineName.append(semanticName);
354 defineName.append(std::to_string(attribute.semantic.slot) +
"_LOC");
355 defines.append(defineName +
" " + std::to_string(next_loc++) +
"\n");
356 source.append(
" @location(" + defineName +
") ");
360 source.append(
" @location(" + std::to_string(next_loc++) +
") ");
362 source.append(attribute.name);
363 source.append(
" : ");
364 if (attribute.type == MaterialDataType::UInt4) {
365 source.append(
"vec4u");
368 source.append(attributeVaryingType(attribute.type));
370 source.append(
",\n");
373 source.append(
"};\n\n");
378 shaderSource.append(
"fn create");
379 shaderSource.append(name);
380 shaderSource.append(
"() -> ");
381 shaderSource.append(name);
382 shaderSource.append(
" {\n");
383 shaderSource.append(
" var t : ");
384 shaderSource.append(name);
385 shaderSource.append(
";\n");
386 for (
const auto& attribute : iface.members) {
387 const char* initializer =
nullptr;
388 switch (attribute.type) {
389 case MaterialDataType::Float: initializer =
"0.0;\n";
break;
390 case MaterialDataType::Float2: initializer =
"vec2f(0);\n";
break;
391 case MaterialDataType::Float3: initializer =
"vec3f(0);\n";
break;
392 case MaterialDataType::Float4: initializer =
"vec4f(0);\n";
break;
393 case MaterialDataType::Float4x4: initializer =
"mat4x4f(0);\n";
break;
398 shaderSource.append(
" t.");
399 shaderSource.append(attribute.name);
400 shaderSource.append(
" = ");
401 shaderSource.append(initializer);
404 shaderSource.append(
" return t;\n}\n\n");
407 void addUniform(std::string& shaderSource, WebGPUBindingGroupVector& bindingGroups, std::string_view name, std::string_view type,
bool useTemplate =
false) {
408 WebGPUBindingGroup& bindings = bindingGroups[0];
409 WebGPULocation location;
410 for (
const WebGPULocation& curr_location : bindings) {
411 if (curr_location.name == name) {
412 location = curr_location;
416 if (location.name != name) {
417 LOG_WARNING(logger,
"adding to bindgroup %s", std::string(name).c_str());
418 location = WebGPULocation(bindings.size(), std::string(name));
419 bindings.push_back(location);
421 shaderSource.append(
"@group(");
422 shaderSource.append(std::to_string(0));
423 shaderSource.append(
") @binding(");
424 shaderSource.append(std::to_string(location.location));
425 shaderSource.append(
") var");
427 shaderSource.append(
"<uniform>");
429 shaderSource.append(
" ");
430 shaderSource.append(name);
431 shaderSource.append(
" : ");
432 shaderSource.append(type);
433 shaderSource.append(
";\n");
436 void addUniformBuffer(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
const ConstantBufferDefinition& definition, WebGPUBindingGroupVector& bindingGroups)
438 if (!identifiersSeen.contains(Strings::add(definition.name))) {
441 if (definition.values.empty())
return;
442 shaderSource.append(
"struct ");
443 shaderSource.append(definition.name);
444 shaderSource.append(
"_t {\n");
446 shaderSource.append(member.name);
447 shaderSource.append(
" : ");
449 switch (member.type) {
450 case MaterialDataType::Float: shaderSource.append(
"f32");
break;
451 case MaterialDataType::Float2: shaderSource.append(
"vec2f");
break;
452 case MaterialDataType::Float3: shaderSource.append(
"vec3f");
break;
453 case MaterialDataType::Float4Array:
454 shaderSource.append(
"array<vec4f, " + std::to_string(member.dimension) +
">");
455 assert(member.dimension !=
static_cast<size_t>(-1));
457 case MaterialDataType::Float4: shaderSource.append(
"vec4f");
break;
458 case MaterialDataType::Float4x4Array:
459 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f");
break;
460 case MaterialDataType::Int: shaderSource.append(
"i32");
break;
461 case MaterialDataType::Int2: shaderSource.append(
"vec2i");
break;
462 case MaterialDataType::Int3: shaderSource.append(
"vec3i");
break;
463 case MaterialDataType::Int4: shaderSource.append(
"vec4i");
break;
464 case MaterialDataType::UInt: shaderSource.append(
"u32");
break;
465 case MaterialDataType::UInt2: shaderSource.append(
"vec2u");
break;
466 case MaterialDataType::UInt3: shaderSource.append(
"vec3u");
break;
467 case MaterialDataType::UInt4: shaderSource.append(
"vec4u");
break;
468 case MaterialDataType::Bool: shaderSource.append(
"u32");
break;
470 LOG_ERROR(logger,
"Invalid type for buffer varable %s in buffer %s.", member.name.c_str(), definition.name.c_str());
471 shaderSource.append(
"<invalid type>");
474 shaderSource.append(
",\n");
476 shaderSource.append(
"};\n");
478 addUniform(shaderSource, bindingGroups, definition.name, definition.name +
"_t",
true);
481 void addEngineBuffers(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups) {
482 for (
const std::string& name : requiredEngineBuffers) {
483 addUniform(shaderSource, bindingGroups, name, name +
"_t",
true);
484 if (name ==
"SceneBuffer") {
485 shaderSource.append(
"#define COGS_VIEWGETTERS_REFERENCED 1\n");
488 for (
const std::string& name : optionalEngineBuffers) {
490 if (identifiersSeen.contains(Strings::add(name))) {
491 addUniform(shaderSource, bindingGroups, name, name +
"_t",
true);
498 shaderSource.append(
"fn transferAttributes(vertexIn : VertexIn, vertexOut : ptr<function, VertexOut>) {\n");
500 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
502 if (dMember.name == member.name) {
503 shaderSource.append(
" (*vertexOut).");
504 shaderSource.append(member.name);
505 shaderSource.append(
" = ");
506 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
507 shaderSource.append(
"octDecode(vertexIn.");
508 shaderSource.append(member.name);
509 shaderSource.append(
"); \n");
512 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
513 shaderSource.append(
"vec4f(vertexIn.");
514 shaderSource.append(member.name);
515 shaderSource.append(
", 1.0);\n");
518 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
519 shaderSource.append(
"vec4f(vertexIn.");
520 shaderSource.append(member.name);
521 shaderSource.append(
", 0.0, 1.0);\n");
525 if (dMember.type != member.type) {
526 switch (dMember.type) {
527 case MaterialDataType::Float: shaderSource.append(
"f32("); close =
true;
break;
528 case MaterialDataType::Float2: shaderSource.append(
"vec2f("); close =
true;
break;
529 case MaterialDataType::Float3: shaderSource.append(
"vec3f("); close =
true;
break;
530 case MaterialDataType::Float4: shaderSource.append(
"vec4f("); close =
true;
break;
531 case MaterialDataType::Float4x4: shaderSource.append(
"mat4x4f("); close =
true;
break;
532 case MaterialDataType::Int: shaderSource.append(
"i32("); close =
true;
break;
533 case MaterialDataType::Int2: shaderSource.append(
"vec2i("); close =
true;
break;
534 case MaterialDataType::Int3: shaderSource.append(
"vec3i("); close =
true;
break;
535 case MaterialDataType::Int4: shaderSource.append(
"vec4i("); close =
true;
break;
536 case MaterialDataType::UInt: shaderSource.append(
"u32("); close =
true;
break;
537 case MaterialDataType::UInt2: shaderSource.append(
"vec2u("); close =
true;
break;
538 case MaterialDataType::UInt3: shaderSource.append(
"vec3u("); close =
true;
break;
539 case MaterialDataType::UInt4: shaderSource.append(
"vec4u("); close =
true;
break;
544 shaderSource.append(
"vertexIn.");
545 shaderSource.append(member.name);
546 if (close) shaderSource.append(1,
')');
547 shaderSource.append(
";\n");
552 shaderSource.append(
"}\n");
555 bool addOutputStruct(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly) {
556 bool outputDepth =
false;
557 bool hasColorAttachments = !outputDefinition.empty() && !depthOnly;
559 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
560 auto it = std::find_if(definitions.begin(), definitions.end(),
561 [&targetString](
const std::pair<std::string, std::string>& p){
562 return p.first == targetString;
565 if (it != definitions.end()) {
566 outputDepth = it->second !=
"0";
569 if (!outputDepth && !hasColorAttachments) {
573 source.append(
"struct FragmentOut {\n");
575 if (hasColorAttachments) {
576 for (
auto member : outputDefinition) {
577 source.append(
" @location(");
578 source.append(std::to_string(member.target));
580 source.append(member.name +
" : ");
582 switch (member.dataType) {
583 case MaterialDataType::Float: source.append(
"f32");
break;
584 case MaterialDataType::Float2: source.append(
"vec2f");
break;
585 case MaterialDataType::Float3: source.append(
"vec3f");
break;
586 case MaterialDataType::Float4: source.append(
"vec4f");
break;
587 case MaterialDataType::Float4x4: source.append(
"mat4x4f");
break;
588 case MaterialDataType::Int: source.append(
"i32");
break;
589 case MaterialDataType::Int2: source.append(
"vec2i");
break;
590 case MaterialDataType::Int3: source.append(
"vec3i");
break;
591 case MaterialDataType::Int4: source.append(
"vec4i");
break;
592 case MaterialDataType::UInt: source.append(
"u32");
break;
593 case MaterialDataType::UInt2: source.append(
"vec2u");
break;
594 case MaterialDataType::UInt3: source.append(
"vec3u");
break;
595 case MaterialDataType::UInt4: source.append(
"vec4u");
break;
599 source.append(
",\n");
603 source.append(
"@builtin(frag_depth) depth : f32\n");
605 source.append(
"};\n");
610 void addCallFunction(std::string& source, std::string_view name, std::string_view functionName, std::string_view inType, std::string_view outType) {
611 source.append(
"fn ");
613 source.append(
"(In : ");
614 source.append(inType);
615 source.append(
") ->");
616 source.append(outType);
617 source.append(
" { \n");
618 source.append(
" return ");
619 source.append(functionName);
620 source.append(
"(In);\n");
621 source.append(
"}\n\n");
628 case MaterialDataType::Unknown:
629 case MaterialDataType::Float:;
630 case MaterialDataType::Float2:
631 case MaterialDataType::Float3:
632 case MaterialDataType::Float4:
634 case MaterialDataType::Int:
635 case MaterialDataType::Int2:
636 case MaterialDataType::Int3:
637 case MaterialDataType::Int4:
639 case MaterialDataType::UInt:
640 case MaterialDataType::UInt2:
641 case MaterialDataType::UInt3:
642 case MaterialDataType::UInt4:
645 LOG_ERROR(logger,
"Unsupported texture datatype %d",
int(type));
652 void addTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups,
const std::vector<MaterialTextureDefinition>& definition,
bool ignoreIdentifiersSeen =
false)
654 for (
auto& texture : definition) {
655 if (!identifiersSeen.contains(Strings::add(texture.name)) && !ignoreIdentifiersSeen) {
659 std::string dataType = textureDataType(texture.format);
661 switch (texture.dimensions) {
662 case TextureDimensions::Texture2D:
663 type +=
"_2d<" + dataType +
">";
665 case TextureDimensions::TexureCube:
666 type +=
"_cube<" + dataType +
">";
668 case TextureDimensions::Texture2DArray:
669 type +=
"_2d_array<" + dataType +
">";
671 case TextureDimensions::Texture3D:
672 type +=
"_3d<" + dataType +
">";
675 LOG_ERROR(logger,
"Unsupported texture type %d",
int(texture.dimensions));
678 addUniform(shaderSource, bindingGroups, texture.name, type);
679 std::string samplerName = texture.name +
"Sampler";
680 if (identifiersSeen.contains(Strings::add(samplerName)) && !ignoreIdentifiersSeen) {
681 addUniform(shaderSource, bindingGroups, samplerName,
"sampler");;
686 void addEngineTextures(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen, WebGPUBindingGroupVector& bindingGroups)
688 for (
auto& texture : engineTextures) {
689 if (!identifiersSeen.contains(Strings::add(texture.name))) {
694 std::string samplerType =
"sampler";
697 if (texture.isDepthTexture) {
699 samplerType +=
"_comparison";
702 switch (texture.dimensions) {
703 case TextureDimensions::Texture2D:
706 case TextureDimensions::TexureCube:
709 case TextureDimensions::Texture2DArray:
712 case TextureDimensions::Texture3D:
716 LOG_ERROR(logger,
"Unsupported texture type %d",
int(texture.dimensions));
719 if (!texture.isDepthTexture) {
722 addUniform(shaderSource, bindingGroups, texture.name, type);
723 addUniform(shaderSource, bindingGroups, texture.name +
"Sampler", samplerType);
728 out.members.reserve(a.members.size() + b.members.size());
730 for (
auto member : b.members) {
732 for (
auto existingMember : a.members) {
733 if (member.name == existingMember.name) {
739 out.members.push_back(member);
745bool Cogs::Core::buildEffectWebGPU(
Context* context,
746 std::vector<std::pair<std::string, std::string>>& definitions,
749 const uint32_t multiViewCount)
751 if (!materialDefinition.effect.geometryShader.entryPoint.empty()) {
752 LOG_ERROR(logger,
"%s: Geometry shader not allowed in WebGPU.", materialDefinition.name.c_str());
755 if (!materialDefinition.effect.hullShader.entryPoint.empty()) {
756 LOG_ERROR(logger,
"%s: Hull shader not allowed in WebGPU.", materialDefinition.name.c_str());
759 if (!materialDefinition.effect.domainShader.entryPoint.empty()) {
760 LOG_ERROR(logger,
"%s: Domain shader not allowed in WebGPU.", materialDefinition.name.c_str());
763 if (!materialDefinition.effect.computeShader.entryPoint.empty()) {
764 LOG_ERROR(logger,
"%s: Compute shader not allowed in WebGPU.", materialDefinition.name.c_str());
768 changeSuffix(materialDefinition.effect.vertexShader.customSourcePath,
".hlsl",
".wgsl");
769 changeSuffix(materialDefinition.effect.pixelShader.customSourcePath,
".hlsl",
".wgsl");
770 std::string prefix =
"" + materialDefinition.name;
772 WebGPUBindingGroupVector bindings;
773 createBufferBinding(bindings, materialDefinition);
774 createTextureBindings(bindings, materialDefinition);
775 createEngineTextureBindings(bindings);
779 std::string vs_header;
780 const std::string shaderName = prefix +
"VertexShader" + permutation.getDefinition()->name +
".wgsl";
781 addEffectDefinesAndStuff(vs_header, definitions, multiViewCount);
782 if (!pp.
process(context, vs_header))
return false;
790 concatUniqueMembers(materialDefinition.effect.vertexShader.shaderInterface, permutation.getDefinition()->vertexInterface, vertexInterface);
791 addInterfaceStruct(vs_header, vs_body,
"VertexIn", vertexInterface, ShaderInterface::VertexIn);
795 concatUniqueMembers(materialDefinition.effect.pixelShader.shaderInterface, permutation.getDefinition()->surfaceInterface, surfaceInterface);
796 addInterfaceStruct(vs_header, vs_body,
"VertexOut", surfaceInterface, ShaderInterface::VertexOut);
798 addInterfaceConstructor(vs_body,
"VertexOut", materialDefinition.effect.pixelShader.shaderInterface);
799 addTransferFunc(vs_body, materialDefinition.effect.vertexShader, materialDefinition.effect.pixelShader);
800 addInclude(vs_body, std::string_view(), materialDefinition.effect.vertexShader.customSourcePath);
801 std::string permutationVS = permutation.getDefinition()->vertexShader;
802 changeSuffix(permutationVS,
".hlsl",
".wgsl");
804 addCallFunction(vs_body,
"callMaterialVertexFunction",
805 materialDefinition.effect.vertexShader.entryPoint.empty() ?
"vertexFunction" : materialDefinition.effect.vertexShader.entryPoint,
806 "VertexIn",
"VertexOut");
807 addInclude(vs_body, std::string_view(),
"Engine/EngineVS.wgsl");
808 addCallFunction(vs_body,
"callVertexFunction",
810 "VertexIn",
"VertexOut");
811 addInclude(vs_body, std::string_view(), permutationVS);
812 if (!pp.
process(context, vs_body))
return false;
816 std::string vs_uniforms;
817 addTextures(vs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
826 addInclude(vs_uniforms, std::string_view(),
"Engine/Common.wgsl");
828 if (!pp.
process(context, vs_uniforms))
return false;
832 std::string all = vs_header + vs_uniforms + vs_body;
833 all = convertDefinesToConstExpressions(all);
835 std::string vspath =
"Shaders/" + shaderName;
840 std::string fs_header;
841 const std::string shaderName = prefix +
"PixelShader" + permutation.getDefinition()->name +
".wgsl";
842 addEffectDefinesAndStuff(fs_header, definitions, 0 );
845 bool fs_returnsStruct =
false;
848 surfaceInterface.members.insert(surfaceInterface.members.end(), permutation.getDefinition()->surfaceInterface.members.begin(),
849 permutation.getDefinition()->surfaceInterface.members.end());
850 addInterfaceStruct(fs_header, fs_body,
"VertexIn", surfaceInterface, ShaderInterface::FragmentIn);
851 fs_returnsStruct = addOutputStruct(fs_header, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly());
854 addInclude(fs_header, std::string_view(), materialDefinition.effect.pixelShader.customSourcePath);
855 std::string permutationFS = permutation.getDefinition()->pixelShader;
856 changeSuffix(permutationFS,
".hlsl",
".wgsl");
858 addCallFunction(fs_header,
"callMaterialSurfaceFunction",
859 materialDefinition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : materialDefinition.effect.pixelShader.entryPoint,
860 "VertexIn",
"SurfaceOut");
861 addInclude(fs_header, std::string_view(),
"Engine/EnginePS.wgsl");
862 addCallFunction(fs_header,
"callSurfaceFunction",
864 "VertexIn",
"SurfaceOut");
865 addInclude(fs_header, std::string_view(), permutationFS);
866 if (fs_returnsStruct) {
870fn main(In : VertexIn) -> FragmentOut {
871 return permutationMain(In);
878fn main(In : VertexIn) {
884 if (!pp.
process(context, fs_header))
return false;
888 std::string fs_uniforms;
889 fs_uniforms.reserve(InitialBufferCapasity);
890 addTextures(fs_uniforms, pp.
identifiersSeen, bindings, materialDefinition.properties.textures,
false);
899 addInclude(fs_uniforms, std::string_view(),
"Engine/Common.wgsl");
900 if (!pp.
process(context, fs_uniforms))
return false;
904 std::string all = fs_header + fs_uniforms + fs_body;
905 all = convertDefinesToConstExpressions(all);
907 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.