1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsRenderBeastPrerequisites.h"
6
7namespace bs
8{
9 class RendererExtension;
10
11namespace ct
12{
13 struct SceneInfo;
14 class RendererViewGroup;
15 class RenderCompositorNode;
16 struct PooledStorageBuffer;
17 struct FrameInfo;
18
19 /** @addtogroup RenderBeast
20 * @{
21 */
22
23 /** Inputs provided to each node in the render compositor hierarchy */
24 struct RenderCompositorNodeInputs
25 {
26 RenderCompositorNodeInputs(const RendererViewGroup& viewGroup, const RendererView& view, const SceneInfo& scene,
27 const RenderBeastOptions& options, const FrameInfo& frameInfo, RenderBeastFeatureSet featureSet)
28 : viewGroup(viewGroup), view(view), scene(scene), options(options), frameInfo(frameInfo), featureSet(featureSet)
29 { }
30
31 const RendererViewGroup& viewGroup;
32 const RendererView& view;
33 const SceneInfo& scene;
34 const RenderBeastOptions& options;
35 const FrameInfo& frameInfo;
36 const RenderBeastFeatureSet featureSet;
37
38 // Callbacks to external systems can hook into the compositor
39 SmallVector<RendererExtension*, 4> extPrepare;
40 SmallVector<RendererExtension*, 4> extPreBasePass;
41 SmallVector<RendererExtension*, 4> extPostBasePass;
42 SmallVector<RendererExtension*, 4> extPostLighting;
43 SmallVector<RendererExtension*, 4> extOverlay;
44
45 SmallVector<RenderCompositorNode*, 4> inputNodes;
46 };
47
48 /**
49 * Node in the render compositor hierarchy. Nodes can be implemented to perform specific rendering tasks. Each node
50 * can depend on other nodes in the hierarchy.
51 *
52 * @note Implementations must provide a getNodeId() and getDependencies() static method, which are expected to
53 * return a unique name for the implemented node, as well as a set of nodes it depends on.
54 */
55 class RenderCompositorNode
56 {
57 public:
58 virtual ~RenderCompositorNode() = default;
59
60 protected:
61 friend class RenderCompositor;
62
63 /** Executes the task implemented in the node. */
64 virtual void render(const RenderCompositorNodeInputs& inputs) = 0;
65
66 /**
67 * Cleans up any temporary resources allocated in a render() call. Any resources lasting longer than one frame
68 * should be kept alive and released in some other manner.
69 */
70 virtual void clear() = 0;
71 };
72
73 /**
74 * Performs rendering by iterating over a hierarchy of render nodes. Each node in the hierarchy performs a specific
75 * rendering tasks and passes its output to the dependant node. The system takes care of initializing, rendering and
76 * cleaning up nodes automatically depending on their dependencies.
77 */
78 class RenderCompositor
79 {
80 public:
81 struct NodeType;
82
83 private:
84 /** Contains internal information about a single render node. */
85 struct NodeInfo
86 {
87 RenderCompositorNode* node;
88 NodeType* nodeType;
89 UINT32 lastUseIdx;
90 SmallVector<RenderCompositorNode*, 4> inputs;
91 };
92
93 public:
94 ~RenderCompositor();
95
96 /**
97 * Rebuilds the render node hierarchy. Call this whenever some setting that may influence the render node
98 * dependencies changes.
99 *
100 * @param[in] view Parent view to which this compositor belongs to.
101 * @param[in] finalNode Identifier of the final node in the node hierarchy. This node is expected to write
102 * to the views render target. All other nodes will be deduced from this node's
103 * dependencies.
104 */
105 void build(const RendererView& view, const StringID& finalNode);
106
107 /** Performs rendering using the current render node hierarchy. This is expected to be called once per frame. */
108 void execute(RenderCompositorNodeInputs& inputs) const;
109
110 private:
111 /** Clears the render node hierarchy. */
112 void clear();
113
114 Vector<NodeInfo> mNodeInfos;
115 bool mIsValid = false;
116
117 /************************************************************************/
118 /* NODE TYPES */
119 /************************************************************************/
120 public:
121 /** Contains information about a specific node type. */
122 struct NodeType
123 {
124 virtual ~NodeType() = default;
125
126 /** Creates a new node of this type. */
127 virtual RenderCompositorNode* create() const = 0;
128
129 /** Returns identifier for all the dependencies of a node of this type. */
130 virtual SmallVector<StringID, 4> getDependencies(const RendererView& view) const = 0;
131
132 StringID id;
133 };
134
135 /** Templated implementation of NodeType. */
136 template<class T>
137 struct TNodeType : NodeType
138 {
139 TNodeType()
140 {
141 id = T::getNodeId();
142 }
143
144 /** @copydoc NodeType::create() */
145 RenderCompositorNode* create() const override { return bs_new<T>(); }
146
147 /** @copydoc NodeType::getDependencies() */
148 SmallVector<StringID, 4> getDependencies(const RendererView& view) const override
149 {
150 return T::getDependencies(view);
151 }
152 };
153
154 /**
155 * Registers a new type of node with the system. Each node type must first be registered before it can be used
156 * in the node hierarchy.
157 */
158 template<class T>
159 static void registerNodeType()
160 {
161 auto findIter = mNodeTypes.find(T::getNodeId());
162 if (findIter != mNodeTypes.end())
163 LOGERR("Found two render compositor nodes with the same name \"" + String(T::getNodeId().c_str()) + "\".");
164
165 mNodeTypes[T::getNodeId()] = bs_new<TNodeType<T>>();
166 }
167
168 /** Releases any information about render node types. */
169 static void cleanUp()
170 {
171 for (auto& entry : mNodeTypes)
172 bs_delete(entry.second);
173
174 mNodeTypes.clear();
175 }
176
177 private:
178 static UnorderedMap<StringID, NodeType*> mNodeTypes;
179 };
180
181 /************************************************************************/
182 /* BASE PASS NODES */
183 /************************************************************************/
184
185 /** Initializes the scene depth texture. Does not perform any rendering. */
186 class RCNodeSceneDepth : public RenderCompositorNode
187 {
188 public:
189 // Outputs
190 SPtr<PooledRenderTexture> depthTex;
191
192 static StringID getNodeId() { return "SceneDepth"; }
193 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
194 protected:
195 /** @copydoc RenderCompositorNode::render */
196 void render(const RenderCompositorNodeInputs& inputs) override;
197
198 /** @copydoc RenderCompositorNode::clear */
199 void clear() override;
200 };
201
202 /**
203 * Initializes the GBuffer textures and renders the base pass into the GBuffer. The base pass includes all the opaque
204 * objects visible to the view.
205 */
206 class RCNodeBasePass : public RenderCompositorNode
207 {
208 public:
209 // Outputs
210 SPtr<PooledRenderTexture> albedoTex;
211 SPtr<PooledRenderTexture> normalTex;
212 SPtr<PooledRenderTexture> roughMetalTex;
213 SPtr<PooledRenderTexture> idTex;
214
215 SPtr<RenderTexture> renderTarget;
216 SPtr<RenderTexture> renderTargetNoMask;
217
218 static StringID getNodeId() { return "BasePass"; }
219 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
220 protected:
221 /** @copydoc RenderCompositorNode::render */
222 void render(const RenderCompositorNodeInputs& inputs) override;
223
224 /** @copydoc RenderCompositorNode::clear */
225 void clear() override;
226 };
227
228 /** Initializes the scene color texture and/or buffer. Does not perform any rendering. */
229 class RCNodeSceneColor : public RenderCompositorNode
230 {
231 public:
232 // Outputs
233 /**
234 * Contains scene color. If MSAA is used this texture will be null until the texture array data is first resolved
235 * into this texture.
236 */
237 SPtr<PooledRenderTexture> sceneColorTex;
238
239 /**
240 * Texture array version of sceneColorTex. Only available when MSAA is used, since random writes to
241 * multisampled texture aren't supported on all render backends.
242 */
243 SPtr<PooledRenderTexture> sceneColorTexArray;
244
245 SPtr<RenderTexture> renderTarget;
246
247 /** Converts MSAA data from the texture array into the MSAA texture. */
248 void resolveMSAA();
249
250 static StringID getNodeId() { return "SceneColor"; }
251 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
252 protected:
253 /** @copydoc RenderCompositorNode::render */
254 void render(const RenderCompositorNodeInputs& inputs) override;
255
256 /** @copydoc RenderCompositorNode::clear */
257 void clear() override;
258 };
259
260 /**
261 * Determines which samples in the GBuffer require per-sample shading and outputs a texture with the coverage (for use
262 * in compute shaders) and populates the primary stencil buffer as well (for use in non-compute shaders). Only relevant
263 * when rendering with MSAA enabled.
264 */
265 class RCNodeMSAACoverage : public RenderCompositorNode
266 {
267 public:
268 // Outputs
269 SPtr<PooledRenderTexture> output;
270
271 static StringID getNodeId() { return "MSAACoverage"; }
272 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
273 protected:
274 /** @copydoc RenderCompositorNode::render */
275 void render(const RenderCompositorNodeInputs& inputs) override;
276
277 /** @copydoc RenderCompositorNode::clear */
278 void clear() override;
279 };
280
281 /************************************************************************/
282 /* UTILITY NODES */
283 /************************************************************************/
284
285 /** Simulates GPU particle systems. */
286 class RCNodeParticleSimulate : public RenderCompositorNode
287 {
288 public:
289 static StringID getNodeId() { return "ParticleSimulate"; }
290 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
291 protected:
292 /** @copydoc RenderCompositorNode::render */
293 void render(const RenderCompositorNodeInputs& inputs) override;
294
295 /** @copydoc RenderCompositorNode::clear */
296 void clear() override;
297 };
298
299 /** Performs view-based sorting on CPU simulated particle systems. */
300 class RCNodeParticleSort : public RenderCompositorNode
301 {
302 public:
303 static StringID getNodeId() { return "ParticleSort"; }
304 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
305 protected:
306 /** @copydoc RenderCompositorNode::render */
307 void render(const RenderCompositorNodeInputs& inputs) override;
308
309 /** @copydoc RenderCompositorNode::clear */
310 void clear() override;
311 };
312
313 /************************************************************************/
314 /* LIGHTING NODES */
315 /************************************************************************/
316
317 /** Initializes the light accumulation texture and/or buffer. Does not perform any rendering. */
318 class RCNodeLightAccumulation : public RenderCompositorNode
319 {
320 public:
321 // Outputs
322 /**
323 * Contains lighting information accumulated from multiple lights. If MSAA is used this texture will be null until
324 * the texture array data is first resolved into this texture.
325 */
326 SPtr<PooledRenderTexture> lightAccumulationTex;
327
328 /**
329 * Texture array version of lightAccumulationTex. Only available when MSAA is used, since random writes to
330 * multisampled texture aren't supported on all render backends.
331 */
332 SPtr<PooledRenderTexture> lightAccumulationTexArray;
333
334 SPtr<RenderTexture> renderTarget;
335
336 /** Converts MSAA data from the texture array into the MSAA texture. */
337 void resolveMSAA();
338
339 static StringID getNodeId() { return "LightAccumulation"; }
340 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
341 protected:
342 /** @copydoc RenderCompositorNode::render */
343 void render(const RenderCompositorNodeInputs& inputs) override;
344
345 /** @copydoc RenderCompositorNode::clear */
346 void clear() override;
347
348 bool mOwnsTexture = false;
349 };
350
351 /**
352 * Handles lighting of surfaces illuminated directly, for both diffuse and specular components. Uses either tiled
353 * deferred or standard deferred rendering approach. Lighting information is output in the light accumulation buffer.
354 */
355 class RCNodeDeferredDirectLighting : public RenderCompositorNode
356 {
357 public:
358 // Outputs
359 RCNodeLightAccumulation* output;
360
361 static StringID getNodeId() { return "DeferredDirectLighting"; }
362 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
363 protected:
364 /** @copydoc RenderCompositorNode::render */
365 void render(const RenderCompositorNodeInputs& inputs) override;
366
367 /** @copydoc RenderCompositorNode::clear */
368 void clear() override;
369
370 SPtr<RenderTexture> mLightOcclusionRT;
371 };
372
373 /**
374 * Calculates specular lighting (specular reflections) using image based methods and deferred rendering. Uses either
375 * tiled deferred or standard deferred depending on the active feature set. The resulting lighting data is combined
376 * with direct lighting present in the light accumulation buffer and output to scene color texture/buffer.
377 */
378 class RCNodeDeferredIndirectSpecularLighting : public RenderCompositorNode
379 {
380 public:
381 // Outputs
382 RCNodeLightAccumulation* output;
383
384 static StringID getNodeId() { return "DeferredIndirectSpecularLighting"; }
385 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
386 protected:
387 /** @copydoc RenderCompositorNode::render */
388 void render(const RenderCompositorNodeInputs& inputs) override;
389
390 /** @copydoc RenderCompositorNode::clear */
391 void clear() override;
392 };
393
394 /**
395 * Evaluates indirect lighting from the light probe volume, if available, or the sky irradiance otherwise.
396 * Results are written to the light accumulation buffer.
397 */
398 class RCNodeIndirectDiffuseLighting : public RenderCompositorNode
399 {
400 public:
401 // Outputs to the unflattened RCNodeLightAccumulation
402
403 static StringID getNodeId() { return "IndirectDiffuseLighting"; }
404 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
405 protected:
406 /** @copydoc RenderCompositorNode::render */
407 void render(const RenderCompositorNodeInputs& inputs) override;
408
409 /** @copydoc RenderCompositorNode::clear */
410 void clear() override;
411 };
412
413 /**
414 * Renders transparent objects using clustered forward rendering. Handles direct diffuse and specular, as well as
415 * indirect specular.
416 */
417 class RCNodeClusteredForward : public RenderCompositorNode
418 {
419 public:
420 static StringID getNodeId() { return "ClusteredForward"; }
421 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
422 protected:
423 /** @copydoc RenderCompositorNode::render */
424 void render(const RenderCompositorNodeInputs& inputs) override;
425
426 /** @copydoc RenderCompositorNode::clear */
427 void clear() override;
428
429 SPtr<RenderTexture> renderTarget;
430 };
431
432 /**
433 * Renders the skybox into the scene color texture. If skybox texture is not available, a solid color will be rendered
434 * instead.
435 */
436 class RCNodeSkybox : public RenderCompositorNode
437 {
438 public:
439 static StringID getNodeId() { return "Skybox"; }
440 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
441 protected:
442 /** @copydoc RenderCompositorNode::render */
443 void render(const RenderCompositorNodeInputs& inputs) override;
444
445 /** @copydoc RenderCompositorNode::clear */
446 void clear() override;
447 };
448
449 /** Moves the contents of the scene color texture into the view's output target. */
450 class RCNodeFinalResolve : public RenderCompositorNode
451 {
452 public:
453 static StringID getNodeId() { return "FinalResolve"; }
454 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
455 protected:
456 /** @copydoc RenderCompositorNode::render */
457 void render(const RenderCompositorNodeInputs& inputs) override;
458
459 /** @copydoc RenderCompositorNode::clear */
460 void clear() override;
461 };
462
463 /************************************************************************/
464 /* POST PROCESS NODES */
465 /************************************************************************/
466
467 /**
468 * Helper node used for post-processing. Takes care of allocating and switching between textures used for post process
469 * effects.
470 */
471 class RCNodePostProcess : public RenderCompositorNode
472 {
473 public:
474 RCNodePostProcess();
475
476 /**
477 * Returns a texture that can be used for rendering a post-process effect, and the result of the previous
478 * output. Switches these textures so the next call they are returned in the opposite parameters.
479 */
480 void getAndSwitch(const RendererView& view, SPtr<RenderTexture>& output, SPtr<Texture>& lastFrame) const;
481
482 /** Returns a texture that contains the last rendererd post process output. */
483 SPtr<Texture> getLastOutput() const;
484
485 static StringID getNodeId() { return "PostProcess"; }
486 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
487 protected:
488 /** @copydoc RenderCompositorNode::render */
489 void render(const RenderCompositorNodeInputs& inputs) override;
490
491 /** @copydoc RenderCompositorNode::clear */
492 void clear() override;
493
494 mutable SPtr<PooledRenderTexture> mOutput[2];
495 mutable bool mAllocated[2];
496 mutable UINT32 mCurrentIdx = 0;
497 };
498
499 /** Calculates the eye adaptation values used for automatic exposure. */
500 class RCNodeEyeAdaptation : public RenderCompositorNode
501 {
502 public:
503 SPtr<PooledRenderTexture> output;
504
505 ~RCNodeEyeAdaptation();
506
507 static StringID getNodeId() { return "EyeAdaptation"; }
508 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
509 protected:
510 /** @copydoc RenderCompositorNode::render */
511 void render(const RenderCompositorNodeInputs& inputs) override;
512
513 /** @copydoc RenderCompositorNode::clear */
514 void clear() override;
515
516 /**
517 * Returns true if the more advanced (and more expensive) compute shader based method of computing eye adaptation
518 * should be used.
519 */
520 bool useHistogramEyeAdapatation(const RenderCompositorNodeInputs& inputs);
521
522 SPtr<PooledRenderTexture> previous;
523 };
524
525 /**
526 * Performs tone mapping on the contents of the scene color texture. At the same time resolves MSAA into a non-MSAA
527 * scene color texture.
528 */
529 class RCNodeTonemapping : public RenderCompositorNode
530 {
531 public:
532 ~RCNodeTonemapping();
533
534 static StringID getNodeId() { return "Tonemapping"; }
535 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
536 protected:
537 /** @copydoc RenderCompositorNode::render */
538 void render(const RenderCompositorNodeInputs& inputs) override;
539
540 /** @copydoc RenderCompositorNode::clear */
541 void clear() override;
542
543 SPtr<PooledRenderTexture> mTonemapLUT;
544 UINT64 mTonemapLastUpdateHash = -1;
545 };
546
547 /** Renders the depth of field effect using Gaussian blurring. */
548 class RCNodeGaussianDOF : public RenderCompositorNode
549 {
550 public:
551 static StringID getNodeId() { return "GaussianDOF"; }
552 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
553 protected:
554 /** @copydoc RenderCompositorNode::render */
555 void render(const RenderCompositorNodeInputs& inputs) override;
556
557 /** @copydoc RenderCompositorNode::clear */
558 void clear() override;
559 };
560
561 /** Renders FXAA. */
562 class RCNodeFXAA : public RenderCompositorNode
563 {
564 public:
565 static StringID getNodeId() { return "FXAA"; }
566 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
567 protected:
568 /** @copydoc RenderCompositorNode::render */
569 void render(const RenderCompositorNodeInputs& inputs) override;
570
571 /** @copydoc RenderCompositorNode::clear */
572 void clear() override;
573 };
574
575 /************************************************************************/
576 /* SCREEN SPACE */
577 /************************************************************************/
578
579 /** Generates a 1/2 size of the scene color texture. If MSAA only the first sample is used. */
580 class RCNodeHalfSceneColor : public RenderCompositorNode
581 {
582 public:
583 SPtr<PooledRenderTexture> output;
584
585 static StringID getNodeId() { return "HalfSceneColor"; }
586 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
587 protected:
588 /** @copydoc RenderCompositorNode::render */
589 void render(const RenderCompositorNodeInputs& inputs) override;
590
591 /** @copydoc RenderCompositorNode::clear */
592 void clear() override;
593 };
594
595 /** Resolves the depth buffer (if multi-sampled). Otherwise just references the original depth buffer. */
596 class RCNodeResolvedSceneDepth : public RenderCompositorNode
597 {
598 public:
599 SPtr<PooledRenderTexture> output;
600
601 static StringID getNodeId() { return "ResolvedSceneDepth"; }
602 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
603 protected:
604 /** @copydoc RenderCompositorNode::render */
605 void render(const RenderCompositorNodeInputs& inputs) override;
606
607 /** @copydoc RenderCompositorNode::clear */
608 void clear() override;
609
610 bool mPassThrough = false;
611 };
612
613 /** Builds the hierarchical Z buffer. */
614 class RCNodeHiZ : public RenderCompositorNode
615 {
616 public:
617 SPtr<PooledRenderTexture> output;
618
619 static StringID getNodeId() { return "HiZ"; }
620 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
621 protected:
622 /** @copydoc RenderCompositorNode::render */
623 void render(const RenderCompositorNodeInputs& inputs) override;
624
625 /** @copydoc RenderCompositorNode::clear */
626 void clear() override;
627 };
628
629 /** Renders screen space ambient occlusion. */
630 class RCNodeSSAO : public RenderCompositorNode
631 {
632 public:
633 SPtr<Texture> output;
634
635 static StringID getNodeId() { return "SSAO"; }
636 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
637 protected:
638 /** @copydoc RenderCompositorNode::render */
639 void render(const RenderCompositorNodeInputs& inputs) override;
640
641 /** @copydoc RenderCompositorNode::clear */
642 void clear() override;
643
644 SPtr<PooledRenderTexture> mPooledOutput;
645 };
646
647 /** Renders screen space reflections. */
648 class RCNodeSSR : public RenderCompositorNode
649 {
650 public:
651 SPtr<Texture> output;
652
653 ~RCNodeSSR();
654
655 static StringID getNodeId() { return "SSR"; }
656 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
657 protected:
658 /** @copydoc RenderCompositorNode::render */
659 void render(const RenderCompositorNodeInputs& inputs) override;
660
661 /** @copydoc RenderCompositorNode::clear */
662 void clear() override;
663
664 /** Cleans up any outputs. */
665 void deallocOutputs();
666
667 SPtr<PooledRenderTexture> mPooledOutput;
668 SPtr<PooledRenderTexture> mPrevFrame;
669 };
670
671 /** Renders the bloom effect. */
672 class RCNodeBloom : public RenderCompositorNode
673 {
674 public:
675 SPtr<Texture> output;
676
677 static StringID getNodeId() { return "Bloom"; }
678 static SmallVector<StringID, 4> getDependencies(const RendererView& view);
679 protected:
680 /** @copydoc RenderCompositorNode::render */
681 void render(const RenderCompositorNodeInputs& inputs) override;
682
683 /** @copydoc RenderCompositorNode::clear */
684 void clear() override;
685
686 SPtr<PooledRenderTexture> mPooledOutput;
687 };
688
689 /** @} */
690}}
691