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 expressionContext->add(r.name + ".width", 0.0);
301 expressionContext->add(r.name + ".height", 0.0);
302
303 renderTexture->width = { expressionContext, r.name + ".width", std::to_string(renderTexture->width.get(0)), 0 };
304 renderTexture->height = { expressionContext, r.name + ".height", std::to_string(renderTexture->height.get(0)), 0 };
305
306 for (auto& p : r.parameters) {
307 const size_t code = StringView(p.key).hash();
308 switch (code) {
309
310 case Cogs::hash("clearColor"):
311 // Set clear color
312 switch (p.type) {
313 case ParsedDataType::Int4:
314 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = static_cast<float>(p.int4Value[i]); }
315 renderTexture->clearColorSet = true;
316 break;
317 case ParsedDataType::UInt4:
318 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = static_cast<float>(p.uint4Value[i]); }
319 renderTexture->clearColorSet = true;
320 break;
321 case ParsedDataType::Float4:
322 for (glm::length_t i = 0; i < 4; i++) { renderTexture->clearColor[i] = p.float4Value[i]; }
323 renderTexture->clearColorSet = true;
324 break;
325 default:
326 LOG_ERROR(logger, "Texture clear color was not a 4-component vector of int nor floats");
327 break;
328 }
329 break;
330
331 default: {
332
333 // Add as variable
334 std::string name = r.name + "." + p.key;
335 addVariable(expressionContext, name, p);
336 switch (code) {
337 case Cogs::hash("width"):
338 readSize_t(renderTexture->width, expressionContext, r.name, p);
339 break;
340 case Cogs::hash("height"):
341 readSize_t(renderTexture->height, expressionContext, r.name, p);
342 break;
343 case Cogs::hash("levels"):
344 readSize_t(renderTexture->levels, expressionContext, r.name, p);
345 break;
346 case Cogs::hash("layers"):
347 readSize_t(renderTexture->layers, expressionContext, r.name, p);
348 break;
349 case Cogs::hash("faces"):
350 readSize_t(renderTexture->faces, expressionContext, r.name, p);
351 break;
352 case Cogs::hash("samples"):
353 readSize_t(renderTexture->samples, expressionContext, r.name, p);
354 break;
355 case Cogs::hash("sizeSource"):
356 renderTexture->sizeSource = pipelineResources.get(prefix + p.value)->resource;
357 break;
358 default:
359 break;
360 }
361 }
362 }
363 }
364
365 return renderTexture;
366 }
367
368 bool handleResourceAlias(const RenderResourceDefinition & r, const std::string & resourceName, const std::string & prefix, RenderTaskResources & pipelineResources)
369 {
370 if (r.alias.size()) {
371 auto aliasedResource = pipelineResources.get(prefix + r.alias);
372
373 if (aliasedResource) {
374 pipelineResources.add(aliasedResource, resourceName);
375 } else {
376 if (r.type != RenderResourceType::RenderTarget) {
377 LOG_ERROR(logger, "Error aliasing resource %s to %s.", r.name.c_str(), resourceName.c_str());
378 }
379 }
380
381 return true;
382 }
383
384 return false;
385 }
386
387 bool createPipelineRecursive(Cogs::Core::RenderTaskContext * renderContext,
388 const Cogs::Core::RenderPipelineDefinition & pipelineDefinition,
389 Cogs::Core::RenderTaskResources & pipelineResources,
391 const Cogs::Core::PipelineOptions & options,
392 Cogs::Core::ExpressionContext* expressionContext,
393 const std::vector<ParsedValue>& attributes,
394 const std::string & prefix,
395 const std::string & prefixOuter)
396 {
397 pipelineResources.resources.reserve(100);
398
399 auto globalResources = pipelineResources;
400
401 for (auto & option : pipelineDefinition.options) {
402 pipeline.dependsVariables.push_back(option.setting);
403 }
404
405// auto * expressionContext = &pipeline.expressionContext;
406 if (!pipelineDefinition.useVariables.empty()
407 || !pipelineDefinition.setVariables.empty()
408 || !pipelineDefinition.useComponentFields.empty()) {
409 pipeline.subContexts.push_back(std::make_unique<SubContext>(expressionContext));
410 expressionContext = &pipeline.subContexts.back()->expressionContext;
411
412 for (auto & r : pipelineDefinition.inputs) {
413 auto resource = pipelineResources.get(prefix + r.key);
414
415 if (resource->type == RenderResourceType::RenderTexture || resource->type == RenderResourceType::RenderTarget) {
416 // Try to figure out prefix-less name in outer-scope.
417 const auto preStrip = prefixOuter.length();
418 StringView nameOuter = resource->name;
419 if (preStrip <= nameOuter.length() && nameOuter.substr(0, preStrip).compare(prefixOuter) == 0) {
420 nameOuter = nameOuter.substr(preStrip);
421 }
422
423 if (resource->type == RenderResourceType::RenderTexture || nameOuter == "Cogs.BackBuffer") {
424 expressionContext->link(expressionContext, nameOuter.to_string() + ".width", r.key + ".width");
425 expressionContext->link(expressionContext, nameOuter.to_string() + ".height", r.key + ".height");
426 }
427 }
428 }
429
430 pipeline.subContexts.back()->useVariables(renderContext->context, pipelineDefinition.useVariables);
431 pipeline.subContexts.back()->setVariables(renderContext->context, pipelineDefinition.setVariables);
432 pipeline.subContexts.back()->useComponentFields(renderContext, pipelineDefinition.useComponentFields);
433 }
434
435 for (auto & r : pipelineDefinition.resources) {
436 auto resourceName = prefix + r.name;
437
438 if (!evaluateCondition(renderContext->context, r.condition, pipelineDefinition, attributes)) continue;
439
440 if (handleResourceAlias(r, resourceName, prefix, pipelineResources)) continue;
441
442 switch (r.type) {
443 case RenderResourceType::RenderBuffer:
444 {
445 auto renderBuffer = createRenderBuffer(renderContext->resources, resourceName, r, expressionContext);
446
447 pipelineResources.add(renderBuffer, resourceName);
448 pipeline.resources.add(renderBuffer, resourceName);
449 }
450 break;
451 case RenderResourceType::RenderList:
452 {
453 auto renderList = renderContext->resources->createRenderList();
454 renderList->setName(resourceName);
455
456 pipelineResources.add(renderList, resourceName);
457 pipeline.resources.add(renderList, resourceName);
458 }
459 break;
460 case RenderResourceType::RenderTexture:
461 {
462 auto renderTexture = createRenderTexture(renderContext, pipeline, pipelineResources, resourceName, prefix, r, expressionContext);
463
464 pipelineResources.add(renderTexture, resourceName);
465 pipeline.resources.add(renderTexture, resourceName);
466 }
467 break;
468 default:
469 break;
470 }
471 }
472
473 for (auto & r : pipelineDefinition.resources) {
474 auto resourceName = prefix + r.name;
475
476 if (!evaluateCondition(renderContext->context, r.condition, pipelineDefinition, attributes)) continue;
477
478 if (handleResourceAlias(r, resourceName, prefix, pipelineResources)) continue;
479
480 if (r.type == RenderResourceType::RenderTarget) {
481 auto renderTarget = renderContext->resources->createRenderTarget();
482 renderTarget->setName(resourceName);
483
484 auto depth = r.getParameter("depth", "");
485 if (depth) {
486 auto depthTexture = pipelineResources.get(prefix + depth->value);
487
488 if (!depthTexture) {
489 auto format = parseTextureFormat(depth->value);
490
491 if (format != TextureFormat::Unknown) {
492 auto depthName = resourceName + ":DepthTexture";
493 auto depth_rtex = renderContext->resources->createRenderTexture();
494 depth_rtex->setName(depthName);
495 depth_rtex->description.flags = TextureFlags::DepthBuffer | TextureFlags::Texture;
496 depth_rtex->description.format = format;
497
498 renderTarget->depth = depth_rtex;
499
500 pipelineResources.add(depth_rtex, depthName);
501 pipeline.resources.add(depth_rtex, depthName);
502 }
503 } else {
504 renderTarget->depth = depthTexture->renderTexure;
505 }
506 }
507
508 auto clearColor = r.getParameter("clearColor", "");
509 if (clearColor && clearColor->type == ParsedDataType::Float4) {
510 renderTarget->clearColors = { clearColor->float4Value };
511 }
512
513 auto levels = r.getParameter("levels", "");
514 if (levels) {
515 readSize_t(renderTarget->levels, expressionContext, r.name + std::to_string((size_t)renderTarget), *levels);
516 }
517
518 size_t textureIndex = 0;
519 for (auto & t : r.textures) {
520 auto name = prefix + t;
521 auto textureResource = pipelineResources.get(name);
522
523 if (textureResource) {
524 renderTarget->textures.push_back(textureResource->renderTexure);
525 } else {
526 auto format = parseTextureFormat(t);
527
528 if (format != TextureFormat::Unknown) {
529 auto textureName = resourceName + ":Texture" + std::to_string(textureIndex++);
530
531 auto texture = renderContext->resources->createRenderTexture();
532 texture->setName(textureName);
533 texture->description.format = format;
534 texture->description.flags = TextureFlags::Texture | TextureFlags::RenderTarget;
535
536 renderTarget->textures.push_back(texture);
537
538 pipelineResources.add(texture, textureName);
539 pipeline.resources.add(texture, textureName);
540 } else {
541 LOG_ERROR(logger, "Could not resolve resource %s.", name.c_str());
542 }
543 }
544 }
545
546 pipelineResources.add(renderTarget, resourceName);
547 pipeline.resources.add(renderTarget, resourceName);
548 }
549 }
550
551 std::list<RenderTask *> tasks;
552
553 for (auto & t : pipelineDefinition.tasks) {
554 if (!evaluateCondition(renderContext->context, t.condition, pipelineDefinition, attributes)) continue;
555
556 if (t.type[0] == '$') {
557 bool found = false;
558
559 for (auto & p : renderContext->renderer->getPipelineManager()->nameMap) {
560 if (p.first == t.type.substr(1)) {
561 auto & g = renderContext->renderer->getPipelineManager()->definitionByKey(renderContext->context, p.second);
562
563 auto gPrefix = prefix + t.name;
564
565 PipelineOptions gOptions;
566
567 for (auto & o : t.options) {
568 gOptions.push_back({ o.key, o.value });
569 }
570
571 RenderTaskResources gResources;
572 for (size_t i = 0; i < 2; ++i) {
573 gResources.add(&pipelineResources.resources[i]);
574 }
575
576 for (auto & input : g.inputs) {
577 bool handled = false;
578 for (auto & ii : t.inputs) {
579 if (ii.key == input.key) {
580 const auto resourceName = prefix + ii.value;
581 if (auto * resource = pipelineResources.get(resourceName); resource) {
582 gResources.add(resource, gPrefix + input.key);
583 handled = true;
584 } else {
585 LOG_ERROR(logger, "In task %s.%s, failed to find input resource '%s'.", pipelineDefinition.name.c_str(), t.name.c_str(), resourceName.c_str());
586 goto bail;
587 }
588 }
589 }
590 if (!handled) {
591 LOG_ERROR(logger, "In task %s.%s, un-matched input key '%s'", pipelineDefinition.name.c_str(), t.name.c_str(), input.key.c_str());
592 goto bail;
593 }
594 }
595
596 for (auto & output : g.outputs) {
597 bool handled = false;
598 for (auto & oo : t.outputs) {
599
600 if ((g.outputs.size() == 1 && t.outputs.size() == 1 && oo.key.empty())
601 || (oo.key == output.key)) {
602 const auto resourceName = prefix + oo.value;
603 if (auto * resource = pipelineResources.get(resourceName); resource) {
604 gResources.add(resource, gPrefix + output.key);
605 handled = true;
606 } else {
607 LOG_ERROR(logger, "In task %s.%s, failed to find output resource '%s'.", pipelineDefinition.name.c_str(), t.name.c_str(), resourceName.c_str());
608 goto bail;
609 }
610 } else {
611 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());
612 }
613 }
614 if (!handled) {
615 LOG_ERROR(logger, "In task %s.%s, un-matched output key '%s'", pipelineDefinition.name.c_str(), t.name.c_str(), output.key.c_str());
616 goto bail;
617 }
618
619 }
620
621 createPipelineRecursive(renderContext, g, gResources, pipeline, gOptions, expressionContext, attributes, gPrefix, prefix);
622
623 for (auto tt : pipeline.tasks) {
624 tasks.push_back(tt);
625 }
626
627 bail:
628 pipeline.tasks.clear();
629
630 found = true;
631 break;
632 }
633 }
634 if (!found)
635 LOG_ERROR(logger, "Failed to resolve pipeline type '%s'", t.type.c_str());
636 continue;
637 }
638
639 auto tt = t;
640 tt.name = prefix + tt.name;
641
642 auto task = createRenderTask(renderContext, tt, pipeline.subContexts, expressionContext, options);
643
644 if (!task) {
645 LOG_ERROR(logger, "Pipeline task chain incomplete.");
646 return false;
647 }
648
649 task->name = tt.name;
650 for (auto & d : t.dependencies) {
651 auto dependencyName = prefix + d;
652
653 auto r = pipelineResources.get(dependencyName);
654
655 if (r != nullptr) {
656 task->dependencies.push_back(r->name);
657 } else {
658 task->dependencies.push_back(prefix + d);
659 }
660 }
661
662 for (auto & input : t.inputs) {
663 const std::string resourceName = prefix + input.value;
664 if (RenderTaskResource* resource = pipelineResources.get(resourceName); resource) {
665 if (!input.key.empty()) {
666 task->input.add(pipelineResources.get(prefix + input.value), input.key);
667 }
668 else {
669 task->input.add(pipelineResources.get(prefix + input.value), input.value);
670 }
671 }
672 else {
673 LOG_ERROR(logger, "Unknown pipeline resource '%s'", resourceName.c_str());
674 return false;
675 }
676 }
677
678 for (auto & output : t.outputs) {
679 if (output.key.size()) {
680 task->output.add(pipelineResources.get(prefix + output.value), output.key);
681 } else {
682 task->output.add(pipelineResources.get(prefix + output.value), output.value);
683 }
684 }
685
686 tasks.push_back(task);
687 }
688
689 if (prefix.size()) {
690 for (auto t : tasks) {
691 pipeline.tasks.push_back(t);
692 }
693
694 return true;
695 }
696
697 evaluateTaskDependencies(tasks, globalResources, pipeline);
698
699 return true;
700 }
701
702
703 size_t pipelineHash(RenderTaskContext * renderContext, const RenderPipeline & pipeline)
704 {
705 size_t hashValue = Cogs::hash();
706
707 for (const std::string& vars : pipeline.dependsVariables) {
708 hashValue = hash(renderContext->context->variables->get(vars, StringView()), hashValue);
709 }
710 return hashValue;
711 }
712}
713
714bool Cogs::Core::createPipeline(RenderTaskContext * renderContext,
715 const RenderPipelineDefinition & pipelineDefinition,
716 RenderTaskResources & pipelineResources,
717 RenderPipeline & pipeline,
718 const StringView & path, // used to pull query-part as options.
719 const CameraData* cameraData,
720 const PipelineOptions & options,
721 const std::string & prefix)
722{
723
724 pipeline.expressionContext.clear();
725 pipeline.expressionContext.inherit(renderContext->expressionContext);
726
727 std::vector<ParsedValue> attributes;
728 auto queryLoc = path.find("?");
729 if (queryLoc != StringView::NoPosition) {
730 parseQueryString(attributes, path.substr(queryLoc + 1));
731 }
732
733 const CameraData* cameraDataSaved = renderContext->cameraData;
734 if (cameraData) {
735 renderContext->cameraData = cameraData;
736 }
737
738 ExpressionContext* expressionContextSave = renderContext->expressionContext;
739 renderContext->expressionContext = &pipeline.expressionContext;
740
741 bool rv = false;
742 if (createPipelineRecursive(renderContext, pipelineDefinition, pipelineResources, pipeline, options, &pipeline.expressionContext, attributes, prefix, "")) {
743 pipeline.dependsVariables.sort();
744 pipeline.dependsVariables.unique();
745 pipeline.hash = pipelineHash(renderContext, pipeline);
746 rv = true;
747 }
748
749 renderContext->expressionContext = expressionContextSave;
750 renderContext->cameraData = cameraDataSaved;
751 return rv;
752}
753
754bool Cogs::Core::isPipelineFresh(RenderTaskContext * renderContext, const RenderPipeline & pipeline)
755{
756 return pipeline.hash == pipelineHash(renderContext, pipeline);
757}
758
759void Cogs::Core::releasePipeline(RenderTaskContext * renderContext, RenderPipeline & pipeline)
760{
761 for (auto & r : pipeline.resources.resources) {
762 if (!r.resource->isOwned()) {
763 renderContext->resources->releaseResource(r.resource);
764 renderContext->resources->destroyResource(r.resource);
765 } else {
766 renderContext->resources->releaseResource(r.resource);
767 }
768 }
769
770 pipeline.resources.resources.clear();
771 pipeline.resourceHandles.clear();
772
773 freeTasks(pipeline.tasks, renderContext);
774 pipeline.tasks.clear();
775
776 pipeline.subContexts.clear();
777 pipeline.expressionContext.clear();
778 pipeline.dependsVariables.clear();
779}
Log implementation class.
Definition: LogManager.h:139
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
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
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