1#include "ShaderBuilderPostProcess.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"
8#include "Renderer/Tasks/PostProcessTask.h"
9#include "Foundation/Logging/Logger.h"
10#include "Rendering/IContext.h"
11#include "Rendering/IBuffers.h"
12#include "Renderer/IRenderer.h"
13#include "Renderer/RenderTarget.h"
15#include <glm/gtc/type_ptr.hpp>
24 constexpr size_t InitialBufferCapasity = 4096u;
28 void changeSuffix(std::string& dst,
const std::string_view& from,
const std::string_view& to)
30 auto pos = dst.find(from);
31 if (pos == std::string::npos)
return;
32 dst.replace(pos, to.length(), to);
35 void removeSuffix(std::string& dst,
const std::string_view& suffix)
37 auto pos = dst.find(suffix);
38 if (pos == std::string::npos)
return;
42 [[nodiscard]] std::string_view parameterType(
const ParsedDataType type)
45 case ParsedDataType::Float:
return "float ";
break;
46 case ParsedDataType::Float2:
return "vec2 ";
break;
47 case ParsedDataType::Float3:
return "vec3 ";
break;
48 case ParsedDataType::Float4:
return "vec4 ";
break;
49 case ParsedDataType::Float4x4:
return "mat4 ";
break;
50 case ParsedDataType::Int:
return "int ";
break;
51 case ParsedDataType::Int2:
return "ivec2 ";
break;
52 case ParsedDataType::Int3:
return "ivec3 ";
break;
53 case ParsedDataType::Int4:
return "ivec4 ";
break;
54 case ParsedDataType::UInt:
return "uint ";
break;
55 case ParsedDataType::UInt2:
return "uvec2 ";
break;
56 case ParsedDataType::UInt3:
return "uvec3 ";
break;
57 case ParsedDataType::UInt4:
return "uvec4 ";
break;
59 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
65 void addHeadersAndInterface(std::string &src) {
70precision highp usampler2D;
72in vec2 vs_NormalizedCoords;
77 vec2 NormalizedCoords;
81VertexIn importAttribs() {
83 In.NormalizedCoords = vs_NormalizedCoords;
84 In.TexCoords = vs_TexCoords;
91 void addDefines(std::string& output,
92 const std::vector<std::pair<std::string, std::string>>& definitions)
94 for (
const std::pair<std::string, std::string>& define : definitions) {
95 output.append(
"#define ");
96 output.append(define.first);
98 output.append(define.second);
103 void addUniforms(std::string& src,
const std::vector<ProcessTaskProperty>& properties) {
104 std::string parameterUBOsrc;
106 bool hasParameters =
false;
107 parameterUBOsrc.append(
"");
108 parameterUBOsrc.append(
"layout (std140) uniform EffectParameters {\n");
111 switch (p.definition->type) {
112 case ParsedDataType::Float:
113 case ParsedDataType::Float2:
114 case ParsedDataType::Float3:
115 case ParsedDataType::Float4:
116 case ParsedDataType::Float4x4:
117 case ParsedDataType::Int:
118 case ParsedDataType::Int2:
119 case ParsedDataType::Int3:
120 case ParsedDataType::Int4:
121 case ParsedDataType::UInt:
122 case ParsedDataType::UInt2:
123 case ParsedDataType::UInt3:
124 case ParsedDataType::UInt4:
125 parameterUBOsrc.append(
" ");
126 parameterUBOsrc.append(parameterType(p.definition->type));
127 parameterUBOsrc.append(
" " + p.definition->key +
";\n");
128 hasParameters =
true;
131 case ParsedDataType::Texture2D:
133 if (p.definition->texture.samples > 1) {
134 LOG_ERROR(logger,
"Sampling from multisampled textures is not allowed on this platform");
136 std::string_view sampler_prefix =
"highp ";
137 switch (p.definition->texture.dataType) {
138 case ParsedDataType::Int:
139 case ParsedDataType::Int2:
140 case ParsedDataType::Int3:
141 case ParsedDataType::Int4:
142 sampler_prefix =
"i";
144 case ParsedDataType::UInt:
145 case ParsedDataType::UInt2:
146 case ParsedDataType::UInt3:
147 case ParsedDataType::UInt4:
148 sampler_prefix =
"u";
153 src.append(
"uniform ");
154 src.append(sampler_prefix);
155 src.append(
"sampler2D " + p.definition->key +
"; \n");
158 case ParsedDataType::Buffer:
159 LOG_ERROR(logger,
"Render buffers not supported on this platform");
161 case ParsedDataType::ConstantBuffer:
162 if (p.definition->key ==
"SceneBuffer") {
163 src.append(
"#define COGS_SCENEBUFFER_REFERENCED 1\n");
164 src.append(
"#define COGS_VIEWGETTERS_REFERENCED 1\n");
165 }
else if (p.definition->value.starts_with(
"Cogs.")) {
166 std::string bufferName = p.definition->value.substr(5);
167 src.append(
"#include \"Engine/" + bufferName +
".es30.glsl\"\n");
174 parameterUBOsrc.append(
"};\n");
176 src.append(parameterUBOsrc);
180 void addOutputStruct(std::string& src,
const PipelineOptions& options) {
181 bool hasCustomTargets =
false;
182 std::string prefix =
"target_";
183 for (
auto o : options) {
186 for (
auto& c : key) {
187 c =
static_cast<decltype(key)::value_type
>(std::tolower(c));
189 if (key.substr(0, prefix.size()) == prefix) {
190 if (!hasCustomTargets) {
191 hasCustomTargets =
true;
192 src.append(
"struct FragmentOut {\n");
195 Cogs::Core::split(o.second,
" ", tokens);
196 if (tokens.size() != 2) {
197 LOG_ERROR(logger,
"Unable to parse pipeline output option %s", o.second.c_str());
200 std::string_view datatype =
"Undefined";
203 datatype = parameterType(ParsedDataType::Float);
206 datatype = parameterType(ParsedDataType::Float2);
209 datatype = parameterType(ParsedDataType::Float3);
212 datatype = parameterType(ParsedDataType::Float4);
215 datatype = parameterType(ParsedDataType::UInt);
218 datatype = parameterType(ParsedDataType::UInt2);
221 datatype = parameterType(ParsedDataType::UInt3);
224 datatype = parameterType(ParsedDataType::UInt4);
227 datatype = parameterType(ParsedDataType::Int);
230 datatype = parameterType(ParsedDataType::Int2);
233 datatype = parameterType(ParsedDataType::Int3);
236 datatype = parameterType(ParsedDataType::Int4);
239 src.append(datatype);
241 src.append(tokens[0]);
245 if (hasCustomTargets) {
246 src.append(
"};\n\n");
250 void addOutputs(std::string& src,
const PipelineOptions& options) {
251 bool defaultTarget =
true;
252 std::string prefix =
"target_";
253 std::string outputStruct;
254 std::string outputExport;
255 outputStruct =
"struct FragmentOut {\n";
256 outputExport =
"void exportOutput(FragmentOut Out) {\n";
257 for (
auto o : options) {
260 for (
auto& c : key) {
261 c =
static_cast<decltype(key)::value_type
>(std::tolower(c));
263 if (key.substr(0, prefix.size()) == prefix) {
264 defaultTarget =
false;
265 int location = std::stoi(key.substr(prefix.size()));
267 Cogs::Core::split(o.second,
" ", tokens);
268 if (tokens.size() != 2) {
272 std::string_view datatype =
"Undefined";
275 datatype = parameterType(ParsedDataType::Float);
278 datatype = parameterType(ParsedDataType::Float2);
281 datatype = parameterType(ParsedDataType::Float3);
284 datatype = parameterType(ParsedDataType::Float4);
287 datatype = parameterType(ParsedDataType::UInt);
290 datatype = parameterType(ParsedDataType::UInt2);
293 datatype = parameterType(ParsedDataType::UInt3);
296 datatype = parameterType(ParsedDataType::UInt4);
299 datatype = parameterType(ParsedDataType::Int);
302 datatype = parameterType(ParsedDataType::Int2);
305 datatype = parameterType(ParsedDataType::Int3);
308 datatype = parameterType(ParsedDataType::Int4);
311 src.append(
"layout(location = " + std::to_string(location) +
") out ");
312 src.append(datatype);
314 src.append(tokens[0]);
316 outputStruct.append(
" ").append(datatype).append(
" ").append(tokens[0]).append(
";\n");
317 outputExport.append(
" g_").append(tokens[0]).append(
" = Out.").append(tokens[0]).append(
";\n");
321 src.append(
"layout(location=0) out vec4 g_fragColor;\n");
322 outputStruct.append(
" vec4 fragColor;\n");
323 outputExport.append(
" g_fragColor = Out.fragColor;\n");
325 outputStruct.append(
"};\n");
326 outputExport.append(
"}\n");
327 src.append(outputStruct +
"\n");
328 src.append(outputExport +
"\n");
341 addHeadersAndInterface(src);
342 addDefines(src, desc.definitions);
343 addUniforms(src, task->properties);
344 addOutputs(src, task->options);
345 src.append(
"#include \"Engine/Common.es30.glsl\"\n\n");
346 std::string prefix_ps = desc.ps;
347 removeSuffix(prefix_ps,
".hlsl");
349 src.append(
"#include \"" + prefix_ps +
".es30.glsl\"\n");
350 auto code =
hash(src);
351 std::string file_prefix = prefix_ps +
"_" + std::to_string(code);
354 pp.
processed.reserve(::InitialBufferCapasity);
355 if (!pp.
process(context->context, src))
return false;
361 VertexIn In = importAttribs();
362 FragmentOut Out = effectMain(In);
367 context->context->resourceStore->addResource(file_prefix + ".es30.glsl", src);
368 desc.ps = file_prefix +
".hlsl";
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....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
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.
bool process(Context *context, const StringView input)
Run a text block through the preprocessor.
std::string processed
Resulting processed text.