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 std::string_view& prefix)
113 {
114 std::string vertexIn;
115 vertexIn.reserve(::InitialBufferCapasity);
116 vertexIn.append("struct VertexIn {\n");
117
118 uint8_t index = 0;
119 for (auto& member : shaderDefinition.shaderInterface.members) {
120 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID) {
121 addVariable(vertexIn, "uint", member.name, member.semantic.name, 0);
122 }
123 else if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None) {
124 addVariable(vertexIn, getType(member.type), member.name, member.semantic.name, member.semantic.slot);
125 }
126 else {
127 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index);
128 index++;
129 }
130 }
131
132 vertexIn.append("};\n");
133
134 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "VertexInterface.hlsl" }), vertexIn);
135 }
136
137 void buildInterface(ResourceStore* resourceStore, const ShaderDefinition& shaderDefinition, const std::string_view& prefix, const std::string_view& stageOut, const std::string_view& stageIn)
138 {
139 std::string vertexOut;
140 vertexOut.reserve(::InitialBufferCapasity);
141 vertexOut.append("struct VertexOut {\n");
142 std::string vertexIn;
143 vertexIn.reserve(::InitialBufferCapasity);
144 vertexIn.append("struct VertexIn {\n");
145
146 uint8_t index = 0;
147 for (const ShaderInterfaceMemberDefinition& member : shaderDefinition.shaderInterface.members) {
148 if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::Position) continue;
149
150 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
151 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
152 }
153
154 for (const ShaderInterfaceMemberDefinition& member : shaderDefinition.shaderInterface.members) {
155 if ((member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)) {
156 addVariable(vertexIn, "uint", member.name, member.semantic.name, 0);
157 }
158 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Position) {
159 }
160 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
161 }
162 else if (member.type == MaterialDataType::Position && stageIn == "PS") {
163 addVariable(vertexIn, "float4", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
164 }
165 else if (member.type == MaterialDataType::VFACE && stageIn == "PS") {
166 addVariable(vertexIn, "float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, 0);
167 }
168 else if (member.type == MaterialDataType::SV_IsFrontFace && stageIn == "PS") {
169 addVariable(vertexIn, "bool", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, 0);
170 }
171 else if (member.type == MaterialDataType::SV_InstanceID && (stageIn == "PS" || stageIn == "VS")) {
172 addVariable(vertexIn, "uint", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, 0);
173 }
174 else if (member.type == MaterialDataType::ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
175 }
176 else if (member.type == MaterialDataType::Float4Array) {
177 // Handle array members.
178 std::string pFix = "[" + (member.dimensionString.size() ? member.dimensionString : std::to_string(member.dimension == static_cast<size_t>(-1) ? 1 : member.dimension)) + "]";
179
180 addVariable(vertexOut, getType(member.type), member.name + pFix, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index, member.modifiers);
181 addVariable(vertexIn, getType(member.type), member.name + pFix, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index, member.modifiers);
182
183 //TODO: Determine a way to reserve a sane amount of semantic slots here.
184 index += member.dimension != static_cast<size_t>(-1) ? uint8_t(member.dimension) : 4;
185 }
186 else {
187 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Color, index, member.modifiers);
188 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Color, index, member.modifiers);
189 ++index;
190 }
191 }
192
193 if (stageOut == "VS") {
194 vertexOut += "uint instanceId : TEXCOORD";
195 vertexOut += std::to_string(index);
196 vertexOut += ";\n";
197 }
198
199 // Put these last as these will allocate output registers but won't be part of next stage input, and hlsl requires matching register ordering.
200 for (const ShaderInterfaceMemberDefinition& member : shaderDefinition.shaderInterface.members) {
201 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
202 addVariable(vertexOut, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance, member.semantic.slot);
203 }
204 else if (member.type == MaterialDataType::ClipDistance && (stageOut == "VS" || stageOut == "GS")) {
205 addVariable(vertexOut, "float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance, 0);
206 }
207 }
208
209
210 vertexOut += "};\n";
211 vertexIn += "};\n";
212
213 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Interface", stageOut, stageIn, ".hlsl" }), vertexOut);
214 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Interface", stageIn, ".hlsl" }), vertexIn);
215 }
216
217 void buildTransfer(ResourceStore* resourceStore, const ShaderDefinition& sourceDefinition, const ShaderDefinition& destinationDefinition, const std::string_view& prefix, const std::string_view& stage)
218 {
219 std::string vertexOut;
220 vertexOut.reserve(::InitialBufferCapasity);
221 vertexOut.append("void transferAttributes(in VertexIn In, inout VertexOut Out) {\n");
222
223 for (const ShaderInterfaceMemberDefinition& member : sourceDefinition.shaderInterface.members) {
224
225 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID) continue;
226
227 for (const ShaderInterfaceMemberDefinition& dMember : destinationDefinition.shaderInterface.members) {
228
229 if (dMember.name == member.name) {
230
231 vertexOut += " Out.";
232 vertexOut += member.name;
233 vertexOut += " = ";
234
235 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
236 vertexOut += "octDecode(In.";
237 vertexOut += member.name;
238 vertexOut += ");\n";
239 break;
240 }
241
242 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
243 vertexOut += "float4(In.";
244 vertexOut += member.name;
245 vertexOut += ", 1.0);\n";
246 break;
247 }
248 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
249 vertexOut += "float4(In.";
250 vertexOut += member.name;
251 vertexOut += ", 0.0, 1.0);\n";
252 break;
253 }
254 if (dMember.type != member.type) {
255
256 switch (dMember.type) {
257 case MaterialDataType::Float: vertexOut += "(float)"; break;
258 case MaterialDataType::Float2: vertexOut += "(float2)"; break;
259 case MaterialDataType::Float3: vertexOut += "(float3)"; break;
260 case MaterialDataType::Float4: vertexOut += "(float4)"; break;
261 case MaterialDataType::Float4x4: vertexOut += "(Float4x4)"; break;
262 case MaterialDataType::Int: vertexOut += "(int)"; break;
263 case MaterialDataType::Int2: vertexOut += "(int2)"; break;
264 case MaterialDataType::Int3: vertexOut += "(int3)"; break;
265 case MaterialDataType::Int4: vertexOut += "(int4)"; break;
266 case MaterialDataType::UInt: vertexOut += "(uint)"; break;
267 case MaterialDataType::UInt2: vertexOut += "(uint2)"; break;
268 case MaterialDataType::UInt3: vertexOut += "(uint3)"; break;
269 case MaterialDataType::UInt4: vertexOut += "(uint4)"; break;
270 default:
271 break;
272 }
273 }
274
275 vertexOut += "In.";
276 vertexOut += member.name;
277 vertexOut += ";\n";
278
279 break;
280 }
281 }
282 }
283
284 vertexOut += "};\n";
285
286 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "Transfer", stage, ".hlsl" }), vertexOut);
287 }
288
289 void buildConstantBuffer(std::string& out, const ResourceStore* /*resourceStore*/, const ConstantBufferDefinition& definition)
290 {
291 out.append("cbuffer ");
292 out.append(definition.name);
293 out.append(" {\n");
294 for (const ConstantBufferVariableDefinition& member : definition.values) {
295 out.append(2, ' ');
296 out.append(DataTypeNames[static_cast<size_t>(member.type)]);
297 out.append(1, ' ');
298 out.append(member.name);
299 if (member.type == MaterialDataType::Float4Array || member.type == MaterialDataType::Float4x4Array) {
300 assert(member.dimension != static_cast<size_t>(-1));
301 out.append("[");
302 out.append(std::to_string(member.dimension));
303 out.append("]");
304 }
305 out.append(";\n");
306 }
307 out.append("};\n");
308 }
309
310 void buildMaterialInterface(ResourceStore* resourceStore, const MaterialDefinition& definition, const EnginePermutation& permutation, const std::string_view& prefix)
311 {
312 std::string out;
313 out.reserve(::InitialBufferCapasity);
314
315 for (auto& buffer : permutation.getDefinition()->properties.buffers) {
316 buildConstantBuffer(out, resourceStore, buffer);
317 }
318
319 for (auto& buffer : definition.properties.buffers) {
320 buildConstantBuffer(out, resourceStore, buffer);
321 }
322
323 std::string tmp;
324 for (auto& texture : definition.properties.textures) {
325
326 // Basic texture type
327 std::string_view type;
328 switch (texture.dimensions)
329 {
330 case TextureDimensions::TexureCube: type = "TextureCube"; break;
331 case TextureDimensions::Texture3D: type = "Texture3D"; break;
332 case TextureDimensions::Texture2DArray: type = "Texture2DArray"; break;
333 default: type = "Texture2D"; break;
334 }
335
336 // Optionally specify templated parameter for type
337 if (texture.format != MaterialDataType::Unknown) {
338 tmp = type; // Populate tmp string with basic type, then append to this string
339 switch (texture.format) {
340 case MaterialDataType::Float: tmp.append("<float>"); break;
341 case MaterialDataType::Float2: tmp.append("<float2>"); break;
342 case MaterialDataType::Float3: tmp.append("<float3>"); break;
343 case MaterialDataType::Float4: tmp.append("<float4>"); break;
344 case MaterialDataType::Int: tmp.append("<int>"); break;
345 case MaterialDataType::Int2: tmp.append("<int2>"); break;
346 case MaterialDataType::Int3: tmp.append("<int3>"); break;
347 case MaterialDataType::Int4: tmp.append("<int4>"); break;
348 case MaterialDataType::UInt: tmp.append("<uint>"); break;
349 case MaterialDataType::UInt2: tmp.append("<uint2>"); break;
350 case MaterialDataType::UInt3: tmp.append("<uint3>"); break;
351 case MaterialDataType::UInt4: tmp.append("<uint4>"); break;
352 default:
353 break;
354 }
355 type = tmp; // let type stringview point to tmp string
356 }
357
358 addVariable(out, type, texture.name, texture.isArray, texture.arraySize);
359
360 addVariable(out, "SamplerState ", texture.name + "Sampler");
361 }
362
363 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "MaterialInterface.hlsl" }), out);
364 }
365
366#if 1
367 void addDefine(std::string& content, const Cogs::StringView& name, const Cogs::StringView& definition)
368 {
369 content.append("#define ");
370 content.append(name.to_string_view());
371 content.append(" ");
372 content.append(definition.to_string_view());
373 content.append("\n");
374 }
375#endif
376
377 void addInclude(std::string& content, const Cogs::StringView& prefix, const Cogs::StringView& path)
378 {
379 content.append("#include \"");
380 if (prefix.size()) content.append(prefix.to_string_view());
381 content.append(path.to_string_view());
382 content.append("\"\n");
383 }
384
385 void addInclude(std::string& content, const Cogs::StringView& path)
386 {
387 addInclude(content, nullptr, path);
388 }
389
390 [[nodiscard]] std::string getAttribute(const ShaderDefinition& definition, const Cogs::StringView& key, const Cogs::StringView& defaultValue = Cogs::StringView())
391 {
392 for (auto& attribute : definition.attributes) {
393 if (attribute.key == key) return attribute.value;
394 }
395
396 return std::string(defaultValue);
397 }
398
399 [[nodiscard]] bool buildEffectPermutation(ResourceStore* resourceStore,
400 std::vector<std::pair<std::string, std::string>>& definitions,
401 const MaterialDefinition& definition, const EnginePermutation& permutation)
402 {
403 std::string prefix = "" + definition.name;
404 std::string includePrefix = definition.name;
405
406 buildVertexInterface(resourceStore, definition.effect.vertexShader, prefix);
407
408 if (definition.effect.hullShader.entryPoint.size()) {
409 buildInterface(resourceStore, definition.effect.hullShader, prefix, "VS", "HS");
410 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.hullShader, prefix, "VS");
411
412 buildInterface(resourceStore, definition.effect.domainShader, prefix, "HS", "DS");
413 buildTransfer(resourceStore, definition.effect.hullShader, definition.effect.domainShader, prefix, "HS");
414
415 if (definition.effect.geometryShader.entryPoint.size()) {
416 buildInterface(resourceStore, definition.effect.geometryShader, prefix, "DS", "GS");
417 buildTransfer(resourceStore, definition.effect.domainShader, definition.effect.geometryShader, prefix, "DS");
418
419 buildInterface(resourceStore, definition.effect.pixelShader, prefix, "GS", "PS");
420 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, prefix, "GS");
421 }
422 else {
423 buildInterface(resourceStore, definition.effect.pixelShader, prefix, "DS", "PS");
424 buildTransfer(resourceStore, definition.effect.domainShader, definition.effect.pixelShader, prefix, "DS");
425 }
426 }
427 else {
428 if (definition.effect.geometryShader.entryPoint.size()) {
429 buildInterface(resourceStore, definition.effect.geometryShader, prefix, "VS", "GS");
430 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.geometryShader, prefix, "VS");
431
432 buildInterface(resourceStore, definition.effect.pixelShader, prefix, "GS", "PS");
433 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, prefix, "GS");
434 }
435 else {
436 buildInterface(resourceStore, definition.effect.pixelShader, prefix, "VS", "PS");
437 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.pixelShader, prefix, "VS");
438 }
439 }
440
441 buildMaterialInterface(resourceStore, definition, permutation, prefix);
442
443 std::string vsContent;
444 vsContent.reserve(::InitialBufferCapasity);
445 addInclude(vsContent, definition.effect.vertexShader.customSourcePath);
446
447 resourceStore->addResource(prefix + "VertexFunction.hlsl", vsContent);
448
449 std::string psContent;
450 psContent.reserve(::InitialBufferCapasity);
451 addInclude(psContent, definition.effect.pixelShader.customSourcePath);
452
453 resourceStore->addResource(prefix + "SurfaceFunction.hlsl", psContent);
454
455 {
456 std::string metaContentVS;
457 metaContentVS.reserve(::InitialBufferCapasity);
458 addInclude(metaContentVS, "Engine/Common.hlsl");
459 addInclude(metaContentVS, includePrefix, "VertexInterface.hlsl");
460
461 if (definition.effect.hullShader.entryPoint.size()) {
462 addInclude(metaContentVS, includePrefix, "InterfaceVSHS.hlsl");
463 }
464 else {
465 if (definition.effect.geometryShader.entryPoint.size()) {
466 addInclude(metaContentVS, includePrefix, "InterfaceVSGS.hlsl");
467 }
468 else {
469 addInclude(metaContentVS, includePrefix, "InterfaceVSPS.hlsl");
470 }
471 }
472
473 addInclude(metaContentVS, includePrefix, "TransferVS.hlsl");
474 addInclude(metaContentVS, includePrefix, "MaterialInterface.hlsl");
475 addInclude(metaContentVS, includePrefix, "VertexFunction.hlsl");
476
477 definitions.emplace_back("VERTEX_FUNCTION", "invokeMaterial");
478 addInclude(metaContentVS, "Engine/EngineVS.hlsl");
479
480 if (definition.effect.vertexShader.entryPoint != "main") {
481 definitions.emplace_back("MATERIAL_VERTEX_FUNCTION", definition.effect.vertexShader.entryPoint.empty() ? "vertexFunction" : definition.effect.vertexShader.entryPoint);
482 addInclude(metaContentVS, permutation.getDefinition()->vertexShader);
483 }
484
485 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "VertexShader", permutation.getDefinition()->name, ".hlsl" }), metaContentVS);
486 }
487
488 if (definition.effect.hullShader.customSourcePath.size()) {
489 std::string hsContent;
490 hsContent.reserve(::InitialBufferCapasity);
491 addInclude(hsContent, definition.effect.hullShader.customSourcePath);
492
493 resourceStore->addResource(prefix + "HullFunction.hlsl", hsContent);
494
495 std::string metaContentHS;
496 metaContentHS.reserve(::InitialBufferCapasity);
497 addInclude(metaContentHS, "Engine/Common.hlsl");
498 addInclude(metaContentHS, includePrefix, "InterfaceHS.hlsl");
499 addInclude(metaContentHS, includePrefix, "InterfaceHSDS.hlsl");
500 addInclude(metaContentHS, includePrefix, "TransferHS.hlsl");
501 addInclude(metaContentHS, includePrefix, "MaterialInterface.hlsl");
502 addInclude(metaContentHS, includePrefix, "HullFunction.hlsl");
503
504 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "HullShader", permutation.getDefinition()->name, ".hlsl" }), metaContentHS);
505 }
506
507 if (definition.effect.domainShader.customSourcePath.size()) {
508 std::string dsContent;
509 dsContent.reserve(::InitialBufferCapasity);
510 addInclude(dsContent, definition.effect.domainShader.customSourcePath);
511
512 resourceStore->addResource(prefix + "DomainFunction.hlsl", dsContent);
513
514 std::string metaContentDS;
515 metaContentDS.reserve(::InitialBufferCapasity);
516 addInclude(metaContentDS, "Engine/Common.hlsl");
517 addInclude(metaContentDS, includePrefix, "InterfaceDS.hlsl");
518
519 if (definition.effect.geometryShader.entryPoint.size()) {
520 addInclude(metaContentDS, includePrefix, "InterfaceDSGS.hlsl");
521 }
522 else {
523 addInclude(metaContentDS, includePrefix, "InterfaceDSPS.hlsl");
524 }
525
526 addInclude(metaContentDS, includePrefix, "TransferDS.hlsl");
527 addInclude(metaContentDS, includePrefix, "MaterialInterface.hlsl");
528 addInclude(metaContentDS, includePrefix, "DomainFunction.hlsl");
529
530 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "DomainShader", permutation.getDefinition()->name, ".hlsl" }), metaContentDS);
531 }
532
533 if (definition.effect.geometryShader.customSourcePath.size()) {
534 std::string gsContent;
535 gsContent.reserve(::InitialBufferCapasity);
536 addInclude(gsContent, definition.effect.geometryShader.customSourcePath);
537
538 resourceStore->addResource(prefix + "GeometryFunction.hlsl", gsContent);
539
540 std::string metaContentGS;
541 metaContentGS.reserve(::InitialBufferCapasity);
542 addInclude(metaContentGS, "Engine/Common.hlsl");
543 addInclude(metaContentGS, includePrefix, "InterfaceGS.hlsl");
544 addInclude(metaContentGS, includePrefix, "InterfaceGSPS.hlsl");
545 addInclude(metaContentGS, includePrefix, "TransferGS.hlsl");
546 addInclude(metaContentGS, includePrefix, "MaterialInterface.hlsl");
547 addInclude(metaContentGS, includePrefix, "GeometryFunction.hlsl");
548
549 if (definition.effect.geometryShader.entryPoint != "main") {
550 if (definition.effect.geometryShader.entryPoint != "geometryFunction") {
551 definitions.emplace_back("GEOMETRY_FUNCTION", definition.effect.geometryShader.entryPoint);
552 }
553
554 auto gsPrimitiveType = getAttribute(definition.effect.geometryShader, "primitivetype", "point");
555
556 definitions.emplace_back("MAX_VERTEX_COUNT", getAttribute(definition.effect.geometryShader, "maxvertexcount", "0"));
557 definitions.emplace_back("GS_PRIMITIVE_TYPE", gsPrimitiveType);
558
559 int gsElementCount = 1;
560 if (gsPrimitiveType == "line") {
561 gsElementCount = 2;
562 }
563 else if (gsPrimitiveType == "lineadj") {
564 gsElementCount = 4;
565 }
566 else if (gsPrimitiveType == "triangle") {
567 gsElementCount = 3;
568 }
569 else if (gsPrimitiveType == "triangleadj") {
570 gsElementCount = 6;
571 }
572
573 definitions.emplace_back("GS_ELEMENT_COUNT", std::to_string(gsElementCount));
574
575 addInclude(metaContentGS, permutation.getDefinition()->geometryShader);
576 }
577
578 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "GeometryShader", permutation.getDefinition()->name, ".hlsl" }), metaContentGS);
579 }
580
581 {
582 std::string metaContentPS;
583 metaContentPS.reserve(::InitialBufferCapasity);
584
585 for (const std::pair<std::string, std::string>& define : definitions) {
586 addDefine(metaContentPS, define.first, define.second);
587 }
588
589 addInclude(metaContentPS, "Engine/Common.hlsl");
590 addInclude(metaContentPS, includePrefix, "InterfacePS.hlsl");
591 addInclude(metaContentPS, includePrefix, "MaterialInterface.hlsl");
592 addInclude(metaContentPS, includePrefix, "SurfaceFunction.hlsl");
593
594 // If entrypoint is main material interfaces render target directly
595 if (definition.effect.pixelShader.entryPoint != "main") {
596 definitions.emplace_back("SURFACE_FUNCTION", "invokeMaterial");
597 addInclude(metaContentPS, "Engine/EnginePS.hlsl");
598
599 definitions.emplace_back("MATERIAL_SURFACE_FUNCTION", definition.effect.pixelShader.entryPoint.empty() ? "surfaceFunction" : definition.effect.pixelShader.entryPoint);
600 addInclude(metaContentPS, permutation.getDefinition()->pixelShader);
601 }
602
603 resourceStore->addResource(Cogs::stringConcatenate({ prefix, "PixelShader", permutation.getDefinition()->name, ".hlsl" }), metaContentPS);
604 }
605 return true;
606 }
607}
608
609bool Cogs::Core::buildEffect(class Context* context,
610 std::vector<std::pair<std::string, std::string>>& definitions,
611 const MaterialDefinition& materialPermutation,
612 const EnginePermutation& permutation)
613{
614 return buildEffectPermutation(context->resourceStore.get(), definitions, materialPermutation, permutation);
615}
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