Cogs.Core
RenderTaskFactory.cpp
1#include "RenderTaskFactory.h"
2
3#include "Serialization/RenderPipelineReader.h"
4
5#include "Systems/Core/CameraSystem.h"
6
7#include "Services/Variables.h"
8#include "Context.h"
9
10#include "GenerateListTask.h"
11#include "FilterListTask.h"
12#include "RenderListTask.h"
13
14#include "DeferredLightingTask.h"
15#include "TransparencyRenderTask.h"
16#include "TransparencyMergeTask.h"
17#include "TransparencyTemporalUpscaleTask.h"
18#include "TransparencyUpscaleTask.h"
19
20#include "PostProcessTask.h"
21#include "ComputeTask.h"
22#include "MipLevelsTask.h"
23
24#include "ClearResourceTask.h"
25#include "CopyResourceTask.h"
26#include "ResolveResourceTask.h"
27#include "ReadbackTask.h"
28
29#include "Renderer/Renderer.h"
30#include "Renderer/RenderPipelineManager.h"
31
32#include "Foundation/Logging/Logger.h"
33#include "Foundation/Collections/Pool.h"
34
35namespace
36{
37 Cogs::Logging::Log logger = Cogs::Logging::getLogger("TaskFactory");
38}
39
40namespace Cogs
41{
42 namespace Core
43 {
44 std::unordered_map<std::string, TaskCreator> creators;
45 std::unordered_map<std::string, TaskDestroyer> destroyers;
46
47 template<typename ResourceType>
48 Collections::Pool<ResourceType> & getPool()
49 {
50 static Collections::Pool<ResourceType> pool(128, 128, MemBlockType::RenderResourceStorage);
51
52 return pool;
53 }
54
55 template<typename TaskType>
56 TaskType * createTask(RenderTaskContext * renderContext, bool initialize = true)
57 {
58 auto pool = &getPool<TaskType>();
59 auto task = pool->create();
60
61 task->deleter = [=]()
62 {
63 if (renderContext) {
64 task->cleanup(renderContext);
65 }
66
67 pool->destroy(task);
68 };
69
70 if (renderContext && initialize) {
71 task->initialize(renderContext);
72 }
73
74 return task;
75 }
76
77 void freeTask(RenderTask * task, RenderTaskContext * renderContext)
78 {
79 for (auto & d : destroyers) {
80 d.second(&task, renderContext);
81 if (!task) return;
82 }
83
84 if (task->deleter) {
85 task->deleter();
86 return;
87 }
88
89 LOG_ERROR(logger, "Render task could not be deleted.");
90 }
91
92 void setProcessTaskEffectParameter(RenderTaskContext* renderContext,
93 std::list<std::unique_ptr<SubContext>>& subContexts,
94 ExpressionContext * expressionContext,
95 ProcessTask* task,
96 const ParsedValue& parameter)
97 {
98 task->effectParameter = parameter;
99
100 task->scope = expressionContext;
101 for (const auto & ep : task->effectParameter.values) {
102 if (ep.key == "useVariables") {
103 if (task->scope == expressionContext) {
104 subContexts.push_back(std::make_unique<SubContext>(expressionContext));
105 task->scope = &subContexts.back()->expressionContext;
106 }
107 subContexts.back()->useVariables(renderContext->context, ep.values);
108 }
109 else if (ep.key == "setVariables") {
110 if (task->scope == expressionContext) {
111 subContexts.push_back(std::make_unique<SubContext>(expressionContext));
112 task->scope = &subContexts.back()->expressionContext;
113 }
114 subContexts.back()->setVariables(renderContext->context, ep.values);
115 }
116 else if (ep.key == "useComponentFields") {
117 if (task->scope == expressionContext) {
118 subContexts.push_back(std::make_unique<SubContext>(expressionContext));
119 task->scope = &subContexts.back()->expressionContext;
120 }
121 subContexts.back()->useComponentFields(renderContext, ep.values);
122 }
123 }
124
125 for (const auto & ep : task->effectParameter.values) {
126 if (ep.key == "properties") {
127 for (const auto & p : ep.values) {
128 if (p.key == "source") continue;
129
130 ProcessTaskProperty prop;
131 prop.definition = &p; // is pointer valid for lifetime of task?
132 prop.float4x4Value = p.float4x4Value;
133
134 for (const auto & q : p.expressions) {
135 //auto name = prefix + "." + p.key + "." + std::to_string(q.first);
136 prop.expressions.push_back({ q.first, task->scope->compile(q.second, "") });
137 }
138 switch (p.type) {
139 case ParsedDataType::Texture2D: {
140 SamplerState samplerState {
144 (p.texture.flags & ParsedValueTextureFlags::LinearSampler) != 0 ? SamplerState::MinMagMipLinear : SamplerState::MinMagMipPoint,
145 SamplerState::Never,
146 0,
147 { 0, 0, 0, 1 }
148 };
149 prop.texture.samplerName = Strings::get(Strings::add(p.key + "Sampler"));
150 prop.texture.samplerState = renderContext->states->getSamplerState(samplerState);
151 break;
152 }
153 default:
154 break;
155 }
156 task->properties.push_back(prop);
157 }
158 }
159 else if (ep.key == "groups" && ep.values.size() == 3) {
160 task->groups.expressions.clear();
161 for (size_t i = 0; i < 3; i++) {
162 auto * e = task->scope->compile(ep.values[i].value, "");
163 if (e) {
164 task->groups.expressions.push_back({ i, e });
165 }
166 }
167 }
168
169 }
170 }
171
173 {
174 uint32_t flags = 0;
175 BucketMask bucketMask = BucketMask::All;
176 StateChangeFlags stateChangeMask = StateChangeFlags::ChangeAll;
177 size_t permutationIndex = 0;
178 RenderLayers renderMask = RenderLayers::All;
179 SortFlags sortFlags = SortFlags::Default;
180 BlendMode blendMode = BlendMode::None;
181 DepthMode depthMode = DepthMode::Default;
182 DepthFunc depthFunc = DepthFunc::Less;
183
184 bool viewportFromTarget = true; // Use render target size as viewport instead of camera viewport.
185 bool temporalOffsets = false;
186 bool clearColor = true;
187 bool clearDepth = true;
188 bool discardColor = false;
189 bool discardDepth = false;
190 bool allowSelfDependency = false;
191 bool drawCallID = false;
192 bool blendModeSet = false;
193 };
194
195 RenderTaskParameters parseParameters(RenderTaskContext * renderContext,
196 const RenderTaskDefinition & taskDefinition,
197 const PipelineOptions& options)
198 {
199 RenderTaskParameters parameters;
200
201 { // Override renderTaskParameters from pipeline options
202 ParsedValue val;
203 for (const PreprocessorDefinition& option : options) {
204 switch (StringView(option.first).hash()) {
205 case Cogs::hash("clearColor"):
206 parseStringValue(option.second, val);
207 val.asBool(parameters.clearColor);
208 break;
209 case Cogs::hash("clearDepth"):
210 parseStringValue(option.second, val);
211 val.asBool(parameters.clearDepth);
212 break;
213 default:
214 break;
215 }
216 }
217 }
218
219 for (auto & p : taskDefinition.parameters) {
220
221 switch (StringView(p.key).hash()) {
222 case Cogs::hash("bucketMask"):
223 parameters.bucketMask = parseEnumFlags(p.value, BucketMask::All);
224 break;
225 case Cogs::hash("stateChangeMask"):
226 parameters.stateChangeMask = parseEnumFlags<StateChangeFlags>(p.value, StateChangeFlags::ChangeAll);
227 break;
228 case Cogs::hash("permutation"):
229 parameters.permutationIndex = renderContext->renderer->getEnginePermutations().getIndex(p.value);
230 break;
231 case Cogs::hash("blendMode"):
232 parameters.blendMode = parseEnum(p.value, parameters.blendMode);
233 parameters.blendModeSet = true;
234 break;
235 case Cogs::hash("depthMode"):
236 parameters.depthMode = parseEnum(p.value, parameters.depthMode);
237 break;
238 case Cogs::hash("depthFunc"):
239 parameters.depthFunc = parseEnum(p.value, parameters.depthFunc);
240 break;
241 case Cogs::hash("clear"):
242 p.asBool(parameters.clearColor);
243 parameters.clearDepth = parameters.clearColor;
244 break;
245 case Cogs::hash("clearDepth"):
246 p.asBool(parameters.clearDepth);
247 break;
248 case Cogs::hash("clearColor"):
249 p.asBool(parameters.clearColor);
250 break;
251 case Cogs::hash("discardDepth"):
252 p.asBool(parameters.discardDepth);
253 break;
254 case Cogs::hash("discardColor"):
255 p.asBool(parameters.discardColor);
256 break;
257 case Cogs::hash("viewportFromTarget"):
258 p.asBool(parameters.viewportFromTarget);
259 break;
260 case Cogs::hash("temporalOffsets"):
261 p.asBool(parameters.temporalOffsets);
262 break;
263 case Cogs::hash("allowSelfDependency"):
264 p.asBool(parameters.allowSelfDependency);
265 break;
266 case Cogs::hash("flags"):
267 parameters.flags = parseEnumFlags(p.value, RenderTaskFlags::None);
268 break;
269 case Cogs::hash("drawCallID"):
270 p.asBool(parameters.drawCallID);
271 break;
272 case Cogs::hash("renderMask"): {
273 parameters.renderMask = parseEnumFlags(p.value, RenderLayers::None);
274 break;
275 }
276 case Cogs::hash("sortFlags"):
277 parameters.sortFlags = parseEnumFlags<SortFlags>(p.value, parameters.sortFlags);
278 break;
279
280 default:
281 break;
282 }
283 }
284
285 return parameters;
286 }
287 }
288}
289
290Cogs::Core::RenderTask * Cogs::Core::createRenderTask(RenderTaskContext * renderContext,
291 const RenderTaskDefinition & taskDefinition,
292 std::list<std::unique_ptr<SubContext>>& subContexts,
293 ExpressionContext * expressionContext,
294 const PipelineOptions & options)
295{
296 RenderTask * task = nullptr;
297
298 auto parameters = parseParameters(renderContext, taskDefinition, options);
299
300 if (taskDefinition.type == "GenerateList") {
301 task = createTask<GenerateListTask>(renderContext);
302 task->initialize(renderContext);
303 } else if (taskDefinition.type == "Filter") {
304 FilterListTask* filterTask = createTask<FilterListTask>(renderContext);
305 filterTask->bucketMask = parameters.bucketMask;
306 filterTask->permutation = parameters.permutationIndex;
307 filterTask->drawCallID = parameters.drawCallID;
308 filterTask->renderMask = parameters.renderMask;
309 filterTask->sortFlags = parameters.sortFlags;
310 filterTask->blendMode = parameters.blendMode;
311 filterTask->blendModeSet = parameters.blendModeSet;
312
313 const CameraData* cameraData = &renderContext->context->cameraSystem->getMainCameraData();
314
315 if (renderContext->cameraData != cameraData) {
316 filterTask->viewportData = renderContext->cameraData;
317 } else {
318 // Main camera data should not be taken a direct dependency on.
319 filterTask->viewportData = nullptr;
320 }
321
322 task = filterTask;
323 } else if (taskDefinition.type == "RenderList") {
324 auto renderTask = createTask<RenderListTask>(renderContext, false);
325 renderTask->bucketMask = parameters.bucketMask;
326 renderTask->stateChangeMask = parameters.stateChangeMask;
327 renderTask->permutationIndex = parameters.permutationIndex;
328 renderTask->colorClear = parameters.clearColor;
329 renderTask->depthClear = parameters.clearDepth;
330 renderTask->discardColor = parameters.discardColor;
331 renderTask->discardDepth = parameters.discardDepth;
332 renderTask->viewportFromTarget = parameters.viewportFromTarget;
333 renderTask->temporalOffsets = parameters.temporalOffsets;
334 renderTask->blendMode = parameters.blendMode;
335 renderTask->depthMode = parameters.depthMode;
336 renderTask->depthFunc = parameters.depthFunc;
337 renderTask->initialize(renderContext);
338 task = renderTask;
339 } else if (taskDefinition.type == "DeferredLighting") {
340 auto defTask = createTask<DeferredLightingTask>(renderContext);
341 defTask->clear = parameters.clearColor;
342 defTask->clearToDefault = true;
343 task = defTask;
344 } else if (taskDefinition.type == "TransparencyRender") {
345 auto tTask = createTask<TransparencyRenderTask>(renderContext);
346 tTask->bucketMask = parameters.bucketMask;
347 tTask->viewportFromTarget = parameters.viewportFromTarget;
348 tTask->temporalOffsets = parameters.temporalOffsets;
349 task = tTask;
350 } else if (taskDefinition.type == "TransparencyMerge") {
351 task = createTask<TransparencyMergeTask>(renderContext);
352 } else if (taskDefinition.type == "TransparencyTemporalUpscale") {
353 task = createTask<TransparencyTemporalUpscaleTask>(renderContext);
354 } else if (taskDefinition.type == "TransparencyUpscale") {
355 task = createTask<TransparencyUpscaleTask>(renderContext);
356 } else if (taskDefinition.type == "PostProcess") {
357 PostProcessTask* pTask = createTask<PostProcessTask>(renderContext, false);
358 pTask->viewportFromTarget = parameters.viewportFromTarget;
359 for (auto & p : taskDefinition.parameters) {
360 if (p.key == "effect") {
361 setProcessTaskEffectParameter(renderContext, subContexts, expressionContext, pTask, p);
362 } else if (p.key == "blendMode") {
363 pTask->blendMode = parseEnum<BlendMode>(p.value, pTask->blendMode);
364 } else if (p.key == "writeDepth") {
365 pTask->writeDepth = p.asBool(pTask->writeDepth);
366 }
367 }
368
369 pTask->initialize(renderContext);
370
371 task = pTask;
372 } else if (taskDefinition.type == "ClearResource") {
373 auto pTask = createTask<ClearResourceTask>(renderContext);
374
375 for (auto & p : taskDefinition.parameters) {
376 if (p.key == "destinationIndex") {
377 readSize_t(pTask->destinationIndex, expressionContext, taskDefinition.name, p);
378 }
379 else if (p.key == "fill") {
380 if (p.type == ParsedDataType::UInt) {
381 pTask->fill_float = false;
382 for(uint32_t i=0; i<4; i++)
383 pTask->fill.UValues[i] = p.uintValue;
384 }
385 else if (p.type == ParsedDataType::Float) {
386 pTask->fill_float = true;
387 for(uint32_t i=0; i<4; i++)
388 pTask->fill.FValues[i] = p.floatValue;
389 }
390 }
391 }
392
393 task = pTask;
394 } else if (taskDefinition.type == "CopyResource") {
395 auto pTask = createTask<CopyResourceTask>(renderContext);
396
397 for (auto & p : taskDefinition.parameters) {
398 if (p.key == "sourceIndex") {
399 readSize_t(pTask->sourceIndex, expressionContext, taskDefinition.name, p);
400 } else if (p.key == "destinationIndex") {
401 readSize_t(pTask->destinationIndex, expressionContext, taskDefinition.name, p);
402 }
403 }
404
405 task = pTask;
406 } else if (taskDefinition.type == "ResolveResource") {
407 task = createTask<ResolveResourceTask>(renderContext);
408 } else if (taskDefinition.type == "Readback") {
409 auto pTask = createTask<ReadbackTask>(renderContext);
410
411 for (auto & p : taskDefinition.parameters) {
412 if (p.key == "bufferIndex") {
413 readSize_t(pTask->bufferIndex, expressionContext, taskDefinition.name, p);
414 } else if (p.key == "size") {
415 readSize_t(pTask->size, expressionContext, taskDefinition.name, p);
416 } else if (p.key == "readbackKey") {
417 pTask->key = p.value;
418 }
419 }
420
421 task = pTask;
422 } else if (taskDefinition.type == "Compute") {
423 auto pTask = createTask<ComputeTask>(renderContext, false);
424
425 for (auto & p : taskDefinition.parameters) {
426 if (p.key == "effect") {
427 setProcessTaskEffectParameter(renderContext, subContexts, expressionContext, pTask, p);
428 }
429 }
430
431 pTask->initialize(renderContext);
432
433 task = pTask;
434 } else if (taskDefinition.type == "MipLevels") {
435 auto pTask = createTask<MipLevelsTask>(renderContext, false);
436
437 for (auto & p : taskDefinition.parameters) {
438 if (p.key == "effect") {
439 setProcessTaskEffectParameter(renderContext, subContexts, expressionContext, pTask, p);
440 } else if (p.key == "firstLevel") {
441 readSize_t(pTask->firstLevel, expressionContext, std::to_string((size_t)(pTask)) + ".firstLevel", p);
442 } else if (p.key == "lastLevel") {
443 readSize_t(pTask->lastLevel, expressionContext, std::to_string((size_t)(pTask)) + ".lastLevel", p);
444 } else if (p.key == "blendMode") {
445 pTask->blendMode = parseEnum<BlendMode>(p.value, pTask->blendMode);
446 }
447 }
448 pTask->initialize(renderContext);
449 task = pTask;
450 } else {
451 auto fIt = creators.find(taskDefinition.type);
452
453 if (fIt != creators.end()) {
454 task = fIt->second(renderContext, taskDefinition, options);
455 task->initialize(renderContext);
456 }
457 }
458
459 if (!task) {
460 LOG_ERROR(logger, "Could not create task of type %s.", taskDefinition.type.c_str());
461 return nullptr;
462 }
463
464 task->name = taskDefinition.name;
465 task->options = options;
466 task->flags = (RenderTaskFlags::ERenderTaskFlags)parameters.flags;
467 task->allowSelfDependency = parameters.allowSelfDependency;
468
469 return task;
470}
471
472void Cogs::Core::destroyRenderTask(RenderTaskContext* renderContext, RenderTask* task)
473{
474 freeTask(task, renderContext);
475}
476
477void Cogs::Core::addTaskType(const StringView & key, TaskCreator creator, TaskDestroyer destroyer)
478{
479 creators[key.to_string()] = creator;
480 destroyers[key.to_string()] = destroyer;
481}
482
483void Cogs::Core::freeTasks(std::vector<RenderTask *> & tasks, RenderTaskContext * renderContext)
484{
485 for (auto & task : tasks) {
486 if (!(task->flags & RenderTaskFlags::Persistent)) {
487 freeTask(task, renderContext);
488 }
489 }
490}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr size_t hash() const noexcept
Get the hash code of the string.
Definition: StringView.h:200
BlendMode
Defines blending modes for rendering.
@ None
No blending enabled for opaque shapes, defaults to Blend for transparent shapes.
DepthMode
Defines common depth stencil modes.
@ Default
Default, depth test & write enabled.
DepthFunc
Defines common depth functions.
RenderLayers
Contains common render layers.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
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
std::pair< std::string, std::string > PreprocessorDefinition
Preprocessor definition.
Definition: IEffects.h:10
Stores the parsed output of a key/value pair.
Definition: Parsing.h:32
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35