VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
frameGraph.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 11.09.2025.
5//
6
7#include "frameGraph.h"
8
9namespace visutwin::canvas
10{
12 {
13 _renderPasses.clear();
14 }
15
16 void FrameGraph::addRenderPass(const std::shared_ptr<RenderPass>& renderPass)
17 {
18 renderPass->frameUpdate();
19
20 auto& beforePasses = renderPass->beforePasses();
21 for (auto pass : beforePasses) {
22 if (pass->enabled()) {
23 addRenderPass(pass);
24 }
25 }
26
27 if (renderPass->enabled()) {
28 _renderPasses.push_back(renderPass);
29 }
30
31 for (auto pass : renderPass->afterPasses()) {
32 if (pass->enabled()) {
33 addRenderPass(pass);
34 }
35 }
36 }
37
39 for (auto renderPass : _renderPasses) {
40 RenderTarget* renderTarget = renderPass->renderTarget().get();
41
42 // if using a target, or null which represents the default back-buffer
43 if (renderTarget != nullptr) {
44 // previous pass using the same render target
45 if (auto it = _renderTargetMap.find(renderTarget); it != _renderTargetMap.end()) {
46 auto prevPass = it->second;
47
48 // if we use the RT without clearing, make sure the previous pass stores data
49 const auto& colorArrayOps = renderPass->colorArrayOps();
50 size_t count = colorArrayOps.size();
51 for (size_t j = 0; j < count; j++) {
52 const auto colorOps = colorArrayOps[j];
53 if (!colorOps->clear) {
54 prevPass->colorArrayOps()[j]->store = true;
55 }
56 }
57
58 const auto depthStencilOps = renderPass->depthStencilOps();
59 if (!depthStencilOps->clearDepth) {
60 prevPass->depthStencilOps()->storeDepth = true;
61 }
62 if (!depthStencilOps->clearStencil) {
63 prevPass->depthStencilOps()->storeStencil = true;
64 }
65 }
66
67 // add the pass to the map
68 _renderTargetMap[renderTarget] = renderPass;
69 }
70 }
71
72 // merge passes if possible
73 if (_renderPasses.size() < 2) return;
74 for (size_t i = 0; i < _renderPasses.size() - 1; i++) {
75 auto firstPass = _renderPasses[i];
76 auto firstRT = firstPass->renderTarget();
77 auto secondPass = _renderPasses[i + 1];
78 auto secondRT = secondPass->renderTarget();
79
80 // if the render targets are different, we can't merge the passes
81 // also only merge passes that have a render target
82 if (firstRT != secondRT || firstRT == nullptr) {
83 continue;
84 }
85
86 // do not merge if the second pass clears any of the attachments
87 const auto secondDepthStencilOps = secondPass->depthStencilOps();
88 if (secondDepthStencilOps->clearDepth ||
89 secondDepthStencilOps->clearStencil) {
90 continue;
91 }
92
93 const auto& secondColorArrayOps = secondPass->colorArrayOps();
94 bool anyColorClear = false;
95 for (const auto& colorOps : secondColorArrayOps) {
96 if (colorOps->clear) {
97 anyColorClear = true;
98 break;
99 }
100 }
101 if (anyColorClear) {
102 continue;
103 }
104
105 // first pass cannot contain after passes
106 if (firstPass->afterPasses().size() > 0) {
107 continue;
108 }
109
110 // second pass cannot contain before passes
111 if (secondPass->beforePasses().size() > 0) {
112 continue;
113 }
114
115 // merge the passes
116 firstPass->setSkipEnd(true);
117 secondPass->setSkipStart(true);
118 }
119
120 // Walk over render passes to find passes rendering to the same cubemap texture.
121 // If those passes are separated only by passes not requiring cubemap (shadows ..),
122 // we skip the mipmap generation till the last rendering to the cubemap, to avoid
123 // mipmaps being generated after each face.
124 Texture* lastCubeTexture = nullptr;
125 std::shared_ptr<RenderPass> lastCubeRenderPass = nullptr;
126
127 for (auto renderPass : _renderPasses) {
128 auto renderTarget = renderPass->renderTarget();
129 Texture* thisTexture = renderTarget ? renderTarget->colorBuffer() : nullptr;
130
131 if (thisTexture && thisTexture->isCubemap()) {
132 // if the previous pass used the same cubemap texture, it does not need mipmaps generated
133 if (lastCubeTexture == thisTexture) {
134 auto& lastColorArrayOps = lastCubeRenderPass->colorArrayOps();
135 size_t count = lastColorArrayOps.size();
136 for (size_t j = 0; j < count; j++) {
137 lastColorArrayOps[j]->genMipmaps = false;
138 }
139 }
140
141 lastCubeTexture = renderTarget->colorBuffer();
142 lastCubeRenderPass = renderPass;
143 } else if (renderPass->requiresCubemaps()) {
144 // if the cubemap is required, break the cubemap rendering chain
145 lastCubeTexture = nullptr;
146 lastCubeRenderPass = nullptr;
147 }
148 }
149
150 _renderTargetMap.clear();
151 }
152
154 compile();
155
156 for (auto pass : _renderPasses) {
157 pass->render();
158 }
159 }
160}
void render(GraphicsDevice *device)
void addRenderPass(const std::shared_ptr< RenderPass > &renderPass)
Abstract GPU interface for resource creation, state management, and draw submission.
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57
bool isCubemap() const
Definition texture.h:85