Cogs.Core
ShaderBuilder.cpp
1#include "ShaderBuilder.h"
2#include "Context.h"
3#include "ResourceStore.h"
4#include "Renderer/EnginePermutations.h"
5
6#include "Rendering/IGraphicsDevice.h"
7
8#include "Foundation/StringUtilities.h"
9#include "Foundation/StringView.h"
10
11namespace
12{
13 using namespace Cogs::Core;
14
16 constexpr size_t InitialBufferCapasity = 4096u;
17
19 {
20 return DataTypeNames[static_cast<size_t>(type)];
21 }
22
23 const char* semanticSlots[] = {
24 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
25 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"
26 };
27
28 struct {
29 const char* name;
30 bool indexable;
31 } semanticInfo[]
32 {
33 { "", false },
34 { "POSITION", true },
35 { "NORMAL", true },
36 { "COLOR", true },
37 { "TEXCOORD", true },
38 { "TANGENT", true },
39 { "INSTANCEVECTOR", true },
40 { "INSTANCEMATRIX", true },
41 { "SV_Position", false },
42 { "SV_VertexID", false },
43 { "SV_InstanceID", false },
44 { "SV_ClipDistance", true },
45 { "VFACE", false },
46 { "SV_ISFrontFace", false }
47 };
48 static_assert(sizeof(semanticInfo) == sizeof(semanticInfo[0]) * size_t(ShaderInterfaceMemberDefinition::SemanticName::Count));
49
50
51 void addVariable(std::string& content,
52 const Cogs::StringView& type,
53 const Cogs::StringView& name,
54 ShaderInterfaceMemberDefinition::SemanticName semantic,
55 uint8_t semanticIndex,
56 ShaderInterfaceMemberDefinition::InterpolationModifiers modifiers = ShaderInterfaceMemberDefinition::NoModifier,
57 bool isArray = false,
58 uint32_t arraySize = 0)
59 {
60 if ((modifiers & ShaderInterfaceMemberDefinition::LinearModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
61 content.append("linear ");
62 }
63 if ((modifiers & ShaderInterfaceMemberDefinition::CentroidModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
64 content.append("centroid ");
65 }
66 if ((modifiers & ShaderInterfaceMemberDefinition::NointerpolationModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
67 content.append("nointerpolation ");
68 }
69 if ((modifiers & ShaderInterfaceMemberDefinition::NoperspectiveModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
70 content.append("noperspective ");
71 }
72 if ((modifiers & ShaderInterfaceMemberDefinition::SampleModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
73 content.append("sample ");
74 }
75
76 content.append(type.to_string_view());
77 content.append(" ");
78 content.append(name.to_string_view());
79 if (isArray) {
80 content.append("[");
81 content.append(std::to_string(arraySize));
82 content.append("]");
83 }
84 if (semantic != ShaderInterfaceMemberDefinition::SemanticName::None) {
85 content.append(" : ");
86 const auto& info = semanticInfo[size_t(semantic)];
87 content.append(info.name);
88 if (info.indexable) {
89 assert(semanticIndex < (sizeof(semanticSlots) / sizeof(size_t)) && "Semantic index out of bounds.");
90 content.append(semanticSlots[semanticIndex]);
91 }
92 else {
93 assert(semanticIndex == 0);
94 }
95 }
96 content.append(";\n");
97 }
98
99 void addVariable(std::string& content,
100 const Cogs::StringView& type,
101 const Cogs::StringView& name,
102 bool isArray = false,
103 uint32_t arraySize = 0)
104 {
105 addVariable(content, type, name,
106 ShaderInterfaceMemberDefinition::SemanticName::None,
107 0,
108 ShaderInterfaceMemberDefinition::NoModifier,
109 isArray, arraySize);
110 }
111
112 void buildVertexInterface(ResourceStore* resourceStore, const ShaderDefinition& shaderDefinition, const EnginePermutationDefinition &permutation, const std::string_view& prefix)
113 {
114 std::string vertexIn;
115 vertexIn.reserve(::InitialBufferCapasity);
116 vertexIn.append("struct VertexIn {\n");
117
118 ShaderInterfaceDefinition shaderInterface = shaderDefinition.shaderInterface;
119 shaderInterface.members.insert(shaderInterface.members.end(), permutation.vertexInterface.members.begin(), permutation.vertexInterface.members.end());
120
121
122 uint8_t index = 0;
123 for (auto& member : shaderInterface.members) {
124 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID) {
125 addVariable(vertexIn, "uint", member.name, member.semantic.name, 0);
126 }
127 else if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None) {
128 addVariable(vertexIn, getType(member.type), member.name, member.semantic.name, member.semantic.slot);
129 }
130 else {
131 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index);
132 index++;
133 }
134 }
135
136 vertexIn.append("};\n");
137
138 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "VertexInterface.hlsl" }), vertexIn);
139 }
140
141 void buildInterface(ResourceStore* resourceStore, const ShaderDefinition& shaderDefinition, const std::vector<ShaderInterfaceMemberDefinition> &additionalMembers, const std::string_view& prefix, const std::string_view& stageOut, const std::string_view& stageIn)
142 {
143 std::string vertexOut;
144 vertexOut.reserve(::InitialBufferCapasity);
145 vertexOut.append("struct VertexOut {\n");
146 std::string vertexIn;
147 vertexIn.reserve(::InitialBufferCapasity);
148 vertexIn.append("struct VertexIn {\n");
149
150 std::vector<ShaderInterfaceMemberDefinition> interfaceMembers = shaderDefinition.shaderInterface.members;
151 for (auto member : additionalMembers) {
152 bool found = false;
153 for (auto existingMember : interfaceMembers) {
154 if (member.name == existingMember.name) {
155 found = true;
156 break;
157 }
158 }
159 if (!found) {
160 interfaceMembers.push_back(member);
161 }
162 }
163
164 uint8_t index = 0;
165 for (const ShaderInterfaceMemberDefinition& member : interfaceMembers) {
166 if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::Position) continue;
167
168 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
169 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
170 }
171
172 for (const ShaderInterfaceMemberDefinition& member : interfaceMembers) {
173 if ((member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)) {
174 addVariable(vertexIn, "uint", member.name, member.semantic.name, 0);
175 }
176 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Position) {
177 }
178 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
179 }
180 else if (member.type == MaterialDataType::Position && stageIn == "PS") {
181 addVariable(vertexIn, "float4", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
182 }
183 else if (member.type == MaterialDataType::VFACE && stageIn == "PS") {
184 addVariable(vertexIn, "float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, 0);
185 }
186 else if (member.type == MaterialDataType::SV_IsFrontFace) {
187 }
188 else if (member.type == MaterialDataType::SV_InstanceID && (stageIn == "PS" || stageIn == "VS")) {
189 }
190 else if (member.type == MaterialDataType::ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
191 }
192 else if (member.type == MaterialDataType::Float4Array) {
193 // Handle array members.
194 std::string pFix = "[" + (member.dimensionString.size() ? member.dimensionString : std::to_string(member.dimension == static_cast<size_t>(-1) ? 1 : member.dimension)) + "]";
195
196 addVariable(vertexOut, getType(member.type), member.name + pFix, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index, member.modifiers);
197 addVariable(vertexIn, getType(member.type), member.name + pFix, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index, member.modifiers);
198
199 //TODO: Determine a way to reserve a sane amount of semantic slots here.
200 index += member.dimension != static_cast<size_t>(-1) ? uint8_t(member.dimension) : 4;
201 }
202 else {
203 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Color, index, member.modifiers);
204 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Color, index, member.modifiers);
205 ++index;
206 }
207 }
208
209 if (stageOut == "VS") {
210 vertexOut += "uint instanceId : TEXCOORD";
211 vertexOut += std::to_string(index);
212 vertexOut += ";\n";
213 }
214
215 // Put these last as these will allocate output registers but won't be part of next stage input, and hlsl requires matching register ordering.
216 for (const ShaderInterfaceMemberDefinition& member : interfaceMembers) {
217 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
218 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance, member.semantic.slot);
219 }
220 else if (member.type == MaterialDataType::ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
221 addVariable(vertexOut, "float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance, 0);
222 }
223 else if (member.type == MaterialDataType::SV_IsFrontFace && stageIn == "PS") {
224 addVariable(vertexIn, "bool", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, 0);
225 }
226 else if (member.type == MaterialDataType::SV_InstanceID && (stageIn == "PS" || stageIn == "VS")) {
227 addVariable(vertexIn, "uint", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, 0);
228 }
229
230 }
231
232
233 vertexOut += "};\n";
234 vertexIn += "};\n";
235
236 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Interface", stageOut, stageIn, ".hlsl" }), vertexOut);
237 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Interface", stageIn, ".hlsl" }), vertexIn);
238 }
239
240 void buildTransfer(ResourceStore* resourceStore, const ShaderDefinition& sourceDefinition, const ShaderDefinition& destinationDefinition, const std::vector<ShaderInterfaceMemberDefinition>& additionalDestinationMembers, const std::string_view& prefix, const std::string_view& stage)
241 {
242 std::string vertexOut;
243 vertexOut.reserve(::InitialBufferCapasity);
244 vertexOut.append("void transferAttributes(in VertexIn In, inout VertexOut Out) {\n");
245
246 std::vector<ShaderInterfaceMemberDefinition> destinationMembers = destinationDefinition.shaderInterface.members;
247 destinationMembers.insert(destinationMembers.end(), additionalDestinationMembers.begin(), additionalDestinationMembers.end());
248
249 for (const ShaderInterfaceMemberDefinition& member : sourceDefinition.shaderInterface.members) {
250
251 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID) continue;
252
253 for (const ShaderInterfaceMemberDefinition& dMember : destinationMembers) {
254
255 if (dMember.name == member.name) {
256
257 vertexOut += " Out.";
258 vertexOut += member.name;
259 vertexOut += " = ";
260
261 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
262 vertexOut += "octDecode(In.";
263 vertexOut += member.name;
264 vertexOut += ");\n";
265 break;
266 }
267
268 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
269 vertexOut += "float4(In.";
270 vertexOut += member.name;
271 vertexOut += ", 1.0);\n";
272 break;
273 }
274 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
275 vertexOut += "float4(In.";
276 vertexOut += member.name;
277 vertexOut += ", 0.0, 1.0);\n";
278 break;
279 }
280 if (dMember.type != member.type) {
281
282 switch (dMember.type) {
283 case MaterialDataType::Float: vertexOut += "(float)"; break;
284 case MaterialDataType::Float2: vertexOut += "(float2)"; break;
285 case MaterialDataType::Float3: vertexOut += "(float3)"; break;
286 case MaterialDataType::Float4: vertexOut += "(float4)"; break;
287 case MaterialDataType::Float4x4: vertexOut += "(Float4x4)"; break;
288 case MaterialDataType::Int: vertexOut += "(int)"; break;
289 case MaterialDataType::Int2: vertexOut += "(int2)"; break;
290 case MaterialDataType::Int3: vertexOut += "(int3)"; break;
291 case MaterialDataType::Int4: vertexOut += "(int4)"; break;
292 case MaterialDataType::UInt: vertexOut += "(uint)"; break;
293 case MaterialDataType::UInt2: vertexOut += "(uint2)"; break;
294 case MaterialDataType::UInt3: vertexOut += "(uint3)"; break;
295 case MaterialDataType::UInt4: vertexOut += "(uint4)"; break;
296 default:
297 break;
298 }
299 }
300
301 vertexOut += "In.";
302 vertexOut += member.name;
303 vertexOut += ";\n";
304
305 break;
306 }
307 }
308 }
309
310 vertexOut += "};\n";
311
312 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Transfer", stage, ".hlsl" }), vertexOut);
313 }
314
315 bool buildSurfaceOutStruct(ResourceStore* resourceStore, const EffectOutputDefinition& outputDefinition, const std::vector<std::pair<std::string, std::string>>& definitions, bool depthOnly, const std::string_view& prefix, const std::string_view& stage) {
316 bool outputDepth = false;
317 bool hasColorAttachments = !outputDefinition.members.empty() && !depthOnly;
318
319
320 {
321 std::string targetString = "COGS_CUSTOM_DEPTH_WRITE";
322 auto it = std::find_if(definitions.begin(), definitions.end(),
323 [&targetString](const std::pair<std::string, std::string>& p) {
324 return p.first == targetString;
325 });
326
327 if (it != definitions.end()) {
328 outputDepth = it->second != "0";
329 }
330 }
331
332 if (!outputDepth && !hasColorAttachments) {
333 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "OutStruct", stage, ".hlsl" }), "");
334 return false;
335 }
336
337 std::string surfOut;
338 surfOut.reserve(::InitialBufferCapasity);
339 surfOut.append("#define COGS_HAS_SURFACEOUT_STRUCT\n");
340 surfOut.append("struct PsOutput {\n");
341 if (hasColorAttachments) {
342 for (auto member : outputDefinition.members) {
343 std::string targetString = "Unknown";
344 switch (member.dataType) {
345 case MaterialDataType::Float: targetString = "float"; break;
346 case MaterialDataType::Float2: targetString = "float2"; break;
347 case MaterialDataType::Float3: targetString = "float3"; break;
348 case MaterialDataType::Float4: targetString = "float4"; break;
349 case MaterialDataType::Float4x4: targetString = "Float4x4"; break;
350 case MaterialDataType::Int: targetString = "int"; break;
351 case MaterialDataType::Int2: targetString = "int2"; break;
352 case MaterialDataType::Int3: targetString = "int3"; break;
353 case MaterialDataType::Int4: targetString = "int4"; break;
354 case MaterialDataType::UInt: targetString = "uint"; break;
355 case MaterialDataType::UInt2: targetString = "uint2"; break;
356 case MaterialDataType::UInt3: targetString = "uint3"; break;
357 case MaterialDataType::UInt4: targetString = "uint4"; break;
358 default:
359 break;
360 }
361
362 surfOut.append(" " + targetString + " " + member.name + " : SV_Target" + std::to_string(member.target) + ";\n");
363 }
364 }
365
366 if (outputDepth) {
367 surfOut.append(" float fragDepth : SV_Depth;\n");
368 }
369 surfOut.append("};\n");
370 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "OutStruct", stage, ".hlsl" }), surfOut);
371 return true;
372
373 }
374
375 void buildConstantBuffer(std::string& out, const ResourceStore* /*resourceStore*/, const ConstantBufferDefinition& definition)
376 {
377 out.append("cbuffer ");
378 out.append(definition.name);
379 out.append(" {\n");
380 for (const ConstantBufferVariableDefinition& member : definition.values) {
381 out.append(2, ' ');
382 out.append(DataTypeNames[static_cast<size_t>(member.type)]);
383 out.append(1, ' ');
384 out.append(member.name);
385 if (member.type == MaterialDataType::Float4Array || member.type == MaterialDataType::Float4x4Array) {
386 assert(member.dimension != static_cast<size_t>(-1));
387 out.append("[");
388 out.append(std::to_string(member.dimension));
389 out.append("]");
390 }
391 out.append(";\n");
392 }
393 out.append("};\n");
394 }
395
396 void buildMaterialInterface(ResourceStore* resourceStore, const MaterialDefinition& definition, const EnginePermutation& permutation, const std::string_view& prefix)
397 {
398 std::string out;
399 out.reserve(::InitialBufferCapasity);
400
401 for (auto& buffer : permutation.getDefinition()->properties.buffers) {
402 buildConstantBuffer(out, resourceStore, buffer);
403 }
404
405 for (auto& buffer : definition.properties.buffers) {
406 buildConstantBuffer(out, resourceStore, buffer);
407 }
408
409 std::string tmp;
410 for (auto& texture : definition.properties.textures) {
411
412 // Basic texture type
413 std::string_view type;
414 switch (texture.dimensions)
415 {
416 case TextureDimensions::TexureCube: type = "TextureCube"; break;
417 case TextureDimensions::Texture3D: type = "Texture3D"; break;
418 case TextureDimensions::Texture2DArray: type = "Texture2DArray"; break;
419 default: type = "Texture2D"; break;
420 }
421
422 // Optionally specify templated parameter for type
423 if (texture.format != MaterialDataType::Unknown) {
424 tmp = type; // Populate tmp string with basic type, then append to this string
425 switch (texture.format) {
426 case MaterialDataType::Float: tmp.append("<float>"); break;
427 case MaterialDataType::Float2: tmp.append("<float2>"); break;
428 case MaterialDataType::Float3: tmp.append("<float3>"); break;
429 case MaterialDataType::Float4: tmp.append("<float4>"); break;
430 case MaterialDataType::Int: tmp.append("<int>"); break;
431 case MaterialDataType::Int2: tmp.append("<int2>"); break;
432 case MaterialDataType::Int3: tmp.append("<int3>"); break;
433 case MaterialDataType::Int4: tmp.append("<int4>"); break;
434 case MaterialDataType::UInt: tmp.append("<uint>"); break;
435 case MaterialDataType::UInt2: tmp.append("<uint2>"); break;
436 case MaterialDataType::UInt3: tmp.append("<uint3>"); break;
437 case MaterialDataType::UInt4: tmp.append("<uint4>"); break;
438 default:
439 break;
440 }
441 type = tmp; // let type stringview point to tmp string
442 }
443
444 addVariable(out, type, texture.name, texture.isArray, texture.arraySize);
445
446 addVariable(out, "SamplerState ", texture.name + "Sampler");
447 }
448
449 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "MaterialInterface.hlsl" }), out);
450 }
451
452#if 1
453 void addDefine(std::string& content, const Cogs::StringView& name, const Cogs::StringView& definition)
454 {
455 content.append("#define ");
456 content.append(name.to_string_view());
457 content.append(" ");
458 content.append(definition.to_string_view());
459 content.append("\n");
460 }
461#endif
462
463 void addInclude(std::string& content, const Cogs::StringView& prefix, const Cogs::StringView& path)
464 {
465 content.append("#include \"");
466 if (prefix.size()) content.append(prefix.to_string_view());
467 content.append(path.to_string_view());
468 content.append("\"\n");
469 }
470
471 void addInclude(std::string& content, const Cogs::StringView& path)
472 {
473 addInclude(content, nullptr, path);
474 }
475
476 [[nodiscard]] std::string getAttribute(const ShaderDefinition& definition, const Cogs::StringView& key, const Cogs::StringView& defaultValue = Cogs::StringView())
477 {
478 for (auto& attribute : definition.attributes) {
479 if (attribute.key == key) return attribute.value;
480 }
481
482 return std::string(defaultValue);
483 }
484
485 [[nodiscard]] bool buildEffectPermutation(ResourceStore* resourceStore,
486 std::vector<std::pair<std::string, std::string>>& definitions,
487 const MaterialDefinition& definition, const EnginePermutation& permutation)
488 {
489 std::string prefix = "" + definition.name;
490 std::string includePrefix = definition.name;
491
492 const std::vector<ShaderInterfaceMemberDefinition>& surfaceInterfaceMembers = permutation.getDefinition()->surfaceInterface.members;
493 buildVertexInterface(resourceStore, definition.effect.vertexShader, *permutation.getDefinition(), prefix);
494 std::vector<ShaderInterfaceMemberDefinition> noAdditionalMembers;
495
496
497 if (definition.effect.hullShader.entryPoint.size()) {
498 buildInterface(resourceStore, definition.effect.hullShader, surfaceInterfaceMembers, prefix, "VS", "HS");
499 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.hullShader, surfaceInterfaceMembers, prefix, "VS");
500
501 buildInterface(resourceStore, definition.effect.domainShader, surfaceInterfaceMembers, prefix, "HS", "DS");
502 buildTransfer(resourceStore, definition.effect.hullShader, definition.effect.domainShader, surfaceInterfaceMembers, prefix, "HS");
503
504 if (definition.effect.geometryShader.entryPoint.size()) {
505 buildInterface(resourceStore, definition.effect.geometryShader, surfaceInterfaceMembers, prefix, "DS", "GS");
506 buildTransfer(resourceStore, definition.effect.domainShader, definition.effect.geometryShader, surfaceInterfaceMembers, prefix, "DS");
507
508 buildInterface(resourceStore, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "GS", "PS");
509 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "GS");
510 }
511 else {
512 buildInterface(resourceStore, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "DS", "PS");
513 buildTransfer(resourceStore, definition.effect.domainShader, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "DS");
514 }
515 }
516 else {
517 if (definition.effect.geometryShader.entryPoint.size()) {
518 buildInterface(resourceStore, definition.effect.geometryShader, surfaceInterfaceMembers, prefix, "VS", "GS");
519 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.geometryShader, surfaceInterfaceMembers, prefix, "VS");
520
521 buildInterface(resourceStore, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "GS", "PS");
522 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "GS");
523 }
524 else {
525 buildInterface(resourceStore, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "VS", "PS");
526 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.pixelShader, surfaceInterfaceMembers, prefix, "VS");
527 }
528 }
529
530 buildMaterialInterface(resourceStore, definition, permutation, prefix);
531
532 std::string vsContent;
533 vsContent.reserve(::InitialBufferCapasity);
534 addInclude(vsContent, definition.effect.vertexShader.customSourcePath);
535
536 resourceStore->addResource(prefix + "VertexFunction.hlsl", vsContent);
537
538 buildSurfaceOutStruct(resourceStore, permutation.getDefinition()->outputs, definitions, permutation.isDepthOnly(), prefix, "PS");
539
540 std::string psContent;
541 psContent.reserve(::InitialBufferCapasity);
542 addInclude(psContent, definition.effect.pixelShader.customSourcePath);
543
544 resourceStore->addResource(prefix + "SurfaceFunction.hlsl", psContent);
545
546 {
547 std::string metaContentVS;
548 metaContentVS.reserve(::InitialBufferCapasity);
549 addInclude(metaContentVS, "Engine/Common.hlsl");
550 addInclude(metaContentVS, includePrefix, "VertexInterface.hlsl");
551
552 if (definition.effect.hullShader.entryPoint.size()) {
553 addInclude(metaContentVS, includePrefix, "InterfaceVSHS.hlsl");
554 }
555 else {
556 if (definition.effect.geometryShader.entryPoint.size()) {
557 addInclude(metaContentVS, includePrefix, "InterfaceVSGS.hlsl");
558 }
559 else {
560 addInclude(metaContentVS, includePrefix, "InterfaceVSPS.hlsl");
561 }
562 }
563
564 addInclude(metaContentVS, includePrefix, "TransferVS.hlsl");
565 addInclude(metaContentVS, includePrefix, "MaterialInterface.hlsl");
566 addInclude(metaContentVS, includePrefix, "VertexFunction.hlsl");
567
568 definitions.emplace_back("VERTEX_FUNCTION", "invokeMaterial");
569 addInclude(metaContentVS, "Engine/EngineVS.hlsl");
570
571 if (definition.effect.vertexShader.entryPoint != "main") {
572 definitions.emplace_back("MATERIAL_VERTEX_FUNCTION", definition.effect.vertexShader.entryPoint.empty() ? "vertexFunction" : definition.effect.vertexShader.entryPoint);
573 addInclude(metaContentVS, permutation.getDefinition()->vertexShader);
574 }
575
576 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "VertexShader", permutation.getDefinition()->name, ".hlsl" }), metaContentVS);
577 }
578
579 if (definition.effect.hullShader.customSourcePath.size()) {
580 std::string hsContent;
581 hsContent.reserve(::InitialBufferCapasity);
582 addInclude(hsContent, definition.effect.hullShader.customSourcePath);
583
584 resourceStore->addResource(prefix + "HullFunction.hlsl", hsContent);
585
586 std::string metaContentHS;
587 metaContentHS.reserve(::InitialBufferCapasity);
588 addInclude(metaContentHS, "Engine/Common.hlsl");
589 addInclude(metaContentHS, includePrefix, "InterfaceHS.hlsl");
590 addInclude(metaContentHS, includePrefix, "InterfaceHSDS.hlsl");
591 addInclude(metaContentHS, includePrefix, "TransferHS.hlsl");
592 addInclude(metaContentHS, includePrefix, "MaterialInterface.hlsl");
593 addInclude(metaContentHS, includePrefix, "HullFunction.hlsl");
594
595 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "HullShader", permutation.getDefinition()->name, ".hlsl" }), metaContentHS);
596 }
597
598 if (definition.effect.domainShader.customSourcePath.size()) {
599 std::string dsContent;
600 dsContent.reserve(::InitialBufferCapasity);
601 addInclude(dsContent, definition.effect.domainShader.customSourcePath);
602
603 resourceStore->addResource(prefix + "DomainFunction.hlsl", dsContent);
604
605 std::string metaContentDS;
606 metaContentDS.reserve(::InitialBufferCapasity);
607 addInclude(metaContentDS, "Engine/Common.hlsl");
608 addInclude(metaContentDS, includePrefix, "InterfaceDS.hlsl");
609
610 if (definition.effect.geometryShader.entryPoint.size()) {
611 addInclude(metaContentDS, includePrefix, "InterfaceDSGS.hlsl");
612 }
613 else {
614 addInclude(metaContentDS, includePrefix, "InterfaceDSPS.hlsl");
615 }
616
617 addInclude(metaContentDS, includePrefix, "TransferDS.hlsl");
618 addInclude(metaContentDS, includePrefix, "MaterialInterface.hlsl");
619 addInclude(metaContentDS, includePrefix, "DomainFunction.hlsl");
620
621 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "DomainShader", permutation.getDefinition()->name, ".hlsl" }), metaContentDS);
622 }
623
624 if (definition.effect.geometryShader.customSourcePath.size()) {
625 std::string gsContent;
626 gsContent.reserve(::InitialBufferCapasity);
627 addInclude(gsContent, definition.effect.geometryShader.customSourcePath);
628
629 resourceStore->addResource(prefix + "GeometryFunction.hlsl", gsContent);
630
631 std::string metaContentGS;
632 metaContentGS.reserve(::InitialBufferCapasity);
633 addInclude(metaContentGS, "Engine/Common.hlsl");
634 addInclude(metaContentGS, includePrefix, "InterfaceGS.hlsl");
635 addInclude(metaContentGS, includePrefix, "InterfaceGSPS.hlsl");
636 addInclude(metaContentGS, includePrefix, "TransferGS.hlsl");
637 addInclude(metaContentGS, includePrefix, "MaterialInterface.hlsl");
638 addInclude(metaContentGS, includePrefix, "GeometryFunction.hlsl");
639
640 if (definition.effect.geometryShader.entryPoint != "main") {
641 if (definition.effect.geometryShader.entryPoint != "geometryFunction") {
642 definitions.emplace_back("GEOMETRY_FUNCTION", definition.effect.geometryShader.entryPoint);
643 }
644
645 auto gsPrimitiveType = getAttribute(definition.effect.geometryShader, "primitivetype", "point");
646
647 definitions.emplace_back("MAX_VERTEX_COUNT", getAttribute(definition.effect.geometryShader, "maxvertexcount", "0"));
648 definitions.emplace_back("GS_PRIMITIVE_TYPE", gsPrimitiveType);
649
650 int gsElementCount = 1;
651 if (gsPrimitiveType == "line") {
652 gsElementCount = 2;
653 }
654 else if (gsPrimitiveType == "lineadj") {
655 gsElementCount = 4;
656 }
657 else if (gsPrimitiveType == "triangle") {
658 gsElementCount = 3;
659 }
660 else if (gsPrimitiveType == "triangleadj") {
661 gsElementCount = 6;
662 }
663
664 definitions.emplace_back("GS_ELEMENT_COUNT", std::to_string(gsElementCount));
665
666 addInclude(metaContentGS, permutation.getDefinition()->geometryShader);
667 }
668
669 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "GeometryShader", permutation.getDefinition()->name, ".hlsl" }), metaContentGS);
670 }
671
672 {
673 std::string metaContentPS;
674 metaContentPS.reserve(::InitialBufferCapasity);
675
676 for (const std::pair<std::string, std::string>& define : definitions) {
677 addDefine(metaContentPS, define.first, define.second);
678 }
679
680 addInclude(metaContentPS, "Engine/Common.hlsl");
681 addInclude(metaContentPS, includePrefix, "InterfacePS.hlsl");
682 addInclude(metaContentPS, includePrefix, "MaterialInterface.hlsl");
683 addInclude(metaContentPS, includePrefix, "OutStructPS.hlsl");
684 addInclude(metaContentPS, includePrefix, "SurfaceFunction.hlsl");
685
686 // If entrypoint is main material interfaces render target directly
687 if (definition.effect.pixelShader.entryPoint != "main") {
688 definitions.emplace_back("SURFACE_FUNCTION", "invokeMaterial");
689 addInclude(metaContentPS, "Engine/EnginePS.hlsl");
690
691 definitions.emplace_back("MATERIAL_SURFACE_FUNCTION", definition.effect.pixelShader.entryPoint.empty() ? "surfaceFunction" : definition.effect.pixelShader.entryPoint);
692 addInclude(metaContentPS, permutation.getDefinition()->pixelShader);
693 addInclude(metaContentPS, "Engine/CommonMainPS.hlsl");
694 }
695 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "PixelShader", permutation.getDefinition()->name, ".hlsl" }), metaContentPS);
696 }
697 return true;
698 }
699}
700
701bool Cogs::Core::buildEffect(class Context* context,
702 std::vector<std::pair<std::string, std::string>>& definitions,
703 const MaterialDefinition& materialPermutation,
704 const EnginePermutation& permutation)
705{
706 return buildEffectPermutation(context->resourceStore.get(), definitions, materialPermutation, permutation);
707}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Definition: Context.h:210
Provides handling of reading and caching of external resources.
void addResource(std::string_view resourceName, const std::string_view content)
Add the given resource string to the resource store.
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:178
constexpr std::string_view to_string_view() const noexcept
Create a standard library string_view of the same view.
Definition: StringView.h:161
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
MaterialDataType
Defines available data types for material properties.
Definition: MaterialTypes.h:20