Cogs.Core
ShaderBuilderPostProcess.cpp
1#include "ShaderBuilderPostProcess.h"
2
3#include "Context.h"
4#include "Utilities/Strings.h"
5#include "Utilities/Parsing.h"
6#include "Utilities/Preprocessor.h"
7#include "ResourceStore.h"
8#include "Renderer/EnginePermutations.h"
9#include "Rendering/IGraphicsDevice.h"
10#include "Renderer/RenderPipelineDefinition.h"
11#include "Renderer/Tasks/PostProcessTask.h"
12#include "Renderer/Tasks/ComputeTask.h"
13#include "Foundation/Logging/Logger.h"
14#include "Rendering/IContext.h"
15#include "Rendering/IBuffers.h"
16#include "Renderer/IRenderer.h"
17#include "Renderer/RenderTarget.h"
18
19#include <glm/gtc/type_ptr.hpp>
20
21#include <array>
22#include <sstream>
23#include <regex>
24#include <map>
25
26
27namespace {
28 constexpr size_t InitialBufferCapasity = 4096u;
29
30 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("ShaderBuilderPostProcess");
31
32 void removeSuffix(std::string& dst, const std::string_view& suffix)
33 {
34 auto pos = dst.find(suffix);
35 if (pos == std::string::npos) return;
36 dst.erase(pos);
37 }
38
39 using namespace Cogs::Core;
40 [[nodiscard]] std::string_view parameterType(const ParsedDataType type)
41 {
42 switch (type) {
43 case ParsedDataType::Float: return "float"; break;
44 case ParsedDataType::Float2: return "float2"; break;
45 case ParsedDataType::Float3: return "float3"; break;
46 case ParsedDataType::Float4: return "float4"; break;
47 case ParsedDataType::Float4x4: return "float4x4"; break;
48 case ParsedDataType::Int: return "int"; break;
49 case ParsedDataType::Int2: return "int2"; break;
50 case ParsedDataType::Int3: return "int3"; break;
51 case ParsedDataType::Int4: return "int4"; break;
52 case ParsedDataType::UInt: return "uint"; break;
53 case ParsedDataType::UInt2: return "uint2"; break;
54 case ParsedDataType::UInt3: return "uint3"; break;
55 case ParsedDataType::UInt4: return "uint4"; break;
56 default:
57 LOG_ERROR(logger, "Unsupported attribute type %d", int(type));
58 return "<illegal>";
59 break;
60 }
61 }
62
63 void addUniforms(std::string& src, const std::vector<ProcessTaskProperty>& properties, const std::unordered_set<Cogs::Core::StringRef>&/* identifiersSeen*/) {
64 std::string parameterUBOsrc;
65
66 bool hasParameters = false;
67 parameterUBOsrc.append("");
68 parameterUBOsrc.append("cbuffer EffectParameters {\n");
69
70 for (const ProcessTaskProperty& p : properties) {
71 switch (p.definition->type) {
72 case ParsedDataType::Float:
73 case ParsedDataType::Float2:
74 case ParsedDataType::Float3:
75 case ParsedDataType::Float4:
76 case ParsedDataType::Float4x4:
77 case ParsedDataType::Int:
78 case ParsedDataType::Int2:
79 case ParsedDataType::Int3:
80 case ParsedDataType::Int4:
81 case ParsedDataType::UInt:
82 case ParsedDataType::UInt2:
83 case ParsedDataType::UInt3:
84 case ParsedDataType::UInt4:
85 parameterUBOsrc.append(" ");
86 parameterUBOsrc.append(parameterType(p.definition->type));
87 parameterUBOsrc.append(" " + p.definition->key + ";\n");
88 hasParameters = true;
89 break;
90
91 case ParsedDataType::Texture2D:
92 {
93 std::string_view type_str = "float4";
94 if (p.definition->texture.dataType != ParsedDataType::Unknown) {
95 type_str = parameterType(p.definition->texture.dataType);
96 }
97
98 if (p.definition->texture.samples <= 1) {
99 src.append("uniform Texture2D<");
100 src.append(type_str);
101 src.append("> " + p.definition->key + ";\n");
102 }
103 else {
104 src.append("uniform Texture2DMS<");
105 src.append(type_str);
106 src.append(", " + std::to_string(p.definition->texture.samples) + "> " + p.definition->key + ";\n");
107 }
108 // if (identifiersSeen.contains(Strings::add(p.definition->key + "Sampler"))) {
109 src.append("uniform SamplerState " + p.definition->key + "Sampler;\n");;
110 // }
111 }
112 break;
113 case ParsedDataType::Buffer:
114 {
115 auto type_str = parameterType(p.definition->buffer.dataType);
116 if ((p.definition->buffer.flags & ParsedValueBufferFlags::Structured) == ParsedValueBufferFlags::None) {
117 src.append("RWBuffer "); // not tested
118 }
119 else {
120 src.append("RWStructuredBuffer<");
121 src.append(type_str);
122 src.append("> ");
123 }
124 src.append(p.definition->key + ";\n");
125 }
126 break;
127 case ParsedDataType::ConstantBuffer:
128 if (p.definition->key == "SceneBuffer") {
129 src.append("#define COGS_SCENEBUFFER_REFERENCED 1\n");
130 src.append("#include \"Engine/Common.hlsl\"\n\n");
131 } else if (p.definition->value.starts_with("Cogs.")) {
132 std::string bufferName = p.definition->value.substr(5);
133 src.append("#include \"Engine/" + bufferName + ".hlsl\"\n");
134 }
135 break;
136 default:
137 break;
138 }
139 }
140 parameterUBOsrc.append("};\n");
141 if (hasParameters) {
142 src.append(parameterUBOsrc);
143 }
144 }
145
146 void addEngineSampleStates(std::string& src) {
147 src.append(R"(
148SamplerState linearSampler;
149SamplerState linearClampSampler;
150SamplerState pointSampler;
151SamplerState pointClampSampler;
152
153)");
154 }
155
156 void addInterface(std::string& src) {
157 src.append(
158 R"(
159struct VertexIn
160{
161 float4 Position : SV_Position;
162 float4 ScreenPosition : TEXCOORD0;
163 float2 TexCoords : TEXCOORD1;
164};
165
166)");
167 }
168
169
170 void addOutputStruct(std::string& src, const PipelineOptions& options, bool writeDepth) {
171 bool hasCustomTargets = false;
172 std::string prefix = "target_";
173 src.append("struct PixelOut {\n");
174 if (writeDepth) {
175 src.append(" float fragDepth : SV_Depth;\n");
176 }
177 for (auto o : options) {
178 auto key = o.first;
179
180 for (auto& c : key) {
181 c = static_cast<decltype(key)::value_type>(std::tolower(c));
182 }
183 if (key.substr(0, prefix.size()) == prefix) {
184 if (!hasCustomTargets) {
185 hasCustomTargets = true;
186 }
187 int location = std::stoi(key.substr(prefix.size()));
188 TokenStream tokens;
189 Cogs::Core::split(o.second, " ", tokens);
190 if (tokens.size() != 2) {
191 LOG_ERROR(logger, "Unable to parse pipeline output option %s", o.second.c_str());
192 continue;
193 }
194 std::string_view datatype = "Undefined";
195 switch (tokens[1].hashLowercase()) {
196 case Cogs::hash("float"):
197 datatype = parameterType(ParsedDataType::Float);
198 break;
199 case Cogs::hash("float2"):
200 datatype = parameterType(ParsedDataType::Float2);
201 break;
202 case Cogs::hash("float3"):
203 datatype = parameterType(ParsedDataType::Float3);
204 break;
205 case Cogs::hash("float4"):
206 datatype = parameterType(ParsedDataType::Float4);
207 break;
208 case Cogs::hash("uint"):
209 datatype = parameterType(ParsedDataType::UInt);
210 break;
211 case Cogs::hash("uint2"):
212 datatype = parameterType(ParsedDataType::UInt2);
213 break;
214 case Cogs::hash("uint3"):
215 datatype = parameterType(ParsedDataType::UInt3);
216 break;
217 case Cogs::hash("uint4"):
218 datatype = parameterType(ParsedDataType::UInt4);
219 break;
220 case Cogs::hash("int"):
221 datatype = parameterType(ParsedDataType::Int);
222 break;
223 case Cogs::hash("int2"):
224 datatype = parameterType(ParsedDataType::Int2);
225 break;
226 case Cogs::hash("int3"):
227 datatype = parameterType(ParsedDataType::Int3);
228 break;
229 case Cogs::hash("int4"):
230 datatype = parameterType(ParsedDataType::Int4);
231 break;
232 }
233 src.append(" ");
234 src.append(datatype);
235 src.append(" ");
236 src.append(tokens[0]);
237 src.append(" : SV_Target" + std::to_string(location) + ";\n");
238 }
239 }
240 if (!hasCustomTargets) {
241 src.append(" float4 fragColor : SV_Target0;\n");
242 }
243 src.append("};\n\n");
244 }
245} // namespace
246
247namespace Cogs
248{
249 namespace Core {
250 bool buildPostProcessEffect(RenderTaskContext* context, EffectDescription& desc, PostProcessTask* task) {
251 std::string src;
252
253 addInterface(src);
254 std::string prefix_ps = desc.ps;
255 removeSuffix(prefix_ps, ".hlsl");
256 src.append("#include \"" + prefix_ps + ".hlsl\"\n");
257 auto code = hash(src);
258 std::string file_prefix = prefix_ps + "_" + std::to_string(code);
259
261 pp.processed.reserve(::InitialBufferCapasity);
262
263 if (!pp.process(context->context, src)) return false;
264 {
265 std::string uniform_src;
266 addUniforms(uniform_src, task->properties, pp.identifiersSeen);
267 addEngineSampleStates(uniform_src);
268 addOutputStruct(uniform_src, task->options, task->writeDepth);
269 uniform_src.append(src);
270 src = std::move(uniform_src);
271 }
272
273 context->context->resourceStore->addResource(file_prefix + ".hlsl", src);
274 desc.ps = file_prefix + ".hlsl";
275 return true;
276 }
277
278 bool buildComputeEffect(RenderTaskContext* context,
279 EffectDescription& desc, ComputeTask* task) {
280 std::string src;
281
282 addEngineSampleStates(src);
283 std::string prefix_cs = desc.cs;
284 removeSuffix(prefix_cs, ".hlsl");
285 src.append("#include \"" + prefix_cs + ".hlsl\"\n");
286 auto code = hash(src);
287 std::string file_prefix = prefix_cs + "_" + std::to_string(code);
288
290 pp.processed.reserve(::InitialBufferCapasity);
291
292 if (!pp.process(context->context, src)) return false;
293 {
294 std::string uniform_src;
295 addUniforms(uniform_src, task->properties, pp.identifiersSeen);
296 uniform_src.append(src);
297 src = std::move(uniform_src);
298 }
299
300 context->context->resourceStore->addResource(file_prefix + ".hlsl", src);
301 desc.cs = file_prefix + ".hlsl";
302 return true;
303 }
304 }
305}
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Definition: Context.h:210
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
COGSFOUNDATION_API size_t hashLowercase(std::string_view str, size_t hashValue=Cogs::hash()) noexcept
Get the hash code of the string converted to lowercase.
Partial C preprocessor.
Definition: Preprocessor.h:42
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.
Definition: Preprocessor.h:51
std::string processed
Resulting processed text.
Definition: Preprocessor.h:48