1#include "ShaderBuilder.h"
3#include "ResourceStore.h"
4#include "Renderer/EnginePermutations.h"
6#include "Rendering/IGraphicsDevice.h"
8#include "Foundation/StringUtilities.h"
9#include "Foundation/StringView.h"
16 constexpr size_t InitialBufferCapasity = 4096u;
20 return DataTypeNames[
static_cast<size_t>(type)];
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"
39 {
"INSTANCEVECTOR",
true },
40 {
"INSTANCEMATRIX",
true },
41 {
"SV_Position",
false },
42 {
"SV_VertexID",
false },
43 {
"SV_InstanceID",
false },
44 {
"SV_ClipDistance",
true },
46 {
"SV_ISFrontFace",
false }
48 static_assert(
sizeof(semanticInfo) ==
sizeof(semanticInfo[0]) * size_t(ShaderInterfaceMemberDefinition::SemanticName::Count));
51 void addVariable(std::string& content,
54 ShaderInterfaceMemberDefinition::SemanticName semantic,
55 uint8_t semanticIndex,
56 ShaderInterfaceMemberDefinition::InterpolationModifiers modifiers = ShaderInterfaceMemberDefinition::NoModifier,
58 uint32_t arraySize = 0)
60 if ((modifiers & ShaderInterfaceMemberDefinition::LinearModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
61 content.append(
"linear ");
63 if ((modifiers & ShaderInterfaceMemberDefinition::CentroidModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
64 content.append(
"centroid ");
66 if ((modifiers & ShaderInterfaceMemberDefinition::NointerpolationModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
67 content.append(
"nointerpolation ");
69 if ((modifiers & ShaderInterfaceMemberDefinition::NoperspectiveModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
70 content.append(
"noperspective ");
72 if ((modifiers & ShaderInterfaceMemberDefinition::SampleModifier) != ShaderInterfaceMemberDefinition::NoModifier) {
73 content.append(
"sample ");
81 content.append(std::to_string(arraySize));
84 if (semantic != ShaderInterfaceMemberDefinition::SemanticName::None) {
85 content.append(
" : ");
86 const auto& info = semanticInfo[size_t(semantic)];
87 content.append(info.name);
89 assert(semanticIndex < (
sizeof(semanticSlots) /
sizeof(
size_t)) &&
"Semantic index out of bounds.");
90 content.append(semanticSlots[semanticIndex]);
93 assert(semanticIndex == 0);
96 content.append(
";\n");
99 void addVariable(std::string& content,
102 bool isArray =
false,
103 uint32_t arraySize = 0)
105 addVariable(content, type, name,
106 ShaderInterfaceMemberDefinition::SemanticName::None,
108 ShaderInterfaceMemberDefinition::NoModifier,
114 std::string vertexIn;
115 vertexIn.reserve(::InitialBufferCapasity);
116 vertexIn.append(
"struct VertexIn {\n");
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);
123 else if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None) {
124 addVariable(vertexIn, getType(member.type), member.name, member.semantic.name, member.semantic.slot);
127 addVariable(vertexIn, getType(member.type), member.name, ShaderInterfaceMemberDefinition::SemanticName::Texcoord, index);
132 vertexIn.append(
"};\n");
134 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"VertexInterface.hlsl" }), vertexIn);
137 void buildInterface(
ResourceStore* resourceStore,
const ShaderDefinition& shaderDefinition,
const std::string_view& prefix,
const std::string_view& stageOut,
const std::string_view& stageIn)
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");
148 if (member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::Position)
continue;
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);
155 if ((member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)) {
156 addVariable(vertexIn,
"uint", member.name, member.semantic.name, 0);
158 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Position) {
160 else if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance && (stageOut ==
"VS" || stageOut ==
"GS")) {
162 else if (member.type == MaterialDataType::Position && stageIn ==
"PS") {
163 addVariable(vertexIn,
"float4", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_Position, 0);
165 else if (member.type == MaterialDataType::VFACE && stageIn ==
"PS") {
166 addVariable(vertexIn,
"float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_VFace, 0);
168 else if (member.type == MaterialDataType::SV_IsFrontFace && stageIn ==
"PS") {
169 addVariable(vertexIn,
"bool", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_IsFrontFace, 0);
171 else if (member.type == MaterialDataType::SV_InstanceID && (stageIn ==
"PS" || stageIn ==
"VS")) {
172 addVariable(vertexIn,
"uint", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID, 0);
174 else if (member.type == MaterialDataType::ClipDistance && (stageOut ==
"VS" || stageOut ==
"GS")) {
176 else if (member.type == MaterialDataType::Float4Array) {
178 std::string pFix =
"[" + (member.dimensionString.size() ? member.dimensionString : std::to_string(member.dimension ==
static_cast<size_t>(-1) ? 1 : member.dimension)) +
"]";
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);
184 index += member.dimension !=
static_cast<size_t>(-1) ? uint8_t(member.dimension) : 4;
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);
193 if (stageOut ==
"VS") {
194 vertexOut +=
"uint instanceId : TEXCOORD";
195 vertexOut += std::to_string(index);
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);
204 else if (member.type == MaterialDataType::ClipDistance && (stageOut ==
"VS" || stageOut ==
"GS")) {
205 addVariable(vertexOut,
"float", member.name, ShaderInterfaceMemberDefinition::SemanticName::SV_ClipDistance, 0);
213 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"Interface", stageOut, stageIn,
".hlsl" }), vertexOut);
214 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"Interface", stageIn,
".hlsl" }), vertexIn);
219 std::string vertexOut;
220 vertexOut.reserve(::InitialBufferCapasity);
221 vertexOut.append(
"void transferAttributes(in VertexIn In, inout VertexOut Out) {\n");
225 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
229 if (dMember.name == member.name) {
231 vertexOut +=
" Out.";
232 vertexOut += member.name;
235 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
236 vertexOut +=
"octDecode(In.";
237 vertexOut += member.name;
242 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
243 vertexOut +=
"float4(In.";
244 vertexOut += member.name;
245 vertexOut +=
", 1.0);\n";
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";
254 if (dMember.type != member.type) {
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;
276 vertexOut += member.name;
286 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"Transfer", stage,
".hlsl" }), vertexOut);
291 out.append(
"cbuffer ");
292 out.append(definition.name);
296 out.append(DataTypeNames[
static_cast<size_t>(member.type)]);
298 out.append(member.name);
299 if (member.type == MaterialDataType::Float4Array || member.type == MaterialDataType::Float4x4Array) {
300 assert(member.dimension !=
static_cast<size_t>(-1));
302 out.append(std::to_string(member.dimension));
313 out.reserve(::InitialBufferCapasity);
315 for (
auto& buffer : permutation.getDefinition()->properties.buffers) {
316 buildConstantBuffer(out, resourceStore, buffer);
319 for (
auto& buffer : definition.properties.buffers) {
320 buildConstantBuffer(out, resourceStore, buffer);
324 for (
auto& texture : definition.properties.textures) {
327 std::string_view type;
328 switch (texture.dimensions)
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;
337 if (texture.format != MaterialDataType::Unknown) {
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;
358 addVariable(out, type, texture.name, texture.isArray, texture.arraySize);
360 addVariable(out,
"SamplerState ", texture.name +
"Sampler");
363 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"MaterialInterface.hlsl" }), out);
369 content.append(
"#define ");
373 content.append(
"\n");
379 content.append(
"#include \"");
381 content.append(path.to_string_view());
382 content.append(
"\"\n");
387 addInclude(content,
nullptr, path);
392 for (
auto& attribute : definition.attributes) {
393 if (attribute.key == key)
return attribute.value;
396 return std::string(defaultValue);
399 [[nodiscard]]
bool buildEffectPermutation(
ResourceStore* resourceStore,
400 std::vector<std::pair<std::string, std::string>>& definitions,
403 std::string prefix =
"" + definition.name;
404 std::string includePrefix = definition.name;
406 buildVertexInterface(resourceStore, definition.effect.vertexShader, prefix);
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");
412 buildInterface(resourceStore, definition.effect.domainShader, prefix,
"HS",
"DS");
413 buildTransfer(resourceStore, definition.effect.hullShader, definition.effect.domainShader, prefix,
"HS");
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");
419 buildInterface(resourceStore, definition.effect.pixelShader, prefix,
"GS",
"PS");
420 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, prefix,
"GS");
423 buildInterface(resourceStore, definition.effect.pixelShader, prefix,
"DS",
"PS");
424 buildTransfer(resourceStore, definition.effect.domainShader, definition.effect.pixelShader, prefix,
"DS");
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");
432 buildInterface(resourceStore, definition.effect.pixelShader, prefix,
"GS",
"PS");
433 buildTransfer(resourceStore, definition.effect.geometryShader, definition.effect.pixelShader, prefix,
"GS");
436 buildInterface(resourceStore, definition.effect.pixelShader, prefix,
"VS",
"PS");
437 buildTransfer(resourceStore, definition.effect.vertexShader, definition.effect.pixelShader, prefix,
"VS");
441 buildMaterialInterface(resourceStore, definition, permutation, prefix);
443 std::string vsContent;
444 vsContent.reserve(::InitialBufferCapasity);
445 addInclude(vsContent, definition.effect.vertexShader.customSourcePath);
447 resourceStore->
addResource(prefix +
"VertexFunction.hlsl", vsContent);
449 std::string psContent;
450 psContent.reserve(::InitialBufferCapasity);
451 addInclude(psContent, definition.effect.pixelShader.customSourcePath);
453 resourceStore->
addResource(prefix +
"SurfaceFunction.hlsl", psContent);
456 std::string metaContentVS;
457 metaContentVS.reserve(::InitialBufferCapasity);
458 addInclude(metaContentVS,
"Engine/Common.hlsl");
459 addInclude(metaContentVS, includePrefix,
"VertexInterface.hlsl");
461 if (definition.effect.hullShader.entryPoint.size()) {
462 addInclude(metaContentVS, includePrefix,
"InterfaceVSHS.hlsl");
465 if (definition.effect.geometryShader.entryPoint.size()) {
466 addInclude(metaContentVS, includePrefix,
"InterfaceVSGS.hlsl");
469 addInclude(metaContentVS, includePrefix,
"InterfaceVSPS.hlsl");
473 addInclude(metaContentVS, includePrefix,
"TransferVS.hlsl");
474 addInclude(metaContentVS, includePrefix,
"MaterialInterface.hlsl");
475 addInclude(metaContentVS, includePrefix,
"VertexFunction.hlsl");
477 definitions.emplace_back(
"VERTEX_FUNCTION",
"invokeMaterial");
478 addInclude(metaContentVS,
"Engine/EngineVS.hlsl");
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);
485 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"VertexShader", permutation.getDefinition()->name,
".hlsl" }), metaContentVS);
488 if (definition.effect.hullShader.customSourcePath.size()) {
489 std::string hsContent;
490 hsContent.reserve(::InitialBufferCapasity);
491 addInclude(hsContent, definition.effect.hullShader.customSourcePath);
493 resourceStore->
addResource(prefix +
"HullFunction.hlsl", hsContent);
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");
504 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"HullShader", permutation.getDefinition()->name,
".hlsl" }), metaContentHS);
507 if (definition.effect.domainShader.customSourcePath.size()) {
508 std::string dsContent;
509 dsContent.reserve(::InitialBufferCapasity);
510 addInclude(dsContent, definition.effect.domainShader.customSourcePath);
512 resourceStore->
addResource(prefix +
"DomainFunction.hlsl", dsContent);
514 std::string metaContentDS;
515 metaContentDS.reserve(::InitialBufferCapasity);
516 addInclude(metaContentDS,
"Engine/Common.hlsl");
517 addInclude(metaContentDS, includePrefix,
"InterfaceDS.hlsl");
519 if (definition.effect.geometryShader.entryPoint.size()) {
520 addInclude(metaContentDS, includePrefix,
"InterfaceDSGS.hlsl");
523 addInclude(metaContentDS, includePrefix,
"InterfaceDSPS.hlsl");
526 addInclude(metaContentDS, includePrefix,
"TransferDS.hlsl");
527 addInclude(metaContentDS, includePrefix,
"MaterialInterface.hlsl");
528 addInclude(metaContentDS, includePrefix,
"DomainFunction.hlsl");
530 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"DomainShader", permutation.getDefinition()->name,
".hlsl" }), metaContentDS);
533 if (definition.effect.geometryShader.customSourcePath.size()) {
534 std::string gsContent;
535 gsContent.reserve(::InitialBufferCapasity);
536 addInclude(gsContent, definition.effect.geometryShader.customSourcePath);
538 resourceStore->
addResource(prefix +
"GeometryFunction.hlsl", gsContent);
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");
549 if (definition.effect.geometryShader.entryPoint !=
"main") {
550 if (definition.effect.geometryShader.entryPoint !=
"geometryFunction") {
551 definitions.emplace_back(
"GEOMETRY_FUNCTION", definition.effect.geometryShader.entryPoint);
554 auto gsPrimitiveType = getAttribute(definition.effect.geometryShader,
"primitivetype",
"point");
556 definitions.emplace_back(
"MAX_VERTEX_COUNT", getAttribute(definition.effect.geometryShader,
"maxvertexcount",
"0"));
557 definitions.emplace_back(
"GS_PRIMITIVE_TYPE", gsPrimitiveType);
559 int gsElementCount = 1;
560 if (gsPrimitiveType ==
"line") {
563 else if (gsPrimitiveType ==
"lineadj") {
566 else if (gsPrimitiveType ==
"triangle") {
569 else if (gsPrimitiveType ==
"triangleadj") {
573 definitions.emplace_back(
"GS_ELEMENT_COUNT", std::to_string(gsElementCount));
575 addInclude(metaContentGS, permutation.getDefinition()->geometryShader);
578 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"GeometryShader", permutation.getDefinition()->name,
".hlsl" }), metaContentGS);
582 std::string metaContentPS;
583 metaContentPS.reserve(::InitialBufferCapasity);
585 for (
const std::pair<std::string, std::string>& define : definitions) {
586 addDefine(metaContentPS, define.first, define.second);
589 addInclude(metaContentPS,
"Engine/Common.hlsl");
590 addInclude(metaContentPS, includePrefix,
"InterfacePS.hlsl");
591 addInclude(metaContentPS, includePrefix,
"MaterialInterface.hlsl");
592 addInclude(metaContentPS, includePrefix,
"SurfaceFunction.hlsl");
595 if (definition.effect.pixelShader.entryPoint !=
"main") {
596 definitions.emplace_back(
"SURFACE_FUNCTION",
"invokeMaterial");
597 addInclude(metaContentPS,
"Engine/EnginePS.hlsl");
599 definitions.emplace_back(
"MATERIAL_SURFACE_FUNCTION", definition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : definition.effect.pixelShader.entryPoint);
600 addInclude(metaContentPS, permutation.getDefinition()->pixelShader);
603 resourceStore->
addResource(Cogs::stringConcatenate({ prefix,
"PixelShader", permutation.getDefinition()->name,
".hlsl" }), metaContentPS);
609bool Cogs::Core::buildEffect(
class Context* context,
610 std::vector<std::pair<std::string, std::string>>& definitions,
614 return buildEffectPermutation(context->
resourceStore.get(), definitions, materialPermutation, permutation);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
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.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr std::string_view to_string_view() const noexcept
Create a standard library string_view of the same view.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
MaterialDataType
Defines available data types for material properties.