Cogs.Core
RenderPipelineFactory.cpp
1#include "RenderPipelineFactory.h"
2
3#include "Context.h"
4
5#include "Renderer/Renderer.h"
6#include "Renderer/RenderPipelineManager.h"
7
8#include "Resources/Texture.h"
9#include "Resources/TextureManager.h"
10
11#include "Tasks/RenderTask.h"
12
13#include "Utilities/Parsing.h"
14
15#include "RenderResources.h"
16
17#include "RenderTexture.h"
18#include "RenderTarget.h"
19#include "RenderBuffer.h"
20#include "RenderList.h"
21
22#include "Foundation/HashSequence.h"
23#include "Foundation/Logging/Logger.h"
24
25namespace
26{
27 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderPipelineFactory");
28}
29
30namespace Cogs::Core
31{
32 bool evaluateCondition(Context * context,
33 const StringView & condition,
34 const RenderPipelineDefinition & pipelineDefinition,
35 const std::vector<ParsedValue>& attributes)
36 {
37 thread_local static std::vector<StringView> tokens;
38 tokens.clear();
39
40 if (!condition.size()) return true;
41
42
43 split(condition, "$=", tokens);
44
45 assert((tokens.size() % 2 == 0) && "Token array must be multiple of two");
46
47 bool totalConditionMet = true;
48
49 for (size_t i = 0; i < tokens.size(); i += 2) {
50 bool conditionMet = false;
51
52 const auto key = tokens[i];
53 const auto expected = tokens[i + 1];
54
55 for (auto & o : pipelineDefinition.options) {
56 if (key == o.key) {
57 bool handled = false;
58
59 // First, check attributes
60 for (const auto & attribute : attributes) {
61 if (key != StringView(attribute.key)) continue;
62
63 handled = true;
64 if (StringView(attribute.value) == expected) {
65 conditionMet = true;
66 break;
67 }
68 }
69
70 StringView def("");
71 if (!o.values.empty()) {
72 def = o.values.front();
73 }
74
75 if (!handled && !o.setting.empty()) {
76 // Otherwise, check variables.
77 const auto setting = context->variables->get(o.setting, def);
78 if (!setting.empty()) {
79 if (setting == expected) {
80 conditionMet = true;
81 break;
82 }
83 handled = true;
84 }
85 }
86 if (!handled && !def.empty()) {
87 // And finally revert to default value.
88 if (def == expected) {
89 conditionMet = true;
90 break;
91 }
92 }
93 }
94 }
95
96 totalConditionMet = totalConditionMet && conditionMet;
97 }
98 return totalConditionMet;
99 }
100
101 void evaluateTaskDependencies(std::list<RenderTask *> tasks, const RenderTaskResources & globalResources, RenderPipeline & pipeline)
102 {
103 auto findResource = [&](const RenderTask * task, const RenderTaskResource & input, bool allow_self_dependency) -> bool
104 {
105 auto globalResource = globalResources.get(input.name);
106
107 if (globalResource) {
108 return true;
109 }
110
111 if (input.resource->isPersistent()) {
112 return true;
113 }
114
115 if(allow_self_dependency){
116 auto t = task;
117 for (auto & output : t->output.resources) {
118 if (output.resource->getName() == input.resource->getName()) {
119 return true;
120 } else if (input.type == RenderResourceType::RenderTexture && output.type == RenderResourceType::RenderTarget) {
121 for (auto & texture : output.renderTarget->textures) {
122 if (texture->getName() == input.resource->getName()) {
123 return true;
124 }
125 }
126 if (output.renderTarget->depth) {
127 if (output.renderTarget->depth->getName() == input.resource->getName()) {
128 return true;
129 }
130 }
131 }
132 }
133 }
134 for (auto & t : pipeline.tasks) {
135 for (auto & output : t->output.resources) {
136 if (output.resource->getName() == input.resource->getName()) {
137 return true;
138 } else if (input.type == RenderResourceType::RenderTexture && output.type == RenderResourceType::RenderTarget) {
139 for (auto & texture : output.renderTarget->textures) {
140 if (texture->getName() == input.resource->getName()) {
141 return true;
142 }
143 }
144 if (output.renderTarget->depth) {
145 if (output.renderTarget->depth->getName() == input.resource->getName()) {
146 return true;
147 }
148 }
149 }
150 }
151 }
152
153 return false;
154 };
155
156 auto findDependency = [&](const RenderTask * task, const StringView & d, bool allow_self_dependency) -> bool
157 {
158 if(allow_self_dependency){
159 for(auto & o : task->output.resources) {
160 if (d == o.name) {
161 return true;
162 }
163 }
164 }
165 for (auto & t : pipeline.tasks) {
166 if (d == t->name) {
167 return true;
168 }
169
170 for (auto & o : t->output.resources) {
171 if (d == o.name) {
172 return true;
173 }
174 }
175 }
176
177 return false;
178 };
179
180 auto findPrerequisites = [&](const RenderTask * task) -> bool
181 {
182 bool foundResources = true;
183 bool foundDependencies = true;
184 bool allowSelfDependency = task->allowSelfDependency;
185
186 for (auto & input : task->input.resources) {
187 foundResources &= findResource(task, input, allowSelfDependency);
188 }
189
190 for (auto & d : task->dependencies) {
191 foundDependencies &= findDependency(task, d, allowSelfDependency);
192 }
193
194 return foundResources && foundDependencies;
195 };
196
197 while (tasks.size()) {
198 auto nextTaskIt = std::find_if(tasks.begin(), tasks.end(), findPrerequisites);
199
200 if (nextTaskIt != tasks.end()) {
201 pipeline.tasks.push_back(*nextTaskIt);
202 tasks.erase(nextTaskIt);
203 } else {
204 LOG_ERROR(logger, "Unable to determine processing order for the following tasks:");
205 for (auto task : tasks) {
206 LOG_ERROR(logger, " %s", task->name.c_str());
207 }
208 break;
209 }
210 }
211 }
212
213 bool addVariable(ExpressionContext * expressionContext, StringView name, const ParsedValue & p)
214 {
215 if (p.type == ParsedDataType::Float) {
216 expressionContext->add(name, p.floatValue);
217 } else if (p.type == ParsedDataType::Int) {
218 expressionContext->add(name, p.intValue);
219 } else if (p.type == ParsedDataType::UInt) {
220 expressionContext->add(name, p.uintValue);
221 } else if (p.type == ParsedDataType::Bool) {
222 expressionContext->add(name, p.boolValue ? 1 : 0);
223 } else if (p.type == ParsedDataType::String) {
224 expressionContext->add(name, parseDouble(p.value, 0));
225 } else {
226 LOG_ERROR(logger, "Invalid variable type for %.*s", StringViewFormat(name));
227 return false;
228 }
229
230 return true;
231 }
232
233 RenderBuffer * createRenderBuffer(RenderResources * renderResources, const std::string & resourceName, const RenderResourceDefinition & r, ExpressionContext * expressionContext)
234 {
235 auto renderBuffer = renderResources->createRenderBuffer();
236 renderBuffer->setName(resourceName);
237 if (r.getParameter("persistent", false)) {
238 renderBuffer->setPersistent();
239 }
240
241 renderBuffer->parameters = r.parameters;
242
243 for (auto & p : r.parameters) {
244 auto name = r.name + "." + p.key;
245 addVariable(expressionContext, name, p);
246
247 const size_t code = StringView(p.key).hash();
248 switch (code) {
249 case Cogs::hash("elementSize"):
250 case Cogs::hash("stride"):
251 readSize_t(renderBuffer->elementSize, expressionContext, r.name, p);
252 break;
253 case Cogs::hash("elementCount"):
254 readSize_t(renderBuffer->elementCount, expressionContext, r.name, p);
255 break;
256 case Cogs::hash("bufferSize"):
257 readSize_t(renderBuffer->bufferSize, expressionContext, r.name, p);
258 break;
259 case Cogs::hash("bufferCount"):
260 readSize_t(renderBuffer->bufferCount, expressionContext, r.name, p);
261 break;
262 default:
263 break;
264 }
265 }
266
267 return renderBuffer;
268 }
269
270 RenderTexture * createRenderTexture(RenderTaskContext * renderContext,
271 RenderPipeline & pipeline,
272 RenderTaskResources & pipelineResources,
273 const std::string & resourceName,
274 const std::string & prefix,
275 const RenderResourceDefinition & r,
276 ExpressionContext * expressionContext)
277 {
278 auto texture = renderContext->context->textureManager->create();
279 texture->setName(resourceName);
280 texture->setResident();
281
282 pipeline.resourceHandles.push_back(texture);
283
284 auto renderTexture = renderContext->resources->createRenderTexture();
285 texture->attachResource(renderTexture);
286
287 renderTexture->setName(resourceName);
288 renderTexture->setResource(texture.resolve());
289
290 if (r.getParameter("persistent", false)) {
291 renderTexture->setPersistent();
292 }
293 renderTexture->setOwned();
294
295 auto format = r.getParameter("format", "R8G8B8A8_UNORM_SRGB");
296 renderTexture->description.format = parseTextureFormat(format ? format->value : "R8G8B8A8_UNORM_SRGB");
297 renderTexture->description.flags = TextureFlags::Texture | ((r.getParameter("flags", "") != nullptr) ? TextureFlags::DepthBuffer : TextureFlags::RenderTarget);
298 renderTexture->description.samples = r.getParameter("samples", 1);
299
300 // TODO should these be prefixed?
301 expressionContext->add(r.name + ".width", 0.0);
302 expressionContext->add(r.name + ".height", 0.0);
303
304 renderTexture->width = { expressionContext, r.name + ".width", std::to_string(renderTexture->width.get(0)), 0 };
305 renderTexture->height = { expressionContext, r.name + ".height", std::to_string(renderTexture->height.get(0)), 0 };
306
307 for (auto& p : r.parameters) {
308 const size_t code = StringView(p.key).hash();
309 switch (code) {
310 case Cogs::hash("format"):
311 case Cogs::hash("flags"):
312 break;
313 case Cogs::hash("sizeSource"):
314 renderTexture->sizeSource = pipelineResources.get(prefix + p.value)->resource;
315 break;
316 case Cogs::hash("clearColor"):
317 // Set clear color
318 switch (p.type) {
319 case ParsedDataType::Int4:
320 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = static_cast<float>(p.int4Value[i]); }
321 renderTexture->clearColorSet = true;
322 break;
323 case ParsedDataType::UInt4:
324 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = static_cast<float>(p.uint4Value[i]); }
325 renderTexture->clearColorSet = true;
326 break;
327 case ParsedDataType::Float4:
328 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = p.float4Value[i]; }
329 renderTexture->clearColorSet = true;
330 break;
331 default:
332 LOG_ERROR(logger, "Texture clear color was not a 4-component vector of int nor floats");
333 break;
334 }
335 break;
336
337 default: {
338
339 // Add as variable
340 std::string name = r.name + "." + p.key;
341 addVariable(expressionContext, name, p);
342 switch (code) {
343 case Cogs::hash("width"):
344 readSize_t(renderTexture->width, expressionContext, r.name, p);
345 break;
346 case Cogs::hash("height"):
347 readSize_t(renderTexture->height, expressionContext, r.name, p);
348 break;
349 case Cogs::hash("levels"):
350 readSize_t(renderTexture->levels, expressionContext, r.name, p);
351 break;
352 case Cogs::hash("layers"):
353 readSize_t(renderTexture->layers, expressionContext, r.name, p);
354 break;
355 case Cogs::hash("faces"):
356 readSize_t(renderTexture->faces, expressionContext, r.name, p);
357 break;
358 case Cogs::hash("samples"):
359 readSize_t(renderTexture->samples, expressionContext, r.name, p);
360 break;
361 default:
362 break;
363 }
364 }
365 }
366 }
367
368 return renderTexture;
369 }
370
371 bool handleResourceAlias(const RenderResourceDefinition & r, const std::string & resourceName, const std::string & prefix, RenderTaskResources & pipelineResources)
372 {
373 if (r.alias.size()) {
374 auto aliasedResource = pipelineResources.get(prefix + r.alias);
375
376 if (aliasedResource) {
377 pipelineResources.add(aliasedResource, resourceName);
378 } else {
379 if (r.type != RenderResourceType::RenderTarget) {
380 LOG_ERROR(logger, "Error aliasing resource %s to %s.", r.name.c_str(), resourceName.c_str());
381 }
382 }
383
384 return true;
385 }
386
387 return false;
388 }
389
390 bool createPipelineRecursive(Cogs::Core::RenderTaskContext * renderContext,
391 const Cogs::Core::RenderPipelineDefinition & pipelineDefinition,
392 Cogs::Core::RenderTaskResources & pipelineResources,
394 const Cogs::Core::PipelineOptions & options,
395 Cogs::Core::ExpressionContext* expressionContext,
396 const std::vector<ParsedValue>& attributes,
397 const std::string & prefix,
398 const std::string & prefixOuter)
399 {
400 pipelineResources.resources.reserve(100);
401
402 auto globalResources = pipelineResources;
403
404 for (auto & option : pipelineDefinition.options) {
405 pipeline.dependsVariables.push_back(option.setting);
406 }
407
408 if (!pipelineDefinition.useVariables.empty() ||
409 !pipelineDefinition.setVariables.empty() ||
410 !pipelineDefinition.useComponentFields.empty()) {
411 pipeline.subContexts.push_back(std::make_unique<SubContext>(expressionContext));
412 expressionContext = &pipeline.subContexts.back()->expressionContext;
413 pipeline.subContexts.back()->useVariables(renderContext->context, pipelineDefinition.useVariables);
414 pipeline.subContexts.back()->setVariables(renderContext->context, pipelineDefinition.setVariables);
415 pipeline.subContexts.back()->useComponentFields(renderContext, pipelineDefinition.useComponentFields);
416 }
417
418 for (auto& r : pipelineDefinition.inputs) {
419 auto resource = pipelineResources.get(prefix + r.key);
420
421 if (resource->type == RenderResourceType::RenderTexture || resource->type == RenderResourceType::RenderTarget) {
422 // Try to figure out prefix-less name in outer-scope.
423 const auto preStrip = prefixOuter.length();
424 StringView nameOuter = resource->name;
425 if (preStrip <= nameOuter.length() && nameOuter.substr(0, preStrip).compare(prefixOuter) == 0) {
426 nameOuter = nameOuter.substr(preStrip);
427 }
428
429 if (resource->type == RenderResourceType::RenderTexture || nameOuter == "Cogs.BackBuffer") {
430 expressionContext->link(expressionContext, nameOuter.to_string() + ".width", r.key + ".width");
431 expressionContext->link(expressionContext, nameOuter.to_string() + ".height", r.key + ".height");
432 }
433 }
434 }
435 for (auto& r : pipelineDefinition.outputs) {
436 auto resource = pipelineResources.get(prefix + r.key);
437
438 if (resource->type == RenderResourceType::RenderTexture || resource->type == RenderResourceType::RenderTarget) {
439 // Try to figure out prefix-less name in outer-scope.
440 const auto preStrip = prefixOuter.length();
441 StringView nameOuter = resource->name;
442 if (preStrip <= nameOuter.length() && nameOuter.substr(0, preStrip).compare(prefixOuter) == 0) {
443 nameOuter = nameOuter.substr(preStrip);
444 }
445
446 expressionContext->link(expressionContext, nameOuter.to_string() + ".width", r.key + ".width");
447 expressionContext->link(expressionContext, nameOuter.to_string() + ".height", r.key + ".height");
448 }
449 }
450
451 for (auto & r : pipelineDefinition.resources) {
452 auto resourceName = prefix + r.name;
453
454 if (!evaluateCondition(renderContext->context, r.condition, pipelineDefinition, attributes)) continue;
455
456 if (handleResourceAlias(r, resourceName, prefix, pipelineResources)) continue;
457
458 switch (r.type) {
459 case RenderResourceType::RenderBuffer:
460 {
461 auto renderBuffer = createRenderBuffer(renderContext->resources, resourceName, r, expressionContext);
462
463 pipelineResources.add(renderBuffer, resourceName);
464 pipeline.resources.add(renderBuffer, resourceName);
465 }
466 break;
467 case RenderResourceType::RenderList:
468 {
469 auto renderList = renderContext->resources->createRenderList();
470 renderList->setName(resourceName);
471
472 pipelineResources.add(renderList, resourceName);
473 pipeline.resources.add(renderList, resourceName);
474 }
475 break;
476 case RenderResourceType::RenderTexture:
477 {
478 auto renderTexture = createRenderTexture(renderContext, pipeline, pipelineResources, resourceName, prefix, r, expressionContext);
479
480 pipelineResources.add(renderTexture, resourceName);
481 pipeline.resources.add(renderTexture, resourceName);
482 }
483 break;
484 default:
485 break;
486 }
487 }
488
489 for (auto & r : pipelineDefinition.resources) {
490 auto resourceName = prefix + r.name;
491
492 if (!evaluateCondition(renderContext->context, r.condition, pipelineDefinition, attributes)) continue;
493
494 if (handleResourceAlias(r, resourceName, prefix, pipelineResources)) continue;
495
496 if (r.type == RenderResourceType::RenderTarget) {
497 auto renderTarget = renderContext->resources->createRenderTarget();
498 renderTarget->setName(resourceName);
499
500 bool has_expression = false;
501 auto depth = r.getParameter("depth", "");
502 if (depth) {
503 auto depthTexture = pipelineResources.get(prefix + depth->value);
504
505 if (!depthTexture) {
506 auto format = parseTextureFormat(depth->value);
507
508 if (format != TextureFormat::Unknown) {
509 auto depthName = resourceName + ":DepthTexture";
510 auto depth_rtex = renderContext->resources->createRenderTexture();
511 depth_rtex->setName(depthName);
512 depth_rtex->description.flags = TextureFlags::DepthBuffer | TextureFlags::Texture;
513 depth_rtex->description.format = format;
514
515 renderTarget->depth = depth_rtex;
516
517 pipelineResources.add(depth_rtex, depthName);
518 pipeline.resources.add(depth_rtex, depthName);
519 }
520 } else {
521 renderTarget->depth = depthTexture->renderTexure;
522 expressionContext->link(expressionContext, depth->value + ".width", r.name + ".width");
523 expressionContext->link(expressionContext, depth->value + ".height", r.name + ".height");
524 has_expression = true;
525 }
526 }
527
528 auto clearColor = r.getParameter("clearColor", "");
529 if (clearColor && clearColor->type == ParsedDataType::Float4) {
530 renderTarget->clearColors = { clearColor->float4Value };
531 }
532
533 auto levels = r.getParameter("levels", "");
534 if (levels) {
535 readSize_t(renderTarget->levels, expressionContext, r.name + std::to_string((size_t)renderTarget), *levels);
536 }
537
538 size_t textureIndex = 0;
539 for (auto & t : r.textures) {
540 auto name = prefix + t;
541 auto textureResource = pipelineResources.get(name);
542
543 if (textureResource) {
544 renderTarget->textures.push_back(textureResource->renderTexure);
545 if (!has_expression) {
546 expressionContext->link(expressionContext, t + ".width", r.name + ".width");
547 expressionContext->link(expressionContext, t + ".height", r.name + ".height");
548 has_expression = true;
549 }
550 } else {
551 auto format = parseTextureFormat(t);
552
553 if (format != TextureFormat::Unknown) {
554 auto textureName = resourceName + ":Texture" + std::to_string(textureIndex++);
555
556 auto texture = renderContext->resources->createRenderTexture();
557 texture->setName(textureName);
558 texture->description.format = format;
559 texture->description.flags = TextureFlags::Texture | TextureFlags::RenderTarget;
560
561 renderTarget->textures.push_back(texture);
562
563 pipelineResources.add(texture, textureName);
564 pipeline.resources.add(texture, textureName);
565 } else {
566 LOG_ERROR(logger, "Could not resolve resource %s.", name.c_str());
567 }
568 }
569 }
570
571 pipelineResources.add(renderTarget, resourceName);
572 pipeline.resources.add(renderTarget, resourceName);
573 }
574 }
575
576 std::list<RenderTask *> tasks;
577
578 for (auto & t : pipelineDefinition.tasks) {
579 if (!evaluateCondition(renderContext->context, t.condition, pipelineDefinition, attributes)) continue;
580
581 if (t.type[0] == '$') {
582 bool found = false;
583
584 for (auto & p : renderContext->renderer->getPipelineManager()->nameMap) {
585 if (p.first == t.type.substr(1)) {
586 auto & g = renderContext->renderer->getPipelineManager()->definitionByKey(renderContext->context, p.second);
587
588 auto gPrefix = prefix + t.name;
589
590 PipelineOptions gOptions;
591
592 for (auto & o : t.options) {
593 gOptions.push_back({ o.key, o.value });
594 }
595
596 RenderTaskResources gResources;
597 for (size_t i = 0; i < 2; ++i) {
598 gResources.add(&pipelineResources.resources[i]);
599 }
600
601 for (auto & input : g.inputs) {
602 bool handled = false;
603 for (auto & ii : t.inputs) {
604 if (ii.key == input.key) {
605 const auto resourceName = prefix + ii.value;
606 if (auto * resource = pipelineResources.get(resourceName); resource) {
607 gResources.add(resource, gPrefix + input.key);
608 handled = true;
609 } else {
610 LOG_ERROR(logger, "In task %s.%s, failed to find input resource '%s'.", pipelineDefinition.name.c_str(), t.name.c_str(), resourceName.c_str());
611 goto bail;
612 }
613 }
614 }
615 if (!handled) {
616 LOG_ERROR(logger, "In task %s.%s, un-matched input key '%s'", pipelineDefinition.name.c_str(), t.name.c_str(), input.key.c_str());
617 goto bail;
618 }
619 }
620
621 for (auto & output : g.outputs) {
622 bool handled = false;
623 for (auto & oo : t.outputs) {
624
625 if ((g.outputs.size() == 1 && t.outputs.size() == 1 && oo.key.empty())
626 || (oo.key == output.key)) {
627 const auto resourceName = prefix + oo.value;
628 if (auto * resource = pipelineResources.get(resourceName); resource) {
629 gResources.add(resource, gPrefix + output.key);
630 handled = true;
631 } else {
632 LOG_ERROR(logger, "In task %s.%s, failed to find output resource '%s'.", pipelineDefinition.name.c_str(), t.name.c_str(), resourceName.c_str());
633 goto bail;
634 }
635 } else {
636 LOG_WARNING(logger, "In task %s.%s, unhandled output key='%s', value='%s'", pipelineDefinition.name.c_str(), t.name.c_str(), oo.key.c_str(), oo.value.c_str());
637 }
638 }
639 if (!handled) {
640 LOG_ERROR(logger, "In task %s.%s, un-matched output key '%s'", pipelineDefinition.name.c_str(), t.name.c_str(), output.key.c_str());
641 goto bail;
642 }
643
644 }
645
646 createPipelineRecursive(renderContext, g, gResources, pipeline, gOptions, expressionContext, attributes, gPrefix, prefix);
647
648 for (auto tt : pipeline.tasks) {
649 tasks.push_back(tt);
650 }
651
652 bail:
653 pipeline.tasks.clear();
654
655 found = true;
656 break;
657 }
658 }
659 if (!found)
660 LOG_ERROR(logger, "Failed to resolve pipeline type '%s'", t.type.c_str());
661 continue;
662 }
663
664 auto tt = t;
665 tt.name = prefix + tt.name;
666
667 auto task = createRenderTask(renderContext, tt, pipeline.subContexts, expressionContext, options);
668
669 if (!task) {
670 LOG_ERROR(logger, "Pipeline task chain incomplete.");
671 return false;
672 }
673
674 task->name = tt.name;
675 for (auto & d : t.dependencies) {
676 auto dependencyName = prefix + d;
677
678 auto r = pipelineResources.get(dependencyName);
679
680 if (r != nullptr) {
681 task->dependencies.push_back(r->name);
682 } else {
683 task->dependencies.push_back(prefix + d);
684 }
685 }
686
687 for (auto & input : t.inputs) {
688 const std::string resourceName = prefix + input.value;
689 if (RenderTaskResource* resource = pipelineResources.get(resourceName); resource) {
690 if (!input.key.empty()) {
691 task->input.add(pipelineResources.get(prefix + input.value), input.key);
692 }
693 else {
694 task->input.add(pipelineResources.get(prefix + input.value), input.value);
695 }
696 }
697 else {
698 LOG_ERROR(logger, "Unknown pipeline resource '%s'", resourceName.c_str());
699 return false;
700 }
701 }
702
703 for (auto & output : t.outputs) {
704 if (output.key.size()) {
705 task->output.add(pipelineResources.get(prefix + output.value), output.key);
706 } else {
707 task->output.add(pipelineResources.get(prefix + output.value), output.value);
708 }
709 }
710
711 tasks.push_back(task);
712 }
713
714 if (prefix.size()) {
715 for (auto t : tasks) {
716 pipeline.tasks.push_back(t);
717 }
718
719 return true;
720 }
721
722 evaluateTaskDependencies(tasks, globalResources, pipeline);
723
724 return true;
725 }
726
727
728 size_t pipelineHash(RenderTaskContext * renderContext, const RenderPipeline & pipeline)
729 {
730 size_t hashValue = Cogs::hash();
731
732 for (const std::string& vars : pipeline.dependsVariables) {
733 hashValue = hash(renderContext->context->variables->get(vars, StringView()), hashValue);
734 }
735 return hashValue;
736 }
737}
738
739bool Cogs::Core::createPipeline(RenderTaskContext * renderContext,
740 const RenderPipelineDefinition & pipelineDefinition,
741 RenderTaskResources & pipelineResources,
742 RenderPipeline & pipeline,
743 const StringView & path, // used to pull query-part as options.
744 const CameraData* cameraData,
745 const PipelineOptions & options,
746 const std::string & prefix)
747{
748
749 pipeline.expressionContext.clear();
750 pipeline.expressionContext.inherit(renderContext->expressionContext);
751
752 std::vector<ParsedValue> attributes;
753 auto queryLoc = path.find("?");
754 if (queryLoc != StringView::NoPosition) {
755 parseQueryString(attributes, path.substr(queryLoc + 1));
756 }
757
758 const CameraData* cameraDataSaved = renderContext->cameraData;
759 if (cameraData) {
760 renderContext->cameraData = cameraData;
761 }
762
763 ExpressionContext* expressionContextSave = renderContext->expressionContext;
764 renderContext->expressionContext = &pipeline.expressionContext;
765
766 bool rv = false;
767 if (createPipelineRecursive(renderContext, pipelineDefinition, pipelineResources, pipeline, options, &pipeline.expressionContext, attributes, prefix, "")) {
768 pipeline.dependsVariables.sort();
769 pipeline.dependsVariables.unique();
770 pipeline.hash = pipelineHash(renderContext, pipeline);
771 rv = true;
772 }
773
774 renderContext->expressionContext = expressionContextSave;
775 renderContext->cameraData = cameraDataSaved;
776 return rv;
777}
778
779bool Cogs::Core::isPipelineFresh(RenderTaskContext * renderContext, const RenderPipeline & pipeline)
780{
781 return pipeline.hash == pipelineHash(renderContext, pipeline);
782}
783
784void Cogs::Core::releasePipeline(RenderTaskContext * renderContext, RenderPipeline & pipeline)
785{
786 for (auto & r : pipeline.resources.resources) {
787 if (!r.resource->isOwned()) {
788 renderContext->resources->releaseResource(r.resource);
789 renderContext->resources->destroyResource(r.resource);
790 } else {
791 renderContext->resources->releaseResource(r.resource);
792 }
793 }
794
795 pipeline.resources.resources.clear();
796 pipeline.resourceHandles.clear();
797
798 freeTasks(pipeline.tasks, renderContext);
799 pipeline.tasks.clear();
800
801 pipeline.subContexts.clear();
802 pipeline.expressionContext.clear();
803 pipeline.dependsVariables.clear();
804}
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
Provides a context for evaluation of expressions.
Definition: Expressions.h:54
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120
@ Texture
Texture usage, see Default.
Definition: Flags.h:118