Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp
Josh Adams ac8b6f2e72 Copying //UE4/Dev-Platform to //UE4/Dev-Main (Source: //UE4/Dev-Platform @ 3046626)
#rb none
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2948322 on 2016/04/19 by Nick.Shin

	update libwebsockets to v1.7.4

	part 4 of 4 - doing this in stages for tracking purposes

	#jira UEPLAT-1246  -  Update libWebsockets
	#jira UEPLAT-1221  -  update websocket library
	#jira UEPLAT-1204  -  Rebuild libwebsockets with SSL

Change 2970016 on 2016/05/07 by Nick.Shin

	undo all of the following upgrades:
	- zlib
	- openssl
	- libcurl
	- libwebsockets

	and reset webrtc

	#jira UE-30298 - Fortnite and Orion crash on login

Change 3020547 on 2016/06/20 by Jeff.Campeau

	Support for applocal deployment of binaries
	-applocaldir added to UAT to specify a per project directory to gather packages for applocal deployment
	Added ApplocalPrerequisitesDirectory property to packaging settings to set -applocaldir for packages built from the editor.

Change 3020552 on 2016/06/20 by Jeff.Campeau

	Add switch to disable debug symbol cache creation

Change 3020567 on 2016/06/20 by Jeff.Campeau

	constexpr enabled for Xbox One

Change 3020568 on 2016/06/20 by Jeff.Campeau

	Separate setting for debug
	#jira UEPLAT-1348

Change 3020628 on 2016/06/20 by Jeff.Campeau

	Use global view instead of relying on current thread (fixes issues if pump message is called from a different thread).

Change 3020629 on 2016/06/20 by Jeff.Campeau

	Use Slate tick to drive message processing during blocking loads (improves PLM).

Change 3020633 on 2016/06/20 by Jeff.Campeau

	Fix Xbox One toolchain pathing to work for environment variables with and without trailing slashes.
	Pass requested XDK edition to VCVars batch file (fixes issues in building with a newer XDK installed SxS than the engine is configured for).

Change 3020873 on 2016/06/21 by Lee.Clark

	PS4 - Fix missing audio when using A3D.

Change 3021225 on 2016/06/21 by Keith.Judge

	Optimized away a bunch of GetVertexShader() calls in FSplineMeshVertexFactoryShaderParameters::SetMesh(). Saves about 0.9ms across a 100ms capture.

Change 3021286 on 2016/06/21 by Dmitry.Rekman

	Linux: symbolication for memory profiler.

	- Also repaired/improved finding function name from debug info and overall callstack parsing.

	#tests Ran Linux editor and TestPAL, crashed multiple times

Change 3021512 on 2016/06/21 by Mark.Satterthwaite

	Compile fixes for new clang version.

Change 3021521 on 2016/06/21 by Mark.Satterthwaite

	Duplicate Fortnite CL #3013418: Don't release Metal buffers directly into the buffer pool, instead defer this until the command-buffer is known to have finished. This prevents the CPU from trying to modify the buffer while the GPU is still reading it if the GPU has fallen so far behind the CPU and therefore eliminates one possible cause of invalid access on the GPU.

Change 3021528 on 2016/06/21 by Mark.Satterthwaite

	Make the Metal buffer pool cull after 30 frames - this will better match Apple's GART which unwires unused allocations after 1sec of idle, making them as expensive to use allocating a new buffer.

Change 3021595 on 2016/06/21 by Mark.Satterthwaite

	Consolidate the way in which optional Metal features are exposed across macOS, iOS & tvOS devices & expose all the available features, unifying more of the code across all three platforms.
	- Implement Metal Depth-16 and stencil-texture-view support where available.
	- Use counting queries in Metal when available and expected (i.e. Metal_SM4+ or Metal_MRT+).
	- On latest iOS devices running Metal export support for GRHISupportsBaseVertexIndex & GRHISupportsFirstInstance when available.
	- On latest iOS devices running Metal export support for indirect buffer draw and dispatch calls.
	- Specify Metal layered rendering like any other and change the code so that there aren't preprocessor defines in the code. This lets the Metal MRT path assert if anyone ever tries to issue a layered draw call as its only supported on Mac.
	- Add support to Metal for setting UAVs from a uniform buffer.
	- Remove unused GlobalUniform header from MetalRHI.
	- Remove unnecessary FrameCount delay from Metal resource free lists.

Change 3021702 on 2016/06/21 by Mark.Satterthwaite

	Fix mis-use of FreeListMutex instead of PoolMutex in MetalContext.

Change 3022152 on 2016/06/21 by Nick.Shin

	Back out revision 5 from //UE4/Dev-Platform/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.cpp

	forgot to un-do this when the giant revert (CL: #2970016) was done

	#jira UE-22166 HTML5 Cook on the fly will launch and then close browser

Change 3022409 on 2016/06/21 by Dmitry.Rekman

	Fixed inability to run Setup.sh on Ubuntu 14.04 (UE-29289).

	- Contains PR #2258 (contributed by wshearn).

Change 3022541 on 2016/06/22 by Lee.Clark

	PS4 - Make sure the render target masks are set correctly for disabled render targets.
	Fixes a validation check for shaders expecting to write to NULL render targets.

Change 3022973 on 2016/06/22 by Michael.Trepka

	Fixed a problem in MacToolChain where both BuildConfiguration.bGeneratedSYMFile and BuildConfiguration.bUsePDBFiles set to false would not disable dSYM generation.

Change 3023106 on 2016/06/22 by Dmitry.Rekman

	Linux: enable code to catch memory stomps during async loading.

	- Changed FLinuxPlatformMemory::BinnedAllocFrom/FreeToOS() to use mmap()/munmap(). Updated platform function signature accordingly.

	#tests Ran OrionServer on Linux (and OrionClient on Windows as a zero probe), tested also with running Linux editor with binned malloc.

Change 3023256 on 2016/06/22 by Mark.Satterthwaite

	Fix compile errors from latest Metal changes that broke iOS.

Change 3023268 on 2016/06/22 by Mark.Satterthwaite

	Use the Linux mmap/munmap/mprotect code to implement BinnedAllocFromOS/BinnedFreeToOS/PageProtect on Apple platforms as they are all equivalent.

Change 3023651 on 2016/06/22 by Mark.Satterthwaite

	Make Metal SM5 the default for 10.11.5 or later, this time most of the features should be working on AMD & Nvidia, though tiled-reflections and distance-field AO/Shadows must still be forcibly disabled on Intel.

Change 3023777 on 2016/06/22 by Brent.Pease

	 + Update config for Android and iOS

Change 3023781 on 2016/06/22 by Chris.Babcock

	Use mmap/munmap for Android BinnedAllocFromOS
	#ue4
	#android

Change 3023947 on 2016/06/22 by Mark.Satterthwaite

	Added a command-line switch for Mac "-RedirectNSLog" that will capture the output of NSLog using an NSPipe and write it into our log instead when not running under the debugger, thereby capturing output from underlying libraries that would otherwise be lost when outside a debugger.

Change 3024434 on 2016/06/23 by Lee.Clark

	PS4 - Remove Delta Color Compression support

Change 3024735 on 2016/06/23 by Mark.Satterthwaite

	Changes to MetalStatistics module initialisation.

Change 3024741 on 2016/06/23 by Mark.Satterthwaite

	Change the way we test for Metal GPU support to avoid instantiating any MTLDevice's until MetalRHI is loaded so we can properly instantiate optional modules.

Change 3025477 on 2016/06/23 by Brent.Pease

	 + Added UnrealPluginLanguage.cs based on AndroidPluginLanguage.cs
	 + Change UEDeployAndroid.cs to use UnrealPluginLanguage

Change 3026085 on 2016/06/23 by Jeff.Campeau

	Separate Xbox One target settings for editor only values
	Move values that need to be loaded by the editor into the default inis (editor won't load target specific inis)
	Eliminate circular dependency on Xbox One settings (causing settings to either not load or memory corruption on shutdown)
	Clean up cached ini sections for UBT/UAT

Change 3026093 on 2016/06/23 by Jeff.Campeau

	Cleanup unused files

Change 3026745 on 2016/06/24 by Mark.Satterthwaite

	+ Implemented rudimentary runtime debugging of MetalRHI with several different levels of complexity controlled by the new console-variable "rhi.Metal.RuntimeDebugLevel".
	+ The MetalStateCache must also correctly set the render-pass descriptor when the previous render-target load action was 'Clear' as we will need to switch render targets or we'll mistakenly clear again.
	+ Queries must not reset the MetalStateCache when they overflow the available buffer space, they simply break the encoder.

	-  By default "rhi.Metal.RuntimeDebugLevel" is off & it is compiled out for Shipping - when enabled each higher level collects more data or changes the MetalRHI behaviour to make a command-buffer failure mode debuggable at the expense of performance. In order for this to work the number of command-buffers that may be allocated from the command-queue is also controllable via a console-variable "rhi.Metal.CommandQueueSize" which must be set prior to startup.

Change 3026831 on 2016/06/24 by Josh.Adams

	Merging //UE4/Dev-Main to Dev-Platform (//UE4/Dev-Platform)

Change 3026940 on 2016/06/24 by Brent.Pease

	PR #2458: added GetGameBundleId blueprint function (Contributed by derekvanvliet)

Change 3027396 on 2016/06/24 by Brent.Pease

	Add BuildGraph.csproj to get Xamarin .sln builds working again

Change 3029211 on 2016/06/27 by Michael.Trepka

	Added a setting (on by default) to make the game window preserve its content's aspect ratio while being resized by user

Change 3029518 on 2016/06/27 by Josh.Adams

	Rollback //UE4/Dev-Platform/Engine/Build/BatchFiles/Mac/xcodeunlock.sh to revision 1

Change 3030385 on 2016/06/28 by Keith.Judge

	Fix XB1 deployment issues with AppXManifest for Paragon.

Change 3030416 on 2016/06/28 by Lee.Clark

	PS4 - Fix Mediaplayer IsPlaying

Change 3030922 on 2016/06/28 by Keith.Judge

	XB1 - Add pass through _RenderThread resource creation functions to D3D11.x RHI. Stops the render/RHI threads from stalling so much.

Change 3030948 on 2016/06/28 by Jeff.Campeau

	Revert to using constant chunk indexes instead of polling the OS.
	(OS API has a bug that will not be fixed.)

Change 3031016 on 2016/06/28 by Brent.Pease

	UEPLAT-1244 - Archive dSYM file
	UEPLAT-1359 - Support creating dSYM bundle

	Changes:
	 + Added ios settings flag for dsym bundle
	 + Added ios setting for creating xcode archive
	 + xcode archive is now only put in the mac host or build machine's ~/Library/Developer/Xcode/Archives folder, it is not copied into the -archive folder like the ipa is

Change 3031352 on 2016/06/28 by Bob.Tellez

	Added tps file for xcodeunlock

Change 3031604 on 2016/06/28 by Mark.Satterthwaite

	Add an additional cast to flush-to-zero in the Metal shader translator bounds-checking code to avoid an internal GPU compiler error.

Change 3031879 on 2016/06/28 by Brent.Pease

	 + PhysX libraries for bitcode support on tvOS.

Change 3032374 on 2016/06/29 by Keith.Judge

	Enable Oodle Handler Component on Xbox One

Change 3032407 on 2016/06/29 by Keith.Judge

	Xbox One - Disable UpdateBufferStats when STATS is 0. Small perf gain.

Change 3032432 on 2016/06/29 by Keith.Judge

	XB1 CPU Perf - Make CreateVertexDeclaration_RenderThread much faster by implementing a pass through to the RHI function rather than stalling the RHI thread.

Change 3033474 on 2016/06/29 by Josh.Adams

	Merging //UE4/Dev-Main to Dev-Platform (//UE4/Dev-Platform)

Change 3033603 on 2016/06/29 by Brent.Pease

	 + Support UnrealPluginLanguage for IOS and TVOS builds
	 + Allow ios/tvos UPL files an opportunity to modify a package's info.plist file

Change 3034004 on 2016/06/30 by Lee.Clark

	PS4 - Use SDK 3.508.101

Change 3034007 on 2016/06/30 by Lee.Clark

	PS4 - VRTracker now uses SCE_VR_TRACKER_ROBUSTNESS_LEVEL_HIGH

Change 3034173 on 2016/06/30 by Lee.Clark

	PS4 - Make sure depth target is null when eliminating fast clears. Fixes a GNM Validation failure

Change 3034498 on 2016/06/30 by Jeff.Campeau

	Use MSBuild version 14 when generating project files.

Change 3034943 on 2016/06/30 by Mark.Satterthwaite

	For Metal modify the MTLVertexDescriptor when calls to SetStreamSource provide different strides than the initial vertex-declaration which then requires compiling a different MTLRenderPipelineState. This silences errors reported by the Metal debug layer where the larger stride would see the shader read beyond the end of the buffer, but the smaller stride provided by SetStreamSource would work correctly. This may eliminate some more causes of Page-Fault GPU restarts.

Change 3035416 on 2016/07/01 by Lee.Clark

	PS4 - Replace export vertex shader check with a CFLAG

Change 3036093 on 2016/07/01 by Brent.Pease

	 + Fix dSYM bundle path on Windows ios builds
	 + Search for DeltaCopy directory if its not found from the user settings
	 + Do not build an XCArchive file when building for ios on non-mac platforms

Change 3036726 on 2016/07/02 by Brent.Pease

	 + Add missing tvOS bitcode library

Change 3037455 on 2016/07/05 by Lee.Clark

	PS4 - Default SmoothFrameRate to false

Change 3037470 on 2016/07/05 by Keith.Judge

	Xbox One - Allow framerate smoothing, but default to off for consistency with PS4.

Change 3038322 on 2016/07/05 by Jeremiah.Waldron

	Fix for asset packages with Unicode characters in their name not being loaded on Android.

	Fixing AndroidString's WIDECHAR* Strstr(WIDECHAR*, WIDECHAR*) function
	  - Using an implementation of wcsstr, with a fix integrated for the incorrect implementation in Android ndk master branch, instead of converting the incoming WIDECHAR strings to ANSI strings just to be able to use strstr on them.

	The previous method was prone to causing the FString's Find and Contains functions to return false positives because when we convert wide to ansi, any character over the value of 255 is just set to '?'
	This in turn caused any package path strings with one of those characters in it to fail to load since they would be interpreted as having a question mark in their path, which is an invalid path character.

	#jira UE-18643
	#android

Change 3038693 on 2016/07/05 by Mark.Satterthwaite

	Change the way we store debug info for Metal shaders - the KeepDebugInfo flag now does precisely that, storing the shader code into the Metal header along with the path it was generated from. That means if KeepDebugInfo is enabled and Optimise is disabled then we can still access the shader code from within the Metal tools. On iOS/tvOS the shader code will be runtime compiled so that it shows up in the tooling but on Macs it will prefer to load the optimised version and simply unpack the shader code to the path from which it was compiled. This only works if we change the Metal shader compiler to emit temporary Metal files to the OS temporary directory so that the tools can read the file directly.

Change 3039880 on 2016/07/06 by Mark.Satterthwaite

	Implement point-light shadow caching for RHI's that support specifying the render target layer from the vertex shader in lieu of geometry shaders. This requires changing FScreenVSForGS to TScreenVSForGS so that there can be a vertex-shader-layer variant (only compiled on RHI's that use it) whose output matches FCopyShadowMapsCubePS input. This alternative rendering path also requires adding the instance count to DrawRectangle so that we can render to all faces of the cubemap from a single draw call.

Change 3040407 on 2016/07/06 by Michael.Trepka

	Added View->Enter Full Screen menu item for games on Mac

Change 3040550 on 2016/07/06 by Mark.Satterthwaite

	Intel Metal compiler requires bool expressions be cast to 'int' rather than 'uint'.

Change 3041098 on 2016/07/07 by Peter.Sauerbrei

	initial changes to get IOS builds from PC in launcher release of engine

Change 3041310 on 2016/07/07 by Keith.Judge

	Xbox One - Optimize away GetDesc() and checks for D3D11_USAGE_DYNAMIC deep in the state cache as it's impossible for any buffer to have that flag set.

Change 3041327 on 2016/07/07 by Keith.Judge

	Xbox One - Remove pointless memory barrier call in D3D11Query

Change 3041352 on 2016/07/07 by Keith.Judge

	Xbox One - Add _RenderThread version of UpdateTexture2D() that just passes through to the RHI one. Saves a fairly significant chunk of time on the render/RHI thread when this is called a lot.

Change 3041419 on 2016/07/07 by Jeff.Campeau

	Xbox One toolchain fix for VS2015 Update 3

Change 3041635 on 2016/07/07 by Jeff.Campeau

	Don't change game render resolution in response to WM_SIZE messages when in fullscreen (the game will restore the correct video mode when the window is restored).
	#jira OR-15578

Change 3041735 on 2016/07/07 by Peter.Sauerbrei

	re-enabled the build parameters for launcher release builds in IOS

Change 3041783 on 2016/07/07 by Joe.Graf

	Changed bAutpApplyFailed to bAutoApplyFailed (typo)

Change 3041784 on 2016/07/07 by Joe.Graf

	Fixed missing %s from a log message in UResavePackagesCommandlet

Change 3042434 on 2016/07/08 by Lee.Clark

	PS4 - Fix compilation failure when Unsafe Command Buffers are enabled.

Change 3042658 on 2016/07/08 by Lee.Clark

	PS4 - Use SDK 3.508.201

Change 3042970 on 2016/07/08 by Josh.Adams

	Redoing CL in 3040890 in Dev-Platform

Change 3043243 on 2016/07/08 by Chris.Babcock

	clamped allowed slot range for gameplay debugger's categories
	copy of CL# 3040313 from //UE4/Dev-Framework
	#jira UE-32866

Change 3043500 on 2016/07/08 by Mark.Satterthwaite

	Downgrade "-Wdelete-non-virtual-dtor " to a warning again for Xcode 8 on iOS/tvOS to match macOS.

Change 3044628 on 2016/07/11 by Mark.Satterthwaite

	Disable ShaderCache by default - it was implemented prior to RHI-thread/parallel-execution so it isn't thread-safe and can't be enabled by default on Mac now that Metal supports these features.
	#jira UE-32989

Change 3044948 on 2016/07/11 by Dmitry.Rekman

	Fix editor crash (happened on Linux, but not really specific to it) (UE-32973)

	- We can pass flags with shadows enabled when rendering asset thumbnails; thus disable shadows always when r.ShadowQuality is 0. (Redoing CL 3029574 by Bob).
	- Also fix mismatched 'noperspective' qualifier that caused NVidia drivers to refuse to link GL shaders.

	#jira UE-32973

Change 3045322 on 2016/07/11 by Josh.Adams

	Merging //UE4/Dev-Main to Dev-Platform (//UE4/Dev-Platform)

Change 3046028 on 2016/07/12 by Lee.Clark

	PS4 - Check for correct SDK installation
	Allow use of 7th core when Morpheus is enabled

Change 3046339 on 2016/07/12 by Peter.Sauerbrei

	fix for incorrect error message when iPhone Plus icon is the correct size

[CL 3046645 by Josh Adams in Main branch]
2016-07-12 15:06:08 -04:00

2457 lines
96 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
SceneRenderTargets.cpp: Scene render target implementation.
=============================================================================*/
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "ScreenRendering.h"
#include "SceneFilterRendering.h"
#include "ReflectionEnvironment.h"
#include "LightPropagationVolume.h"
#include "SceneUtils.h"
#include "HdrCustomResolveShaders.h"
#include "Public/LightPropagationVolumeBlendable.h"
#include "Engine/EngineTypes.h"
IMPLEMENT_UNIFORM_BUFFER_STRUCT(FGBufferResourceStruct,TEXT("GBuffers"));
static TAutoConsoleVariable<int32> CVarBasePassOutputsVelocityDebug(
TEXT("r.BasePassOutputsVelocityDebug"),
0,
TEXT("Debug settings for Base Pass outputting velocity.\n")
TEXT("0 - Regular rendering\n")
TEXT("1 - Skip setting GBufferVelocity RT\n")
TEXT("2 - Set Color Mask 0 for GBufferVelocity RT"),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarRSMResolution(
TEXT("r.LPV.RSMResolution"),
360,
TEXT("Reflective Shadow Map resolution (used for LPV) - higher values result in less aliasing artifacts, at the cost of performance"),
ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GBasePassOutputsVelocityDebug = 0;
/*-----------------------------------------------------------------------------
FSceneRenderTargets
-----------------------------------------------------------------------------*/
int32 GDownsampledOcclusionQueries = 0;
static FAutoConsoleVariableRef CVarDownsampledOcclusionQueries(
TEXT("r.DownsampledOcclusionQueries"),
GDownsampledOcclusionQueries,
TEXT("Whether to issue occlusion queries to a downsampled depth buffer"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarSceneTargetsResizingMethod(
TEXT("r.SceneRenderTargetResizeMethod"),
0,
TEXT("Control the scene render target resize method:\n")
TEXT("(This value is only used in game mode and on windowing platforms.)\n")
TEXT("0: Resize to match requested render size (Default) (Least memory use, can cause stalls when size changes e.g. ScreenPercentage)\n")
TEXT("1: Fixed to screen resolution.\n")
TEXT("2: Expands to encompass the largest requested render dimension. (Most memory use, least prone to allocation stalls.)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarOptimizeForUAVPerformance(
TEXT("r.OptimizeForUAVPerformance"),
0,
TEXT("Allows to profile if hardware has a performance cost due to render target reuse (more info: search for GCNPerformanceTweets.pdf Tip 37)\n")
TEXT("If we see a noticeable difference on some hardware we can add another option like -1 (meaning auto) and make it the new default.\n")
TEXT("0: Optimize for GPU memory savings and reuse render targets (default)\n")
TEXT("1: Optimize for GPU performance (might render faster but can require more GPU memory)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarCustomDepth(
TEXT("r.CustomDepth"),
1,
TEXT("0: feature is disabled\n")
TEXT("1: feature is enabled, texture is created on demand\n")
TEXT("2: feature is enabled, texture is not released until required (should be the project setting if the feature should not stall)\n")
TEXT("3: feature is enabled, stencil writes are enabled, texture is not released until required (should be the project setting if the feature should not stall)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMobileMSAA(
TEXT("r.MobileMSAA"),
0,
TEXT("Use MSAA instead of Temporal AA on mobile:\n")
TEXT("1: Use Temporal AA (MSAA disabled)\n")
TEXT("2: Use 2x MSAA (Temporal AA disabled)\n")
TEXT("4: Use 4x MSAA (Temporal AA disabled)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarGBufferFormat(
TEXT("r.GBufferFormat"),
1,
TEXT("Defines the memory layout used for the GBuffer.\n")
TEXT("(affects performance, mostly through bandwidth, quality of normals and material attributes).\n")
TEXT(" 0: lower precision (8bit per component, for profiling)\n")
TEXT(" 1: low precision (default)\n")
TEXT(" 3: high precision normals encoding\n")
TEXT(" 5: high precision"),
ECVF_RenderThreadSafe);
/** The global render targets used for scene rendering. */
static TGlobalResource<FSceneRenderTargets> SceneRenderTargetsSingleton;
FSceneRenderTargets& FSceneRenderTargets::Get(FRHICommandList& RHICmdList)
{
FSceneRenderTargets* SceneContext = (FSceneRenderTargets*)RHICmdList.GetRenderThreadContext(FRHICommandListBase::ERenderThreadContext::SceneRenderTargets);
if (!SceneContext)
{
return SceneRenderTargetsSingleton;
}
check(!RHICmdList.IsImmediate());
return *SceneContext;
}
FSceneRenderTargets& FSceneRenderTargets::Get(FRHICommandListImmediate& RHICmdList)
{
check(IsInRenderingThread() && !RHICmdList.GetRenderThreadContext(FRHICommandListBase::ERenderThreadContext::SceneRenderTargets)
&& !FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RenderThread_Local)); // if we are processing tasks on the local queue, it is assumed this are in support of async tasks, which cannot use the current state of the render targets. This can be relaxed if needed.
return SceneRenderTargetsSingleton;
}
FSceneRenderTargets& FSceneRenderTargets::Get(FRHIAsyncComputeCommandListImmediate& RHICmdList)
{
check(IsInRenderingThread() && !RHICmdList.GetRenderThreadContext(FRHICommandListBase::ERenderThreadContext::SceneRenderTargets)
&& !FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RenderThread_Local)); // if we are processing tasks on the local queue, it is assumed this are in support of async tasks, which cannot use the current state of the render targets. This can be relaxed if needed.
return SceneRenderTargetsSingleton;
}
FSceneRenderTargets& FSceneRenderTargets::Get_Todo_PassContext()
{
check(IsInRenderingThread()
&& !FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RenderThread_Local)); // if we are processing tasks on the local queue, it is assumed this are in support of async tasks, which cannot use the current state of the render targets. This can be relaxed if needed.
return SceneRenderTargetsSingleton;
}
FSceneRenderTargets& FSceneRenderTargets::Get_FrameConstantsOnly()
{
return SceneRenderTargetsSingleton;
}
FSceneRenderTargets* FSceneRenderTargets::CreateSnapshot(const FViewInfo& InView)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FSceneRenderTargets_CreateSnapshot);
check(IsInRenderingThread() && FMemStack::Get().GetNumMarks() == 1); // we do not want this popped before the end of the scene and it better be the scene allocator
FSceneRenderTargets* NewSnapshot = new (FMemStack::Get()) FSceneRenderTargets(InView, *this);
check(NewSnapshot->bSnapshot);
Snapshots.Add(NewSnapshot);
return NewSnapshot;
}
void FSceneRenderTargets::SetSnapshotOnCmdList(FRHICommandList& TargetCmdList)
{
check(bSnapshot);
TargetCmdList.SetRenderThreadContext(this, FRHICommandListBase::ERenderThreadContext::SceneRenderTargets);
}
void FSceneRenderTargets::DestroyAllSnapshots()
{
if (Snapshots.Num())
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FSceneRenderTargets_DestroyAllSnapshots);
check(IsInRenderingThread());
for (auto Snapshot : Snapshots)
{
Snapshot->~FSceneRenderTargets();
}
Snapshots.Reset();
GRenderTargetPool.DestructSnapshots();
}
}
template <size_t N>
static void SnapshotArray(TRefCountPtr<IPooledRenderTarget> (&Dest)[N], const TRefCountPtr<IPooledRenderTarget> (&Src)[N])
{
for (int32 Index = 0; Index < N; Index++)
{
Dest[Index] = GRenderTargetPool.MakeSnapshot(Src[Index]);
}
}
FSceneRenderTargets::FSceneRenderTargets(const FViewInfo& View, const FSceneRenderTargets& SnapshotSource)
: LightAttenuation(GRenderTargetPool.MakeSnapshot(SnapshotSource.LightAttenuation))
, LightAccumulation(GRenderTargetPool.MakeSnapshot(SnapshotSource.LightAccumulation))
, DirectionalOcclusion(GRenderTargetPool.MakeSnapshot(SnapshotSource.DirectionalOcclusion))
, SceneDepthZ(GRenderTargetPool.MakeSnapshot(SnapshotSource.SceneDepthZ))
, LightingChannels(GRenderTargetPool.MakeSnapshot(SnapshotSource.LightingChannels))
, NoMSAASceneDepthZ(GRenderTargetPool.MakeSnapshot(SnapshotSource.NoMSAASceneDepthZ))
, SceneAlphaCopy(GRenderTargetPool.MakeSnapshot(SnapshotSource.SceneAlphaCopy))
, AuxiliarySceneDepthZ(GRenderTargetPool.MakeSnapshot(SnapshotSource.AuxiliarySceneDepthZ))
, SmallDepthZ(GRenderTargetPool.MakeSnapshot(SnapshotSource.SmallDepthZ))
, GBufferA(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferA))
, GBufferB(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferB))
, GBufferC(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferC))
, GBufferD(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferD))
, GBufferE(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferE))
, GBufferVelocity(GRenderTargetPool.MakeSnapshot(SnapshotSource.GBufferVelocity))
, DBufferA(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferA))
, DBufferB(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferB))
, DBufferC(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferC))
, ScreenSpaceAO(GRenderTargetPool.MakeSnapshot(SnapshotSource.ScreenSpaceAO))
, QuadOverdrawBuffer(GRenderTargetPool.MakeSnapshot(SnapshotSource.QuadOverdrawBuffer))
, CustomDepth(GRenderTargetPool.MakeSnapshot(SnapshotSource.CustomDepth))
, CustomStencilSRV(SnapshotSource.CustomStencilSRV)
, OptionalShadowDepthColor(GRenderTargetPool.MakeSnapshot(SnapshotSource.OptionalShadowDepthColor))
, PreShadowCacheDepthZ(GRenderTargetPool.MakeSnapshot(SnapshotSource.PreShadowCacheDepthZ))
, SkySHIrradianceMap(GRenderTargetPool.MakeSnapshot(SnapshotSource.SkySHIrradianceMap))
, EditorPrimitivesColor(GRenderTargetPool.MakeSnapshot(SnapshotSource.EditorPrimitivesColor))
, EditorPrimitivesDepth(GRenderTargetPool.MakeSnapshot(SnapshotSource.EditorPrimitivesDepth))
, SeparateTranslucencyRT(SnapshotSource.SeparateTranslucencyRT)
, SeparateTranslucencyDepthRT(SnapshotSource.SeparateTranslucencyDepthRT)
, bScreenSpaceAOIsValid(SnapshotSource.bScreenSpaceAOIsValid)
, bCustomDepthIsValid(SnapshotSource.bCustomDepthIsValid)
, bPreshadowCacheNewlyAllocated(SnapshotSource.bPreshadowCacheNewlyAllocated)
, GBufferRefCount(SnapshotSource.GBufferRefCount)
, LargestDesiredSizeThisFrame(SnapshotSource.LargestDesiredSizeThisFrame)
, LargestDesiredSizeLastFrame(SnapshotSource.LargestDesiredSizeLastFrame)
, ThisFrameNumber(SnapshotSource.ThisFrameNumber)
, bVelocityPass(SnapshotSource.bVelocityPass)
, bSeparateTranslucencyPass(SnapshotSource.bSeparateTranslucencyPass)
, GBufferResourcesUniformBuffer(SnapshotSource.GBufferResourcesUniformBuffer)
, BufferSize(SnapshotSource.BufferSize)
, SeparateTranslucencyBufferSize(SnapshotSource.SeparateTranslucencyBufferSize)
, SeparateTranslucencyScale(SnapshotSource.SeparateTranslucencyScale)
, SmallColorDepthDownsampleFactor(SnapshotSource.SmallColorDepthDownsampleFactor)
, bLightAttenuationEnabled(SnapshotSource.bLightAttenuationEnabled)
, bUseDownsizedOcclusionQueries(SnapshotSource.bUseDownsizedOcclusionQueries)
, CurrentGBufferFormat(SnapshotSource.CurrentGBufferFormat)
, CurrentSceneColorFormat(SnapshotSource.CurrentSceneColorFormat)
, bAllowStaticLighting(SnapshotSource.bAllowStaticLighting)
, CurrentMaxShadowResolution(SnapshotSource.CurrentMaxShadowResolution)
, CurrentRSMResolution(SnapshotSource.CurrentRSMResolution)
, CurrentTranslucencyLightingVolumeDim(SnapshotSource.CurrentTranslucencyLightingVolumeDim)
, CurrentMobile32bpp(SnapshotSource.CurrentMobile32bpp)
, CurrentMobileMSAA(SnapshotSource.CurrentMobileMSAA)
, CurrentMinShadowResolution(SnapshotSource.CurrentMinShadowResolution)
, bCurrentLightPropagationVolume(SnapshotSource.bCurrentLightPropagationVolume)
, CurrentFeatureLevel(SnapshotSource.CurrentFeatureLevel)
, CurrentShadingPath(SnapshotSource.CurrentShadingPath)
, bAllocateVelocityGBuffer(SnapshotSource.bAllocateVelocityGBuffer)
, bGBuffersFastCleared(SnapshotSource.bGBuffersFastCleared)
, bSceneDepthCleared(SnapshotSource.bSceneDepthCleared)
, bSnapshot(true)
, QuadOverdrawIndex(SnapshotSource.QuadOverdrawIndex)
{
SnapshotArray(SceneColor, SnapshotSource.SceneColor);
SnapshotArray(ReflectionColorScratchCubemap, SnapshotSource.ReflectionColorScratchCubemap);
SnapshotArray(DiffuseIrradianceScratchCubemap, SnapshotSource.DiffuseIrradianceScratchCubemap);
SnapshotArray(ReflectionBrightness, SnapshotSource.ReflectionBrightness);
SnapshotArray(TranslucencyLightingVolumeAmbient, SnapshotSource.TranslucencyLightingVolumeAmbient);
SnapshotArray(TranslucencyLightingVolumeDirectional, SnapshotSource.TranslucencyLightingVolumeDirectional);
}
inline const TCHAR* GetReflectionBrightnessTargetName(uint32 Index)
{
const TCHAR* Names[2] =
{
TEXT("ReflectionBrightness0"),
TEXT("ReflectionBrightness1")
};
check(Index < ARRAY_COUNT(Names));
return Names[Index];
}
inline const TCHAR* GetSceneColorTargetName(EShadingPath ShadingPath)
{
const TCHAR* SceneColorNames[(uint32)EShadingPath::Num] =
{
TEXT("SceneColorMobile"),
TEXT("SceneColorDeferred")
};
check((uint32)ShadingPath < ARRAY_COUNT(SceneColorNames));
return SceneColorNames[(uint32)ShadingPath];
}
FIntPoint FSceneRenderTargets::ComputeDesiredSize(const FSceneViewFamily& ViewFamily)
{
enum ESizingMethods { RequestedSize, ScreenRes, Grow, VisibleSizingMethodsCount };
ESizingMethods SceneTargetsSizingMethod = Grow;
bool bIsSceneCapture = false;
bool bIsReflectionCapture = false;
for (int32 ViewIndex = 0, ViewCount = ViewFamily.Views.Num(); ViewIndex < ViewCount; ++ViewIndex)
{
const FSceneView* View = ViewFamily.Views[ViewIndex];
bIsSceneCapture |= View->bIsSceneCapture;
bIsReflectionCapture |= View->bIsReflectionCapture;
}
if(!FPlatformProperties::SupportsWindowedMode())
{
// Force ScreenRes on non windowed platforms.
SceneTargetsSizingMethod = RequestedSize;
}
else if (GIsEditor)
{
// Always grow scene render targets in the editor.
SceneTargetsSizingMethod = Grow;
}
else
{
// Otherwise use the setting specified by the console variable.
SceneTargetsSizingMethod = (ESizingMethods) FMath::Clamp(CVarSceneTargetsResizingMethod.GetValueOnRenderThread(), 0, (int32)VisibleSizingMethodsCount);
}
FIntPoint DesiredBufferSize = FIntPoint::ZeroValue;
switch (SceneTargetsSizingMethod)
{
case RequestedSize:
DesiredBufferSize = FIntPoint(ViewFamily.FamilySizeX, ViewFamily.FamilySizeY);
break;
case ScreenRes:
DesiredBufferSize = FIntPoint(GSystemResolution.ResX, GSystemResolution.ResY);
break;
case Grow:
DesiredBufferSize = FIntPoint(FMath::Max((uint32)GetBufferSizeXY().X, ViewFamily.FamilySizeX),
FMath::Max((uint32)GetBufferSizeXY().Y, ViewFamily.FamilySizeY));
break;
default:
checkNoEntry();
}
// we want to shrink the buffer but as we can have multiple scenecaptures per frame we have to delay that a frame to get all size requests
{
// this allows The BufferSize to not grow below the SceneCapture requests (happen before scene rendering, in the same frame with a Grow request)
LargestDesiredSizeThisFrame = LargestDesiredSizeThisFrame.ComponentMax(DesiredBufferSize);
uint32 FrameNumber = ViewFamily.FrameNumber;
// this could be refined to be some time or multiple frame if we have SceneCaptures not running each frame any more
if(ThisFrameNumber != FrameNumber)
{
// this allows the BufferSize to shrink each frame (in game)
ThisFrameNumber = FrameNumber;
LargestDesiredSizeLastFrame = LargestDesiredSizeThisFrame;
LargestDesiredSizeThisFrame = FIntPoint(0, 0);
}
DesiredBufferSize = DesiredBufferSize.ComponentMax(LargestDesiredSizeLastFrame);
}
return DesiredBufferSize;
}
inline uint16 GetNumSceneColorMSAASamples(ERHIFeatureLevel::Type InFeatureLevel)
{
if (InFeatureLevel > ERHIFeatureLevel::ES3_1 ||
//@todo-rco: Fix when iOS OpenGL supports MSAA
GShaderPlatformForFeatureLevel[InFeatureLevel] == SP_OPENGL_ES2_IOS)
{
return 1;
}
uint16 NumSamples = CVarMobileMSAA.GetValueOnRenderThread();
if (NumSamples != 1 && NumSamples != 2 && NumSamples != 4)
{
NumSamples = 1;
}
return NumSamples;
}
void FSceneRenderTargets::Allocate(FRHICommandList& RHICmdList, const FSceneViewFamily& ViewFamily)
{
check(IsInRenderingThread());
// ViewFamily setup wasn't complete
check(ViewFamily.FrameNumber != UINT_MAX);
// If feature level has changed, release all previously allocated targets to the pool. If feature level has changed but
const auto NewFeatureLevel = ViewFamily.Scene->GetFeatureLevel();
CurrentShadingPath = ViewFamily.Scene->GetShadingPath();
FIntPoint DesiredBufferSize = ComputeDesiredSize(ViewFamily);
check(DesiredBufferSize.X > 0 && DesiredBufferSize.Y > 0);
QuantizeBufferSize(DesiredBufferSize.X, DesiredBufferSize.Y);
int GBufferFormat = CVarGBufferFormat.GetValueOnRenderThread();
int SceneColorFormat;
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SceneColorFormat"));
SceneColorFormat = CVar->GetValueOnRenderThread();
}
bool bNewAllowStaticLighting;
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
bNewAllowStaticLighting = CVar->GetValueOnRenderThread() != 0;
}
bool bDownsampledOcclusionQueries = GDownsampledOcclusionQueries != 0;
int32 MaxShadowResolution = GetCachedScalabilityCVars().MaxShadowResolution;
int32 RSMResolution = FMath::Clamp(CVarRSMResolution.GetValueOnRenderThread(), 1, 2048);
if (ViewFamily.Scene->GetShadingPath() == EShadingPath::Mobile)
{
// ensure there is always enough space for mobile renderer's tiled shadow maps
// by reducing the shadow map resolution.
int32 MaxShadowDepthBufferDim = FMath::Max(GMaxShadowDepthBufferSizeX, GMaxShadowDepthBufferSizeY);
if (MaxShadowResolution * 2 > MaxShadowDepthBufferDim)
{
MaxShadowResolution = MaxShadowDepthBufferDim / 2;
}
}
int32 TranslucencyLightingVolumeDim = GTranslucencyLightingVolumeDim;
uint32 Mobile32bpp = !IsMobileHDR() || IsMobileHDR32bpp();
int32 MobileMSAA = GetNumSceneColorMSAASamples(NewFeatureLevel);
bool bLightPropagationVolume = UseLightPropagationVolumeRT(NewFeatureLevel);
uint32 MinShadowResolution;
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Shadow.MinResolution"));
MinShadowResolution = CVar->GetValueOnRenderThread();
}
if( (BufferSize.X != DesiredBufferSize.X) ||
(BufferSize.Y != DesiredBufferSize.Y) ||
(CurrentGBufferFormat != GBufferFormat) ||
(CurrentSceneColorFormat != SceneColorFormat) ||
(bAllowStaticLighting != bNewAllowStaticLighting) ||
(bUseDownsizedOcclusionQueries != bDownsampledOcclusionQueries) ||
(CurrentMaxShadowResolution != MaxShadowResolution) ||
(CurrentRSMResolution != RSMResolution) ||
(CurrentTranslucencyLightingVolumeDim != TranslucencyLightingVolumeDim) ||
(CurrentMobile32bpp != Mobile32bpp) ||
(CurrentMobileMSAA != MobileMSAA) ||
(bCurrentLightPropagationVolume != bLightPropagationVolume) ||
(CurrentMinShadowResolution != MinShadowResolution))
{
CurrentGBufferFormat = GBufferFormat;
CurrentSceneColorFormat = SceneColorFormat;
bAllowStaticLighting = bNewAllowStaticLighting;
bUseDownsizedOcclusionQueries = bDownsampledOcclusionQueries;
CurrentMaxShadowResolution = MaxShadowResolution;
CurrentRSMResolution = RSMResolution;
CurrentTranslucencyLightingVolumeDim = TranslucencyLightingVolumeDim;
CurrentMobile32bpp = Mobile32bpp;
CurrentMobileMSAA = MobileMSAA;
CurrentMinShadowResolution = MinShadowResolution;
bCurrentLightPropagationVolume = bLightPropagationVolume;
// Reinitialize the render targets for the given size.
SetBufferSize(DesiredBufferSize.X, DesiredBufferSize.Y);
UE_LOG(LogRenderer, Log, TEXT("Reallocating scene render targets to support %ux%u (Frame:%u)."), BufferSize.X, BufferSize.Y, ViewFamily.FrameNumber);
UpdateRHI();
}
// Do allocation of render targets if they aren't available for the current shading path
CurrentFeatureLevel = NewFeatureLevel;
AllocateRenderTargets(RHICmdList);
}
void FSceneRenderTargets::BeginRenderingSceneColor(FRHICommandList& RHICmdList, ESimpleRenderTargetMode RenderTargetMode/*=EUninitializedColorExistingDepth*/, FExclusiveDepthStencil DepthStencilAccess, bool bTransitionWritable)
{
SCOPED_DRAW_EVENT(RHICmdList, BeginRenderingSceneColor);
AllocSceneColor(RHICmdList);
SetRenderTarget(RHICmdList, GetSceneColorSurface(), GetSceneDepthSurface(), RenderTargetMode, DepthStencilAccess, bTransitionWritable);
}
int32 FSceneRenderTargets::GetGBufferRenderTargets(ERenderTargetLoadAction ColorLoadAction, FRHIRenderTargetView OutRenderTargets[MaxSimultaneousRenderTargets], int32& OutVelocityRTIndex)
{
int32 MRTCount = 0;
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GetSceneColorSurface(), 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferA->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferB->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferC->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
// The velocity buffer needs to be bound before other optionnal rendertargets (when UseSelecUseSelectiveBasePassOutputs() is true).
// Otherwise there is an issue on some AMD hardware where the target does not get updated. Seems to be related to the velocity buffer format as it works fine with other targets.
if (bAllocateVelocityGBuffer)
{
OutVelocityRTIndex = MRTCount;
check(OutVelocityRTIndex == 4); // As defined in BasePassPixelShader.usf
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferVelocity->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
}
else
{
OutVelocityRTIndex = -1;
}
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferD->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
if (bAllowStaticLighting)
{
check(MRTCount == (bAllocateVelocityGBuffer ? 6 : 5)); // As defined in BasePassPixelShader.usf
OutRenderTargets[MRTCount++] = FRHIRenderTargetView(GBufferE->GetRenderTargetItem().TargetableTexture, 0, -1, ColorLoadAction, ERenderTargetStoreAction::EStore);
}
check(MRTCount <= MaxSimultaneousRenderTargets);
return MRTCount;
}
void FSceneRenderTargets::BeginRenderingGBuffer(FRHICommandList& RHICmdList, ERenderTargetLoadAction ColorLoadAction, ERenderTargetLoadAction DepthLoadAction, bool bBindQuadOverdrawBuffers, const FLinearColor& ClearColor/*=(0,0,0,1)*/)
{
SCOPED_DRAW_EVENT(RHICmdList, BeginRenderingSceneColor);
if (IsAnyForwardShadingEnabled(GetFeatureLevelShaderPlatform(CurrentFeatureLevel)))
{
// in this non-standard case, just render to scene color with default mode
BeginRenderingSceneColor(RHICmdList, ColorLoadAction == ERenderTargetLoadAction::EClear ? ESimpleRenderTargetMode::EClearColorExistingDepth : ESimpleRenderTargetMode::EUninitializedColorExistingDepth);
return;
}
AllocSceneColor(RHICmdList);
// Set the scene color surface as the render target, and the scene depth surface as the depth-stencil target.
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4)
{
bool bClearColor = ColorLoadAction == ERenderTargetLoadAction::EClear;
bool bClearDepth = DepthLoadAction == ERenderTargetLoadAction::EClear;
//if the desired clear color doesn't match the bound hwclear value, or there isn't one at all (editor code)
//then we need to fall back to a shader clear.
const FTextureRHIRef& SceneColorTex = GetSceneColorSurface();
bool bShaderClear = false;
if (bClearColor)
{
if (!SceneColorTex->HasClearValue() || (ClearColor != SceneColorTex->GetClearColor()))
{
ColorLoadAction = ERenderTargetLoadAction::ENoAction;
bShaderClear = true;
}
else
{
bGBuffersFastCleared = true;
}
}
int32 VelocityRTIndex;
FRHIRenderTargetView RenderTargets[MaxSimultaneousRenderTargets];
int32 MRTCount = GetGBufferRenderTargets(ColorLoadAction, RenderTargets, VelocityRTIndex);
//make sure our conditions for shader clear fallback are valid.
check(RenderTargets[0].Texture == SceneColorTex);
FRHIDepthRenderTargetView DepthView(GetSceneDepthSurface(), DepthLoadAction, ERenderTargetStoreAction::EStore);
FRHISetRenderTargetsInfo Info(MRTCount, RenderTargets, DepthView);
if (bClearDepth)
{
bSceneDepthCleared = true;
}
if (bBindQuadOverdrawBuffers && AllowDebugViewPS(DVSM_QuadComplexity, GetFeatureLevelShaderPlatform(CurrentFeatureLevel)))
{
if (QuadOverdrawBuffer.IsValid() && QuadOverdrawBuffer->GetRenderTargetItem().UAV.IsValid())
{
QuadOverdrawIndex = 7; // As defined in QuadOverdraw.usf
// Increase the rendertarget count in order to control the bound slot of the UAV.
check(Info.NumColorRenderTargets <= QuadOverdrawIndex);
Info.NumColorRenderTargets = QuadOverdrawIndex;
Info.UnorderedAccessView[Info.NumUAVs++] = QuadOverdrawBuffer->GetRenderTargetItem().UAV;
// Clear to default value
const uint32 ClearValue[4] = { 0, 0, 0, 0 };
RHICmdList.ClearUAV(QuadOverdrawBuffer->GetRenderTargetItem().UAV, ClearValue);
RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToGfx, QuadOverdrawBuffer->GetRenderTargetItem().UAV);
}
}
// set the render target
RHICmdList.SetRenderTargetsAndClear(Info);
if (bShaderClear)
{
FLinearColor ClearColors[MaxSimultaneousRenderTargets];
ClearColors[0] = ClearColor;
for (int32 i = 1; i < MRTCount; ++i)
{
ClearColors[i] = RenderTargets[i].Texture->GetClearColor();
}
//depth/stencil should have been handled by the fast clear. only color for RT0 can get changed.
RHICmdList.ClearMRT(true, MRTCount, ClearColors, false, 0.0f, false, 0, FIntRect());
}
//bind any clear data that won't be bound automatically by the preceding SetRenderTargetsAndClear
bool bBindClearColor = !bClearColor && bGBuffersFastCleared;
bool bBindClearDepth = !bClearDepth && bSceneDepthCleared;
RHICmdList.BindClearMRTValues(bBindClearColor, bBindClearDepth, bBindClearDepth);
}
}
void FSceneRenderTargets::FinishRenderingGBuffer(FRHICommandListImmediate& RHICmdList)
{
if (IsAnyForwardShadingEnabled(GetFeatureLevelShaderPlatform(CurrentFeatureLevel)))
{
// in this non-standard case, just render to scene color with default mode
FinishRenderingSceneColor(RHICmdList, true);
return;
}
int32 VelocityRTIndex;
FRHIRenderTargetView RenderTargets[MaxSimultaneousRenderTargets];
int32 NumMRTs = GetGBufferRenderTargets(ERenderTargetLoadAction::ELoad, RenderTargets, VelocityRTIndex);
FResolveParams ResolveParams;
for (int32 i = 0; i < NumMRTs; ++i)
{
// When the basepass outputs to the velocity buffer, don't resolve it yet if selective outputs are enabled, as it will be resolved after the velocity pass.
if (i != VelocityRTIndex || !UseSelectiveBasePassOutputs())
{
RHICmdList.CopyToResolveTarget(RenderTargets[i].Texture, RenderTargets[i].Texture, true, ResolveParams);
}
}
FTextureRHIParamRef DepthSurface = GetSceneDepthSurface();
RHICmdList.CopyToResolveTarget(DepthSurface, DepthSurface, true, ResolveParams);
QuadOverdrawIndex = INDEX_NONE;
}
int32 FSceneRenderTargets::GetNumGBufferTargets() const
{
int32 NumGBufferTargets = 1;
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4 && !IsAnyForwardShadingEnabled(GetFeatureLevelShaderPlatform(CurrentFeatureLevel)))
{
// This needs to match TBasePassPixelShaderBaseType::ModifyCompilationEnvironment()
NumGBufferTargets = bAllowStaticLighting ? 6 : 5;
if (bAllocateVelocityGBuffer)
{
++NumGBufferTargets;
}
}
return NumGBufferTargets;
}
void FSceneRenderTargets::AllocSceneColor(FRHICommandList& RHICmdList)
{
if (GetSceneColorForCurrentShadingPath())
{
// no work needed
return;
}
// create SceneColor on demand so it can be shared with other pooled RT
EPixelFormat SceneColorBufferFormat = GetSceneColorFormat();
// Create the scene color.
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SceneColorBufferFormat, FClearValueBinding::Black, TexCreate_None, TexCreate_RenderTargetable, false));
Desc.Flags |= TexCreate_FastVRAM;
int32 OptimizeForUAVPerformance = CVarOptimizeForUAVPerformance.GetValueOnRenderThread();
// with TexCreate_UAV it would allow better sharing with later elements but it might come at a high cost:
// GCNPerformanceTweets.pdf Tip 37: Warning: Causes additional synchronization between draw calls when using a render target allocated with this flag, use sparingly
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM5 && !OptimizeForUAVPerformance)
{
Desc.TargetableFlags |= TexCreate_UAV;
}
if (CurrentFeatureLevel < ERHIFeatureLevel::SM4)
{
Desc.NumSamples = GetNumSceneColorMSAASamples(CurrentFeatureLevel);
}
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GetSceneColorForCurrentShadingPath(), GetSceneColorTargetName(CurrentShadingPath));
}
// otherwise we have a severe problem
check(GetSceneColorForCurrentShadingPath());
}
void FSceneRenderTargets::AllocLightAttenuation(FRHICommandList& RHICmdList)
{
if(LightAttenuation)
{
// no work needed
return;
}
check(IsInRenderingThread());
// create LightAttenuation on demand so it can be shared with other pooled RT
// Create a texture to store the resolved light attenuation values, and a render-targetable surface to hold the unresolved light attenuation values.
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding::White, TexCreate_None, TexCreate_RenderTargetable, false));
Desc.Flags |= TexCreate_FastVRAM;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, LightAttenuation, TEXT("LightAttenuation"));
// the channel assignment is documented in ShadowRendering.cpp (look for Light Attenuation channel assignment)
}
// otherwise we have a severe problem
check(LightAttenuation);
}
TRefCountPtr<IPooledRenderTarget>& FSceneRenderTargets::GetReflectionBrightnessTarget()
{
bool bSupportsR32Float = CurrentFeatureLevel > ERHIFeatureLevel::ES2;
int32 ReflectionBrightnessIndex = bSupportsR32Float ? 0 : 1;
return ReflectionBrightness[ReflectionBrightnessIndex];
}
void FSceneRenderTargets::ReleaseGBufferTargets()
{
GBufferResourcesUniformBuffer.SafeRelease();
GBufferA.SafeRelease();
GBufferB.SafeRelease();
GBufferC.SafeRelease();
GBufferD.SafeRelease();
GBufferE.SafeRelease();
GBufferVelocity.SafeRelease();
}
void FSceneRenderTargets::PreallocGBufferTargets(bool bShouldRenderVelocities)
{
if (GBasePassOutputsVelocityDebug == 1)
{
bAllocateVelocityGBuffer = false;
}
else
{
bAllocateVelocityGBuffer = bShouldRenderVelocities && FVelocityRendering::OutputsToGBuffer();
}
}
void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList)
{
// AdjustGBufferRefCount +1 doesn't match -1 (within the same frame)
ensure(GBufferRefCount == 0);
if (GBufferA)
{
// no work needed
return;
}
// create GBuffer on demand so it can be shared with other pooled RT
// good to see the quality loss due to precision in the gbuffer
const bool bHighPrecisionGBuffers = (CurrentGBufferFormat >= EGBufferFormat::Force16BitsPerChannel);
// good to profile the impact of non 8 bit formats
const bool bEnforce8BitPerChannel = (CurrentGBufferFormat == EGBufferFormat::Force8BitsPerChannel);
// Create the world-space normal g-buffer.
{
EPixelFormat NormalGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_A2B10G10R10;
if(bEnforce8BitPerChannel)
{
NormalGBufferFormat = PF_B8G8R8A8;
}
else if (CurrentGBufferFormat == EGBufferFormat::HighPrecisionNormals)
{
NormalGBufferFormat = PF_FloatRGBA;
}
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, NormalGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferA, TEXT("GBufferA"));
}
// Create the specular color and power g-buffer.
{
const EPixelFormat SpecularGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8;
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SpecularGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferB, TEXT("GBufferB"));
}
// Create the diffuse color g-buffer.
{
const EPixelFormat DiffuseGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8;
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, DiffuseGBufferFormat, FClearValueBinding::Transparent, TexCreate_SRGB, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferC, TEXT("GBufferC"));
}
// Create the mask g-buffer (e.g. SSAO, subsurface scattering, wet surface mask, skylight mask, ...).
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(0, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferD, TEXT("GBufferD"));
}
if (bAllowStaticLighting)
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(1, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferE, TEXT("GBufferE"));
}
GBasePassOutputsVelocityDebug = CVarBasePassOutputsVelocityDebug.GetValueOnRenderThread();
if (bAllocateVelocityGBuffer)
{
FPooledRenderTargetDesc VelocityRTDesc = FVelocityRendering::GetRenderTargetDesc();
GRenderTargetPool.FindFreeElement(RHICmdList, VelocityRTDesc, GBufferVelocity, TEXT("GBufferVelocity"));
}
// otherwise we have a severe problem
check(GBufferA);
// Create the required render targets if running Highend.
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4)
{
// Allocate the Gbuffer resource uniform buffer.
const FSceneRenderTargetItem& GBufferAToUse = GBufferA ? GBufferA->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
const FSceneRenderTargetItem& GBufferBToUse = GBufferB ? GBufferB->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
const FSceneRenderTargetItem& GBufferCToUse = GBufferC ? GBufferC->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
const FSceneRenderTargetItem& GBufferDToUse = GBufferD ? GBufferD->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
const FSceneRenderTargetItem& GBufferEToUse = GBufferE ? GBufferE->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
const FSceneRenderTargetItem& GBufferVelocityToUse = GBufferVelocity ? GBufferVelocity->GetRenderTargetItem() : GSystemTextures.BlackDummy->GetRenderTargetItem();
FGBufferResourceStruct GBufferResourceStruct;
GBufferResourceStruct.GBufferATexture = GBufferAToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferBTexture = GBufferBToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferCTexture = GBufferCToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferDTexture = GBufferDToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferETexture = GBufferEToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferVelocityTexture = GBufferVelocityToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferATextureNonMS = GBufferAToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferBTextureNonMS = GBufferBToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferCTextureNonMS = GBufferCToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferDTextureNonMS = GBufferDToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferETextureNonMS = GBufferEToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferVelocityTextureNonMS = GBufferVelocityToUse.ShaderResourceTexture;
GBufferResourceStruct.GBufferATextureMS = GBufferAToUse.TargetableTexture;
GBufferResourceStruct.GBufferBTextureMS = GBufferBToUse.TargetableTexture;
GBufferResourceStruct.GBufferCTextureMS = GBufferCToUse.TargetableTexture;
GBufferResourceStruct.GBufferDTextureMS = GBufferDToUse.TargetableTexture;
GBufferResourceStruct.GBufferETextureMS = GBufferEToUse.TargetableTexture;
GBufferResourceStruct.GBufferVelocityTextureMS = GBufferVelocityToUse.TargetableTexture;
GBufferResourceStruct.GBufferATextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourceStruct.GBufferBTextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourceStruct.GBufferCTextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourceStruct.GBufferDTextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourceStruct.GBufferETextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourceStruct.GBufferVelocityTextureSampler = TStaticSamplerState<>::GetRHI();
GBufferResourcesUniformBuffer = FGBufferResourceStruct::CreateUniformBuffer(GBufferResourceStruct, UniformBuffer_SingleFrame);
}
// so that
GBufferRefCount = 1;
}
const TRefCountPtr<IPooledRenderTarget>& FSceneRenderTargets::GetSceneColor() const
{
if (!GetSceneColorForCurrentShadingPath())
{
// to avoid log/ensure spam
static bool bFirst = true;
if(bFirst)
{
bFirst = false;
// the first called should be AllocSceneColor(), contact MartinM if that happens
ensure(GetSceneColorForCurrentShadingPath());
}
return GSystemTextures.BlackDummy;
}
return GetSceneColorForCurrentShadingPath();
}
bool FSceneRenderTargets::IsSceneColorAllocated() const
{
return GetSceneColorForCurrentShadingPath() != 0;
}
TRefCountPtr<IPooledRenderTarget>& FSceneRenderTargets::GetSceneColor()
{
if (!GetSceneColorForCurrentShadingPath())
{
// to avoid log/ensure spam
static bool bFirst = true;
if(bFirst)
{
bFirst = false;
// the first called should be AllocSceneColor(), contact MartinM if that happens
ensure(GetSceneColorForCurrentShadingPath());
}
return GSystemTextures.BlackDummy;
}
return GetSceneColorForCurrentShadingPath();
}
void FSceneRenderTargets::SetSceneColor(IPooledRenderTarget* In)
{
check(CurrentShadingPath < EShadingPath::Num);
SceneColor[(int32)CurrentShadingPath] = In;
}
void FSceneRenderTargets::SetLightAttenuation(IPooledRenderTarget* In)
{
LightAttenuation = In;
}
const TRefCountPtr<IPooledRenderTarget>& FSceneRenderTargets::GetLightAttenuation() const
{
if(!LightAttenuation)
{
// to avoid log/ensure spam
static bool bFirst = true;
if(bFirst)
{
bFirst = false;
// First we need to call AllocLightAttenuation()
ensure(LightAttenuation);
}
return GSystemTextures.WhiteDummy;
}
return LightAttenuation;
}
TRefCountPtr<IPooledRenderTarget>& FSceneRenderTargets::GetLightAttenuation()
{
if(!LightAttenuation)
{
// to avoid log/ensure spam
static bool bFirst = true;
if(bFirst)
{
bFirst = false;
// the first called should be AllocLightAttenuation()
ensure(LightAttenuation);
}
return GSystemTextures.WhiteDummy;
}
return LightAttenuation;
}
void FSceneRenderTargets::AdjustGBufferRefCount(FRHICommandList& RHICmdList, int Delta)
{
if(Delta > 0 && GBufferRefCount == 0)
{
AllocGBufferTargets(RHICmdList);
}
else
{
GBufferRefCount += Delta;
if (GBufferRefCount == 0)
{
ReleaseGBufferTargets();
}
}
}
void FSceneRenderTargets::FinishRenderingSceneColor(FRHICommandListImmediate& RHICmdList, bool bKeepChanges, const FResolveRect& ResolveRect)
{
SCOPED_DRAW_EVENT(RHICmdList, FinishRenderingSceneColor);
if(bKeepChanges)
{
ResolveSceneColor(RHICmdList);
}
}
bool FSceneRenderTargets::BeginRenderingCustomDepth(FRHICommandListImmediate& RHICmdList, bool bPrimitives)
{
IPooledRenderTarget* CustomDepthRenderTarget = RequestCustomDepth(RHICmdList, bPrimitives);
if(CustomDepthRenderTarget)
{
SCOPED_DRAW_EVENT(RHICmdList, BeginRenderingCustomDepth);
FRHIDepthRenderTargetView DepthView(CustomDepthRenderTarget->GetRenderTargetItem().ShaderResourceTexture);
FRHISetRenderTargetsInfo Info(0, nullptr, DepthView);
Info.bClearStencil = IsCustomDepthPassWritingStencil();
check(DepthView.Texture->GetStencilClearValue() == 0);
RHICmdList.SetRenderTargetsAndClear(Info);
return true;
}
return false;
}
void FSceneRenderTargets::FinishRenderingCustomDepth(FRHICommandListImmediate& RHICmdList, const FResolveRect& ResolveRect)
{
SCOPED_DRAW_EVENT(RHICmdList, FinishRenderingCustomDepth);
RHICmdList.CopyToResolveTarget(CustomDepth->GetRenderTargetItem().TargetableTexture, CustomDepth->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
bCustomDepthIsValid = true;
}
/**
* Saves a previously rendered scene color target
*/
void FSceneRenderTargets::ResolveSceneColor(FRHICommandList& RHICmdList, const FResolveRect& ResolveRect)
{
SCOPED_DRAW_EVENT(RHICmdList, ResolveSceneColor);
auto& CurrentSceneColor = GetSceneColor();
uint32 samples = CurrentSceneColor->GetDesc().NumSamples;
const EShaderPlatform CurrentShaderPlatform = GShaderPlatformForFeatureLevel[CurrentFeatureLevel];
if (samples <= 1 || CurrentShaderPlatform == SP_METAL || IsVulkanMobilePlatform(CurrentShaderPlatform))
{
RHICmdList.CopyToResolveTarget(GetSceneColorSurface(), GetSceneColorTexture(), true, FResolveParams(ResolveRect));
}
else
{
// Custom shader based color resolve for HDR color to emulate mobile.
SetRenderTarget(RHICmdList, GetSceneColorTexture(), FTextureRHIParamRef());
if(ResolveRect.IsValid())
{
RHICmdList.SetScissorRect(true, ResolveRect.X1, ResolveRect.Y1, ResolveRect.X2, ResolveRect.Y2);
}
else
{
RHICmdList.SetScissorRect(false, 0, 0, 0, 0);
}
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
auto ShaderMap = GetGlobalShaderMap(CurrentFeatureLevel);
TShaderMapRef<FHdrCustomResolveVS> VertexShader(ShaderMap);
if(samples == 2)
{
TShaderMapRef<FHdrCustomResolve2xPS> PixelShader(ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, CurrentFeatureLevel, BoundShaderState, GetVertexDeclarationFVector4(), *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, CurrentSceneColor->GetRenderTargetItem().TargetableTexture);
RHICmdList.DrawPrimitive(PT_TriangleList, 0, 1, 1);
}
else if(samples == 4)
{
TShaderMapRef<FHdrCustomResolve4xPS> PixelShader(ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, CurrentFeatureLevel, BoundShaderState, GetVertexDeclarationFVector4(), *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, CurrentSceneColor->GetRenderTargetItem().TargetableTexture);
RHICmdList.DrawPrimitive(PT_TriangleList, 0, 1, 1);
}
else if(samples == 8)
{
TShaderMapRef<FHdrCustomResolve8xPS> PixelShader(ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, CurrentFeatureLevel, BoundShaderState, GetVertexDeclarationFVector4(), *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, CurrentSceneColor->GetRenderTargetItem().TargetableTexture);
RHICmdList.DrawPrimitive(PT_TriangleList, 0, 1, 1);
}
else
{
// Everything other than 2,4,8 samples is not implemented.
check(0);
}
}
}
/** Resolves the GBuffer targets so that their resolved textures can be sampled. */
void FSceneRenderTargets::ResolveGBufferSurfaces(FRHICommandList& RHICmdList, const FResolveRect& ResolveRect)
{
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4)
{
SCOPED_DRAW_EVENT(RHICmdList, ResolveGBufferSurfaces);
RHICmdList.CopyToResolveTarget(GBufferA->GetRenderTargetItem().TargetableTexture, GBufferA->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
RHICmdList.CopyToResolveTarget(GBufferB->GetRenderTargetItem().TargetableTexture, GBufferB->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
RHICmdList.CopyToResolveTarget(GBufferC->GetRenderTargetItem().TargetableTexture, GBufferC->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
RHICmdList.CopyToResolveTarget(GBufferD->GetRenderTargetItem().TargetableTexture, GBufferD->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
if (bAllowStaticLighting)
{
RHICmdList.CopyToResolveTarget(GBufferE->GetRenderTargetItem().TargetableTexture, GBufferE->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
}
if (bAllocateVelocityGBuffer)
{
RHICmdList.CopyToResolveTarget(GBufferVelocity->GetRenderTargetItem().TargetableTexture, GBufferVelocity->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams(ResolveRect));
}
}
}
void FSceneRenderTargets::BeginRenderingPrePass(FRHICommandList& RHICmdList, bool bPerformClear)
{
SCOPED_DRAW_EVENT(RHICmdList, BeginRenderingPrePass);
FTextureRHIRef ColorTarget;
FTexture2DRHIRef DepthTarget = GetSceneDepthSurface();
if (bPerformClear)
{
FRHIRenderTargetView ColorView(ColorTarget, 0, -1, ERenderTargetLoadAction::ENoAction, ERenderTargetStoreAction::ENoAction);
FRHIDepthRenderTargetView DepthView(DepthTarget, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore);
// Clear the depth buffer.
// Note, this is a reversed Z depth surface, so 0.0f is the far plane.
FRHISetRenderTargetsInfo Info(1, &ColorView, DepthView);
RHICmdList.SetRenderTargetsAndClear(Info);
bSceneDepthCleared = true;
}
else
{
// Set the scene depth surface and a DUMMY buffer as color buffer
// (as long as it's the same dimension as the depth buffer),
FRHIRenderTargetView ColorView(ColorTarget, 0, -1, ERenderTargetLoadAction::ENoAction, ERenderTargetStoreAction::ENoAction);
FRHIDepthRenderTargetView DepthRTV(DepthTarget, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::EStore);
RHICmdList.SetRenderTargets(1, &ColorView, &DepthRTV, 0, NULL);
RHICmdList.BindClearMRTValues(false, true, true);
}
}
void FSceneRenderTargets::FinishRenderingPrePass(FRHICommandListImmediate& RHICmdList)
{
SCOPED_DRAW_EVENT(RHICmdList, FinishRenderingPrePass);
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneDepthZ);
}
void FSceneRenderTargets::BeginRenderingSceneAlphaCopy(FRHICommandListImmediate& RHICmdList)
{
SCOPED_DRAW_EVENT(RHICmdList, BeginRenderingSceneAlphaCopy);
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneAlphaCopy);
SetRenderTarget(RHICmdList, GetSceneAlphaCopySurface(), 0);
}
void FSceneRenderTargets::FinishRenderingSceneAlphaCopy(FRHICommandListImmediate& RHICmdList)
{
SCOPED_DRAW_EVENT(RHICmdList, FinishRenderingSceneAlphaCopy);
RHICmdList.CopyToResolveTarget(GetSceneAlphaCopySurface(), SceneAlphaCopy->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams(FResolveRect()));
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneAlphaCopy);
}
void FSceneRenderTargets::BeginRenderingLightAttenuation(FRHICommandList& RHICmdList, bool bClearToWhite)
{
SCOPED_CONDITIONAL_DRAW_EVENT(RHICmdList, ClearLightAttenuation, bClearToWhite);
SCOPED_CONDITIONAL_DRAW_EVENT(RHICmdList, BeginRenderingLightAttenuation, !bClearToWhite);
AllocLightAttenuation(RHICmdList);
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, GetLightAttenuation());
// Set the light attenuation surface as the render target, and the scene depth buffer as the depth-stencil surface.
SetRenderTarget(RHICmdList, GetLightAttenuationSurface(), GetSceneDepthSurface(), bClearToWhite ? ESimpleRenderTargetMode::EClearColorExistingDepth : ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true);
}
void FSceneRenderTargets::FinishRenderingLightAttenuation(FRHICommandList& RHICmdList)
{
SCOPED_DRAW_EVENT(RHICmdList, FinishRenderingLightAttenuation);
// Resolve the light attenuation surface.
RHICmdList.CopyToResolveTarget(GetLightAttenuationSurface(), LightAttenuation->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams(FResolveRect()));
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, GetLightAttenuation());
}
void FSceneRenderTargets::BeginRenderingTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bFirstTimeThisFrame)
{
// Use the scene color buffer.
BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite);
if (bFirstTimeThisFrame)
{
// Clear the stencil buffer for ResponsiveAA
RHICmdList.Clear(false, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect());
}
// viewport to match view size
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
}
void FSceneRenderTargets::FinishRenderingTranslucency(FRHICommandListImmediate& RHICmdList, const class FViewInfo& View)
{
FinishRenderingSceneColor(RHICmdList, true);
}
bool FSceneRenderTargets::BeginRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bFirstTimeThisFrame)
{
bSeparateTranslucencyPass = true;
if(IsSeparateTranslucencyActive(View))
{
FIntPoint ScaledSize;
float Scale = 1.0f;
GetSeparateTranslucencyDimensions(ScaledSize, Scale);
SCOPED_DRAW_EVENT(RHICmdList, BeginSeparateTranslucency);
TRefCountPtr<IPooledRenderTarget>* SeparateTranslucency;
if (bSnapshot)
{
check(SeparateTranslucencyRT.GetReference());
SeparateTranslucency = &SeparateTranslucencyRT;
}
else
{
SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, ScaledSize);
}
const FTexture2DRHIRef &SeparateTranslucencyDepth = Scale < 1.0f ? (const FTexture2DRHIRef&)GetSeparateTranslucencyDepth(RHICmdList, GetBufferSizeXY())->GetRenderTargetItem().TargetableTexture : GetSceneDepthSurface();
check((*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture->GetClearColor() == FLinearColor::Black);
// clear the render target the first time, re-use afterwards
SetRenderTarget(RHICmdList, (*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture, SeparateTranslucencyDepth,
bFirstTimeThisFrame ? ESimpleRenderTargetMode::EClearColorExistingDepth : ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite);
if (!bFirstTimeThisFrame)
{
// Clear the stencil buffer for ResponsiveAA
RHICmdList.BindClearMRTValues(true, false, true);
}
RHICmdList.SetViewport(View.ViewRect.Min.X * Scale, View.ViewRect.Min.Y * Scale, 0.0f, View.ViewRect.Max.X * Scale, View.ViewRect.Max.Y * Scale, 1.0f);
return true;
}
return false;
}
void FSceneRenderTargets::FinishRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View)
{
if(IsSeparateTranslucencyActive(View))
{
SCOPED_DRAW_EVENT(RHICmdList, FinishSeparateTranslucency);
TRefCountPtr<IPooledRenderTarget>* SeparateTranslucency;
TRefCountPtr<IPooledRenderTarget>* SeparateTranslucencyDepth;
if (bSnapshot)
{
check(SeparateTranslucencyRT.GetReference());
SeparateTranslucency = &SeparateTranslucencyRT;
SeparateTranslucencyDepth = &SeparateTranslucencyDepthRT;
}
else
{
FIntPoint ScaledSize;
float Scale = 1.0f;
GetSeparateTranslucencyDimensions(ScaledSize, Scale);
SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, ScaledSize);
SeparateTranslucencyDepth = &GetSeparateTranslucencyDepth(RHICmdList, GetBufferSizeXY());
}
RHICmdList.CopyToResolveTarget((*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucency)->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
RHICmdList.CopyToResolveTarget((*SeparateTranslucencyDepth)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucencyDepth)->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
}
bSeparateTranslucencyPass = false;
}
void FSceneRenderTargets::ResolveSceneDepthTexture(FRHICommandList& RHICmdList)
{
SCOPED_DRAW_EVENT(RHICmdList, ResolveSceneDepthTexture);
RHICmdList.CopyToResolveTarget(GetSceneDepthSurface(), GetSceneDepthTexture(), true, FResolveParams());
}
void FSceneRenderTargets::ResolveSceneDepthToAuxiliaryTexture(FRHICommandList& RHICmdList)
{
// Resolve the scene depth to an auxiliary texture when SM3/SM4 is in use. This needs to happen so the auxiliary texture can be bound as a shader parameter
// while the primary scene depth texture can be bound as the target. Simultaneously binding a single DepthStencil resource as a parameter and target
// is unsupported in d3d feature level 10.
if(!GSupportsDepthFetchDuringDepthTest)
{
SCOPED_DRAW_EVENT(RHICmdList, ResolveSceneDepthToAuxiliaryTexture);
RHICmdList.CopyToResolveTarget(GetSceneDepthSurface(), GetAuxiliarySceneDepthTexture(), true, FResolveParams());
}
}
void FSceneRenderTargets::CleanUpEditorPrimitiveTargets()
{
EditorPrimitivesDepth.SafeRelease();
EditorPrimitivesColor.SafeRelease();
}
int32 FSceneRenderTargets::GetEditorMSAACompositingSampleCount() const
{
int32 Value = 1;
// only supported on SM5 yet (SM4 doesn't have MSAA sample load functionality which makes it harder to implement)
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM5 && GRHISupportsMSAADepthSampleAccess)
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MSAA.CompositingSampleCount"));
Value = CVar->GetValueOnRenderThread();
if(Value <= 1)
{
Value = 1;
}
else if(Value <= 2)
{
Value = 2;
}
else if(Value <= 4)
{
Value = 4;
}
else
{
Value = 8;
}
}
return Value;
}
const FTexture2DRHIRef& FSceneRenderTargets::GetEditorPrimitivesColor(FRHICommandList& RHICmdList)
{
const bool bIsValid = IsValidRef(EditorPrimitivesColor);
if( !bIsValid || EditorPrimitivesColor->GetDesc().NumSamples != GetEditorMSAACompositingSampleCount() )
{
// If the target is does not match the MSAA settings it needs to be recreated
InitEditorPrimitivesColor(RHICmdList);
}
return (const FTexture2DRHIRef&)EditorPrimitivesColor->GetRenderTargetItem().TargetableTexture;
}
const FTexture2DRHIRef& FSceneRenderTargets::GetEditorPrimitivesDepth(FRHICommandList& RHICmdList)
{
const bool bIsValid = IsValidRef(EditorPrimitivesDepth);
if (!bIsValid || (CurrentFeatureLevel >= ERHIFeatureLevel::SM5 && EditorPrimitivesDepth->GetDesc().NumSamples != GetEditorMSAACompositingSampleCount()) )
{
// If the target is does not match the MSAA settings it needs to be recreated
InitEditorPrimitivesDepth(RHICmdList);
}
return (const FTexture2DRHIRef&)EditorPrimitivesDepth->GetRenderTargetItem().TargetableTexture;
}
TAutoConsoleVariable<int32> FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled(
TEXT("r.SeparateTranslucency"),
1,
TEXT("Allows to disable the separate translucency feature (all translucency is rendered in separate RT and composited\n")
TEXT("after DOF, if not specified otherwise in the material).\n")
TEXT(" 0: off (translucency is affected by depth of field)\n")
TEXT(" 1: on costs GPU performance and memory but keeps translucency unaffected by Depth of Field. (default)"),
ECVF_RenderThreadSafe);
bool FSceneRenderTargets::IsSeparateTranslucencyActive(const FViewInfo& View) const
{
int32 Value = FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled.GetValueOnRenderThread();
return (Value != 0) && CurrentFeatureLevel >= ERHIFeatureLevel::SM4
&& (View.Family->EngineShowFlags.PostProcessing || View.Family->EngineShowFlags.ShaderComplexity)
&& View.Family->EngineShowFlags.SeparateTranslucency;
}
void FSceneRenderTargets::InitEditorPrimitivesColor(FRHICommandList& RHICmdList)
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize,
PF_B8G8R8A8,
FClearValueBinding::Transparent,
TexCreate_None,
TexCreate_ShaderResource | TexCreate_RenderTargetable,
false));
Desc.NumSamples = GetEditorMSAACompositingSampleCount();
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, EditorPrimitivesColor, TEXT("EditorPrimitivesColor"));
}
void FSceneRenderTargets::InitEditorPrimitivesDepth(FRHICommandList& RHICmdList)
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize,
PF_DepthStencil,
FClearValueBinding::DepthFar,
TexCreate_None,
TexCreate_ShaderResource | TexCreate_DepthStencilTargetable,
false));
Desc.NumSamples = GetEditorMSAACompositingSampleCount();
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, EditorPrimitivesDepth, TEXT("EditorPrimitivesDepth"));
}
void FSceneRenderTargets::QuantizeBufferSize(int32& InOutBufferSizeX, int32& InOutBufferSizeY)
{
// ensure sizes are dividable by DividableBy to get post processing effects with lower resolution working well
const uint32 DividableBy = 4;
const uint32 Mask = ~(DividableBy - 1);
InOutBufferSizeX = (InOutBufferSizeX + DividableBy - 1) & Mask;
InOutBufferSizeY = (InOutBufferSizeY + DividableBy - 1) & Mask;
}
void FSceneRenderTargets::SetBufferSize(int32 InBufferSizeX, int32 InBufferSizeY)
{
QuantizeBufferSize(InBufferSizeX, InBufferSizeY);
BufferSize.X = InBufferSizeX;
BufferSize.Y = InBufferSizeY;
}
void FSceneRenderTargets::SetSeparateTranslucencyBufferSize(bool bAnyViewWantsDownsampledSeparateTranslucency)
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.SeparateTranslucencyScreenPercentage"));
const float CVarScale = FMath::Clamp(CVar->GetValueOnRenderThread() / 100.0f, 0.0f, 100.0f);
float EffectiveScale = CVarScale;
// 'r.SeparateTranslucencyScreenPercentage' CVar wins over automatic downsampling
if (FMath::Abs(CVarScale - 1.0f) < .001f && bAnyViewWantsDownsampledSeparateTranslucency)
{
EffectiveScale = .5f;
}
int32 ScaledX = GetBufferSizeXY().X * EffectiveScale;
int32 ScaledY = GetBufferSizeXY().Y * EffectiveScale;
SeparateTranslucencyBufferSize = FIntPoint(FMath::Max(ScaledX, 1), FMath::Max(ScaledY, 1));
SeparateTranslucencyScale = EffectiveScale;
}
void FSceneRenderTargets::AllocateMobileRenderTargets(FRHICommandList& RHICmdList)
{
// on ES2 we don't do on demand allocation of SceneColor yet (in non ES2 it's released in the Tonemapper Process())
AllocSceneColor(RHICmdList);
AllocateCommonDepthTargets(RHICmdList);
AllocateDebugViewModeTargets(RHICmdList);
EPixelFormat Format = GetSceneColor()->GetDesc().Format;
#if PLATFORM_HTML5
// For 64-bit ES2 without framebuffer fetch, create extra render target for copy of alpha channel.
if((Format == PF_FloatRGBA) && (GSupportsShaderFramebufferFetch == false))
{
// creating a PF_R16F (a true one-channel renderable fp texture) is only supported on GL if EXT_texture_rg is available. It's present
// on iOS, but not in WebGL or Android.
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneAlphaCopy, TEXT("SceneAlphaCopy"));
}
else
#endif
{
SceneAlphaCopy = GSystemTextures.MaxFP16Depth;
}
}
// for easier use of "VisualizeTexture"
static TCHAR* const GetVolumeName(uint32 Id, bool bDirectional)
{
// (TCHAR*) for non VisualStudio
switch(Id)
{
case 0: return bDirectional ? (TCHAR*)TEXT("TranslucentVolumeDir0") : (TCHAR*)TEXT("TranslucentVolume0");
case 1: return bDirectional ? (TCHAR*)TEXT("TranslucentVolumeDir1") : (TCHAR*)TEXT("TranslucentVolume1");
case 2: return bDirectional ? (TCHAR*)TEXT("TranslucentVolumeDir2") : (TCHAR*)TEXT("TranslucentVolume2");
default:
check(0);
}
return (TCHAR*)TEXT("InvalidName");
}
void FSceneRenderTargets::AllocateReflectionTargets(FRHICommandList& RHICmdList, int32 TargetSize)
{
if (GSupportsRenderTargetFormat_PF_FloatRGBA)
{
const int32 NumReflectionCaptureMips = FMath::CeilLogTwo(TargetSize) + 1;
if (ReflectionColorScratchCubemap[0] && ReflectionColorScratchCubemap[0]->GetRenderTargetItem().TargetableTexture->GetNumMips() != NumReflectionCaptureMips)
{
ReflectionColorScratchCubemap[0].SafeRelease();
ReflectionColorScratchCubemap[1].SafeRelease();
}
// Reflection targets are shared between both mobile and deferred shading paths. If we have already allocated for one and are now allocating for the other,
// we can skip these targets.
bool bSharedReflectionTargetsAllocated = ReflectionColorScratchCubemap[0] != nullptr;
if (!bSharedReflectionTargetsAllocated)
{
// We write to these cubemap faces individually during filtering
uint32 CubeTexFlags = TexCreate_TargetArraySlicesIndependently;
{
// Create scratch cubemaps for filtering passes
FPooledRenderTargetDesc Desc2(FPooledRenderTargetDesc::CreateCubemapDesc(TargetSize, PF_FloatRGBA, FClearValueBinding::None, CubeTexFlags, TexCreate_RenderTargetable, false, 1, NumReflectionCaptureMips));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc2, ReflectionColorScratchCubemap[0], TEXT("ReflectionColorScratchCubemap0"));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc2, ReflectionColorScratchCubemap[1], TEXT("ReflectionColorScratchCubemap1"));
}
extern int32 GDiffuseIrradianceCubemapSize;
const int32 NumDiffuseIrradianceMips = FMath::CeilLogTwo(GDiffuseIrradianceCubemapSize) + 1;
{
FPooledRenderTargetDesc Desc2(FPooledRenderTargetDesc::CreateCubemapDesc(GDiffuseIrradianceCubemapSize, PF_FloatRGBA, FClearValueBinding::None, CubeTexFlags, TexCreate_RenderTargetable, false, 1, NumDiffuseIrradianceMips));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc2, DiffuseIrradianceScratchCubemap[0], TEXT("DiffuseIrradianceScratchCubemap0"));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc2, DiffuseIrradianceScratchCubemap[1], TEXT("DiffuseIrradianceScratchCubemap1"));
}
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(FSHVector3::MaxSHBasis, 1), PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SkySHIrradianceMap, TEXT("SkySHIrradianceMap"));
}
}
auto& ReflectionBrightnessTarget = GetReflectionBrightnessTarget();
if (!ReflectionBrightnessTarget)
{
bool bSupportsR32Float = CurrentFeatureLevel > ERHIFeatureLevel::ES2;
//@todo: FScene::UpdateSkyCaptureContents() is called before FSceneRenderTargets::AllocateRenderTargets()
// so CurrentFeatureLevel == ERHIFeatureLevel::Num and that crashes OpenGL ES2 as R32F is not valid
if (CurrentFeatureLevel == ERHIFeatureLevel::Num)
{
bSupportsR32Float = GMaxRHIFeatureLevel > ERHIFeatureLevel::ES2;
}
int32 ReflectionBrightnessIndex = bSupportsR32Float ? 0 : 1;
EPixelFormat BrightnessFormat = bSupportsR32Float ? PF_R32_FLOAT : PF_FloatRGBA;
FPooledRenderTargetDesc Desc3(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), BrightnessFormat, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc3, ReflectionBrightnessTarget, GetReflectionBrightnessTargetName(ReflectionBrightnessIndex));
}
}
}
void FSceneRenderTargets::AllocateDebugViewModeTargets(FRHICommandList& RHICmdList)
{
// If the shader/quad complexity shader need a quad overdraw buffer to be bind, allocate it.
if (AllowDebugViewPS(DVSM_QuadComplexity, GetFeatureLevelShaderPlatform(CurrentFeatureLevel)))
{
FIntPoint QuadOverdrawSize;
QuadOverdrawSize.X = 2 * FMath::Max<uint32>((BufferSize.X + 1) / 2, 1); // The size is time 2 since left side is QuadDescriptor, and right side QuadComplexity.
QuadOverdrawSize.Y = FMath::Max<uint32>((BufferSize.Y + 1) / 2, 1);
FPooledRenderTargetDesc QuadOverdrawDesc = FPooledRenderTargetDesc::Create2DDesc(
QuadOverdrawSize,
PF_R32_UINT,
FClearValueBinding::None,
0,
TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_UAV,
false
);
GRenderTargetPool.FindFreeElement(RHICmdList, QuadOverdrawDesc, QuadOverdrawBuffer, TEXT("QuadOverdrawBuffer"));
}
}
void FSceneRenderTargets::AllocateCommonDepthTargets(FRHICommandList& RHICmdList)
{
if (!SceneDepthZ)
{
// Create a texture to store the resolved scene depth, and a render-targetable surface to hold the unresolved scene depth.
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_None, TexCreate_DepthStencilTargetable, false));
Desc.NumSamples = GetNumSceneColorMSAASamples(CurrentFeatureLevel);
Desc.Flags |= TexCreate_FastVRAM;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneDepthZ, TEXT("SceneDepthZ"));
SceneStencilSRV = RHICreateShaderResourceView((FTexture2DRHIRef&)SceneDepthZ->GetRenderTargetItem().TargetableTexture, 0, 1, PF_X24_G8);
// create non-MSAA version for hit proxies on PC
const EShaderPlatform CurrentShaderPlatform = GShaderPlatformForFeatureLevel[CurrentFeatureLevel];
if (Desc.NumSamples > 1 && CurrentShaderPlatform != SP_METAL && !IsVulkanMobilePlatform(CurrentShaderPlatform))
{
Desc.NumSamples = 1;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, NoMSAASceneDepthZ, TEXT("NoMSAASceneDepthZ"));
}
else
{
NoMSAASceneDepthZ = SceneDepthZ;
}
}
// When targeting DX Feature Level 10, create an auxiliary texture to store the resolved scene depth, and a render-targetable surface to hold the unresolved scene depth.
if (!AuxiliarySceneDepthZ && !GSupportsDepthFetchDuringDepthTest)
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_None, TexCreate_DepthStencilTargetable, false));
Desc.AutoWritable = false;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, AuxiliarySceneDepthZ, TEXT("AuxiliarySceneDepthZ"));
}
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GetPreShadowCacheTextureResolution(), PF_ShadowDepth, FClearValueBinding::None, TexCreate_None, TexCreate_DepthStencilTargetable, false));
Desc.AutoWritable = false;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, PreShadowCacheDepthZ, TEXT("PreShadowCacheDepthZ"));
// Mark the preshadow cache as newly allocated, so the cache will know to update
bPreshadowCacheNewlyAllocated = true;
}
if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
{
const FIntPoint ShadowBufferResolution = GetShadowDepthTextureResolution();
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(ShadowBufferResolution, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, OptionalShadowDepthColor, TEXT("OptionalShadowDepthColor"));
}
}
void FSceneRenderTargets::AllocateLightingChannelTexture(FRHICommandList& RHICmdList)
{
if (!LightingChannels)
{
// Only need 3 bits for lighting channels
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_R16_UINT, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, LightingChannels, TEXT("LightingChannels"));
}
}
void FSceneRenderTargets::AllocateDeferredShadingPathRenderTargets(FRHICommandList& RHICmdList)
{
AllocateCommonDepthTargets(RHICmdList);
// Create a quarter-sized version of the scene depth.
{
FIntPoint SmallDepthZSize(FMath::Max<uint32>(BufferSize.X / SmallColorDepthDownsampleFactor, 1), FMath::Max<uint32>(BufferSize.Y / SmallColorDepthDownsampleFactor, 1));
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(SmallDepthZSize, PF_DepthStencil, FClearValueBinding::None, TexCreate_None, TexCreate_DepthStencilTargetable, true));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SmallDepthZ, TEXT("SmallDepthZ"));
}
// Create the required render targets if running Highend.
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4)
{
// Create the screen space ambient occlusion buffer
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_G8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM5)
{
// UAV is only needed to support "r.AmbientOcclusion.Compute"
// todo: ideally this should be only UAV or RT, not both
Desc.TargetableFlags |= TexCreate_UAV;
}
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, ScreenSpaceAO, TEXT("ScreenSpaceAO"));
}
{
uint32 TranslucencyTargetFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable;
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM5)
{
TranslucencyTargetFlags |= TexCreate_UAV;
}
for (int32 RTSetIndex = 0; RTSetIndex < NumTranslucentVolumeRenderTargetSets; RTSetIndex++)
{
GRenderTargetPool.FindFreeElement(
RHICmdList,
FPooledRenderTargetDesc(FPooledRenderTargetDesc::CreateVolumeDesc(
GTranslucencyLightingVolumeDim,
GTranslucencyLightingVolumeDim,
GTranslucencyLightingVolumeDim,
PF_FloatRGBA,
FClearValueBinding::None,
0,
TranslucencyTargetFlags,
false,
1,
false)),
TranslucencyLightingVolumeAmbient[RTSetIndex],
GetVolumeName(RTSetIndex, false)
);
GRenderTargetPool.FindFreeElement(
RHICmdList,
FPooledRenderTargetDesc(FPooledRenderTargetDesc::CreateVolumeDesc(
GTranslucencyLightingVolumeDim,
GTranslucencyLightingVolumeDim,
GTranslucencyLightingVolumeDim,
PF_FloatRGBA,
FClearValueBinding::None,
0,
TranslucencyTargetFlags,
false,
1,
false)),
TranslucencyLightingVolumeDirectional[RTSetIndex],
GetVolumeName(RTSetIndex, true)
);
}
}
}
// LPV : Dynamic directional occlusion for diffuse and specular
if(UseLightPropagationVolumeRT(CurrentFeatureLevel))
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_R8G8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DirectionalOcclusion, TEXT("DirectionalOcclusion"));
}
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM4)
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_None, TexCreate_RenderTargetable, false));
if (CurrentFeatureLevel >= ERHIFeatureLevel::SM5)
{
Desc.TargetableFlags |= TexCreate_UAV;
}
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, LightAccumulation, TEXT("LightAccumulation"));
}
AllocateDebugViewModeTargets(RHICmdList);
if (bAllocateVelocityGBuffer)
{
FPooledRenderTargetDesc VelocityRTDesc = FVelocityRendering::GetRenderTargetDesc();
GRenderTargetPool.FindFreeElement(RHICmdList, VelocityRTDesc, GBufferVelocity, TEXT("GBufferVelocity"));
}
}
EPixelFormat FSceneRenderTargets::GetSceneColorFormat() const
{
EPixelFormat SceneColorBufferFormat = PF_FloatRGBA;
if (CurrentFeatureLevel < ERHIFeatureLevel::SM4)
{
// Potentially allocate an alpha channel in th -fe scene color texture to store the resolved scene depth.
SceneColorBufferFormat = GSupportsRenderTargetFormat_PF_FloatRGBA ? PF_FloatRGBA : PF_B8G8R8A8;
if (!IsMobileHDR() || IsMobileHDR32bpp())
{
SceneColorBufferFormat = PF_B8G8R8A8;
}
}
else
{
switch(CurrentSceneColorFormat)
{
case 0:
SceneColorBufferFormat = PF_R8G8B8A8; break;
case 1:
SceneColorBufferFormat = PF_A2B10G10R10; break;
case 2:
SceneColorBufferFormat = PF_FloatR11G11B10; break;
case 3:
SceneColorBufferFormat = PF_FloatRGB; break;
case 4:
// default
break;
case 5:
SceneColorBufferFormat = PF_A32B32G32R32F; break;
}
// Fallback in case the scene color selected isn't supported.
if (!GPixelFormats[SceneColorBufferFormat].Supported)
{
SceneColorBufferFormat = PF_FloatRGBA;
}
}
return SceneColorBufferFormat;
}
void FSceneRenderTargets::AllocateRenderTargets(FRHICommandList& RHICmdList)
{
if (BufferSize.X > 0 && BufferSize.Y > 0 && !AreShadingPathRenderTargetsAllocated(CurrentShadingPath))
{
if ((EShadingPath)CurrentShadingPath == EShadingPath::Mobile)
{
AllocateMobileRenderTargets(RHICmdList);
}
else
{
AllocateDeferredShadingPathRenderTargets(RHICmdList);
}
}
}
void FSceneRenderTargets::ReleaseSceneColor()
{
for (auto i = 0; i < (int32)EShadingPath::Num; ++i)
{
SceneColor[i].SafeRelease();
}
}
void FSceneRenderTargets::ReleaseAllTargets()
{
ReleaseGBufferTargets();
ReleaseSceneColor();
SceneAlphaCopy.SafeRelease();
SceneDepthZ.SafeRelease();
SceneStencilSRV.SafeRelease();
LightingChannels.SafeRelease();
NoMSAASceneDepthZ.SafeRelease();
AuxiliarySceneDepthZ.SafeRelease();
SmallDepthZ.SafeRelease();
DBufferA.SafeRelease();
DBufferB.SafeRelease();
DBufferC.SafeRelease();
ScreenSpaceAO.SafeRelease();
QuadOverdrawBuffer.SafeRelease();
LightAttenuation.SafeRelease();
LightAccumulation.SafeRelease();
DirectionalOcclusion.SafeRelease();
CustomDepth.SafeRelease();
CustomStencilSRV.SafeRelease();
OptionalShadowDepthColor.SafeRelease();
PreShadowCacheDepthZ.SafeRelease();
for (int32 i = 0; i < ARRAY_COUNT(ReflectionColorScratchCubemap); i++)
{
ReflectionColorScratchCubemap[i].SafeRelease();
}
ReflectionBrightness[0].SafeRelease();
ReflectionBrightness[1].SafeRelease();
for (int32 i = 0; i < ARRAY_COUNT(DiffuseIrradianceScratchCubemap); i++)
{
DiffuseIrradianceScratchCubemap[i].SafeRelease();
}
SkySHIrradianceMap.SafeRelease();
for (int32 RTSetIndex = 0; RTSetIndex < NumTranslucentVolumeRenderTargetSets; RTSetIndex++)
{
TranslucencyLightingVolumeAmbient[RTSetIndex].SafeRelease();
TranslucencyLightingVolumeDirectional[RTSetIndex].SafeRelease();
}
EditorPrimitivesColor.SafeRelease();
EditorPrimitivesDepth.SafeRelease();
}
void FSceneRenderTargets::ReleaseDynamicRHI()
{
ReleaseAllTargets();
GRenderTargetPool.FreeUnusedResources();
}
/** Returns the size of the shadow depth buffer, taking into account platform limitations and game specific resolution limits. */
FIntPoint FSceneRenderTargets::GetShadowDepthTextureResolution() const
{
int32 MaxShadowRes = CurrentMaxShadowResolution;
const FIntPoint ShadowBufferResolution(
FMath::Clamp(MaxShadowRes,1,GMaxShadowDepthBufferSizeX),
FMath::Clamp(MaxShadowRes,1,GMaxShadowDepthBufferSizeY));
return ShadowBufferResolution;
}
int32 FSceneRenderTargets::GetReflectiveShadowMapResolution() const
{
check(IsInRenderingThread());
return CurrentRSMResolution;
}
FIntPoint FSceneRenderTargets::GetPreShadowCacheTextureResolution() const
{
const FIntPoint ShadowDepthResolution = GetShadowDepthTextureResolution();
// Higher numbers increase cache hit rate but also memory usage
const int32 ExpandFactor = 2;
static auto CVarPreShadowResolutionFactor = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.Shadow.PreShadowResolutionFactor"));
float Factor = CVarPreShadowResolutionFactor->GetValueOnRenderThread();
FIntPoint Ret;
Ret.X = FMath::Clamp(FMath::TruncToInt(ShadowDepthResolution.X * Factor) * ExpandFactor, 1, GMaxShadowDepthBufferSizeX);
Ret.Y = FMath::Clamp(FMath::TruncToInt(ShadowDepthResolution.Y * Factor) * ExpandFactor, 1, GMaxShadowDepthBufferSizeY);
return Ret;
}
FIntPoint FSceneRenderTargets::GetTranslucentShadowDepthTextureResolution() const
{
FIntPoint ShadowDepthResolution = GetShadowDepthTextureResolution();
int32 Factor = GetTranslucentShadowDownsampleFactor();
ShadowDepthResolution.X = FMath::Clamp(ShadowDepthResolution.X / Factor, 1, GMaxShadowDepthBufferSizeX);
ShadowDepthResolution.Y = FMath::Clamp(ShadowDepthResolution.Y / Factor, 1, GMaxShadowDepthBufferSizeY);
return ShadowDepthResolution;
}
const FTextureRHIRef& FSceneRenderTargets::GetSceneColorSurface() const
{
if (!GetSceneColorForCurrentShadingPath())
{
return GBlackTexture->TextureRHI;
}
return (const FTextureRHIRef&)GetSceneColor()->GetRenderTargetItem().TargetableTexture;
}
const FTextureRHIRef& FSceneRenderTargets::GetSceneColorTexture() const
{
if (!GetSceneColorForCurrentShadingPath())
{
return GBlackTexture->TextureRHI;
}
return (const FTextureRHIRef&)GetSceneColor()->GetRenderTargetItem().ShaderResourceTexture;
}
const FTexture2DRHIRef* FSceneRenderTargets::GetActualDepthTexture() const
{
const FTexture2DRHIRef* DepthTexture = NULL;
if((CurrentFeatureLevel >= ERHIFeatureLevel::SM4) || IsPCPlatform(GShaderPlatformForFeatureLevel[CurrentFeatureLevel]))
{
if(GSupportsDepthFetchDuringDepthTest)
{
DepthTexture = &GetSceneDepthTexture();
}
else
{
DepthTexture = &GetAuxiliarySceneDepthSurface();
}
}
else if (IsMobilePlatform(GShaderPlatformForFeatureLevel[CurrentFeatureLevel]))
{
// TODO: avoid depth texture fetch when shader needs fragment previous depth and device supports framebuffer fetch
//bool bSceneDepthInAlpha = (GetSceneColor()->GetDesc().Format == PF_FloatRGBA);
//bool bOnChipDepthFetch = (GSupportsShaderDepthStencilFetch || (bSceneDepthInAlpha && GSupportsShaderFramebufferFetch));
//
//if (bOnChipDepthFetch)
//{
// DepthTexture = (const FTexture2DRHIRef*)(&GSystemTextures.DepthDummy->GetRenderTargetItem().ShaderResourceTexture);
//}
//else
{
DepthTexture = &GetSceneDepthTexture();
}
}
check(DepthTexture != NULL);
return DepthTexture;
}
IPooledRenderTarget* FSceneRenderTargets::GetGBufferVelocityRT()
{
if (!bAllocateVelocityGBuffer)
{
return nullptr;
}
return GBufferVelocity;
}
IPooledRenderTarget* FSceneRenderTargets::RequestCustomDepth(FRHICommandListImmediate& RHICmdList, bool bPrimitives)
{
int Value = CVarCustomDepth.GetValueOnRenderThread();
if((Value == 1 && bPrimitives) || Value == 2 || IsCustomDepthPassWritingStencil())
{
if (!CustomStencilSRV.GetReference() || !CustomDepth.GetReference() || BufferSize != CustomDepth->GetDesc().Extent)
{
// Todo: Could check if writes stencil here and create min viable target
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_None, TexCreate_DepthStencilTargetable, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, CustomDepth, TEXT("CustomDepth"));
CustomStencilSRV = RHICreateShaderResourceView((FTexture2DRHIRef&)CustomDepth->GetRenderTargetItem().TargetableTexture, 0, 1, PF_X24_G8);
}
return CustomDepth;
}
return 0;
}
bool FSceneRenderTargets::IsCustomDepthPassWritingStencil() const
{
return (CVarCustomDepth.GetValueOnRenderThread() == 3);
}
/** Returns an index in the range [0, NumCubeShadowDepthSurfaces) given an input resolution. */
int32 FSceneRenderTargets::GetCubeShadowDepthZIndex(int32 ShadowResolution) const
{
static auto CVarMinShadowResolution = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Shadow.MinResolution"));
FIntPoint ObjectShadowBufferResolution = GetShadowDepthTextureResolution();
// Use a lower resolution because cubemaps use a lot of memory
ObjectShadowBufferResolution.X /= 2;
ObjectShadowBufferResolution.Y /= 2;
const int32 SurfaceSizes[NumCubeShadowDepthSurfaces] =
{
ObjectShadowBufferResolution.X,
ObjectShadowBufferResolution.X / 2,
ObjectShadowBufferResolution.X / 4,
ObjectShadowBufferResolution.X / 8,
CVarMinShadowResolution->GetValueOnRenderThread()
};
for (int32 SearchIndex = 0; SearchIndex < NumCubeShadowDepthSurfaces; SearchIndex++)
{
if (ShadowResolution >= SurfaceSizes[SearchIndex])
{
return SearchIndex;
}
}
check(0);
return 0;
}
/** Returns the appropriate resolution for a given cube shadow index. */
int32 FSceneRenderTargets::GetCubeShadowDepthZResolution(int32 ShadowIndex) const
{
checkSlow(ShadowIndex >= 0 && ShadowIndex < NumCubeShadowDepthSurfaces);
static auto CVarMinShadowResolution = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Shadow.MinResolution"));
FIntPoint ObjectShadowBufferResolution = GetShadowDepthTextureResolution();
// Use a lower resolution because cubemaps use a lot of memory
ObjectShadowBufferResolution.X = FMath::Max(ObjectShadowBufferResolution.X / 2, 1);
ObjectShadowBufferResolution.Y = FMath::Max(ObjectShadowBufferResolution.Y / 2, 1);
const int32 SurfaceSizes[NumCubeShadowDepthSurfaces] =
{
ObjectShadowBufferResolution.X,
FMath::Max(ObjectShadowBufferResolution.X / 2, 1),
FMath::Max(ObjectShadowBufferResolution.X / 4, 1),
FMath::Max(ObjectShadowBufferResolution.X / 8, 1),
CVarMinShadowResolution->GetValueOnRenderThread()
};
return SurfaceSizes[ShadowIndex];
}
bool FSceneRenderTargets::AreShadingPathRenderTargetsAllocated(EShadingPath InShadingPath) const
{
switch (InShadingPath)
{
case EShadingPath::Mobile:
{
return (SceneColor[(int32)EShadingPath::Mobile] != nullptr);
}
case EShadingPath::Deferred:
{
return (ScreenSpaceAO != nullptr);
}
default:
{
checkNoEntry();
return false;
}
}
}
/*-----------------------------------------------------------------------------
FSceneTextureShaderParameters
-----------------------------------------------------------------------------*/
//
void FSceneTextureShaderParameters::Bind(const FShaderParameterMap& ParameterMap)
{
// only used if Material has an expression that requires SceneColorTexture
SceneColorTextureParameter.Bind(ParameterMap,TEXT("SceneColorTexture"));
SceneColorTextureParameterSampler.Bind(ParameterMap,TEXT("SceneColorTextureSampler"));
// only used if Material has an expression that requires SceneDepthTexture
SceneDepthTextureParameter.Bind(ParameterMap,TEXT("SceneDepthTexture"));
SceneDepthTextureParameterSampler.Bind(ParameterMap,TEXT("SceneDepthTextureSampler"));
// Only used if Material has an expression that requires SceneAlphaCopyTexture
SceneAlphaCopyTextureParameter.Bind(ParameterMap,TEXT("SceneAlphaCopyTexture"));
SceneAlphaCopyTextureParameterSampler.Bind(ParameterMap,TEXT("SceneAlphaCopyTextureSampler"));
//
SceneDepthTextureNonMS.Bind(ParameterMap,TEXT("SceneDepthTextureNonMS"));
SceneColorSurfaceParameter.Bind(ParameterMap,TEXT("SceneColorSurface"));
// only used if Material has an expression that requires SceneColorTextureMSAA
SceneDepthSurfaceParameter.Bind(ParameterMap,TEXT("SceneDepthSurface"));
DirectionalOcclusionSampler.Bind(ParameterMap, TEXT("DirectionalOcclusionSampler"));
DirectionalOcclusionTexture.Bind(ParameterMap, TEXT("DirectionalOcclusionTexture"));
}
template< typename ShaderRHIParamRef, typename TRHICmdList >
void FSceneTextureShaderParameters::Set(
TRHICmdList& RHICmdList,
const ShaderRHIParamRef& ShaderRHI,
const FSceneView& View,
ESceneRenderTargetsMode::Type TextureMode,
ESamplerFilter ColorFilter ) const
{
if (TextureMode == ESceneRenderTargetsMode::SetTextures)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// optimization possible: TShaderRHIParamRef is no param Ref
if (SceneColorTextureParameter.IsBound())
{
FSamplerStateRHIRef Filter;
switch ( ColorFilter )
{
case SF_Bilinear:
Filter = TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
break;
case SF_Trilinear:
Filter = TStaticSamplerState<SF_Trilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
break;
case SF_AnisotropicPoint:
Filter = TStaticSamplerState<SF_AnisotropicPoint,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
break;
case SF_AnisotropicLinear:
Filter = TStaticSamplerState<SF_AnisotropicLinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
break;
case SF_Point:
default:
Filter = TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
break;
}
SetTextureParameter(
RHICmdList,
ShaderRHI,
SceneColorTextureParameter,
SceneColorTextureParameterSampler,
Filter,
SceneContext.GetSceneColorTexture()
);
}
if (SceneAlphaCopyTextureParameter.IsBound() && SceneContext.HasSceneAlphaCopyTexture())
{
FSamplerStateRHIRef Filter;
Filter = TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
SetTextureParameter(
RHICmdList,
ShaderRHI,
SceneAlphaCopyTextureParameter,
SceneAlphaCopyTextureParameterSampler,
Filter,
SceneContext.GetSceneAlphaCopyTexture()
);
}
if(SceneDepthTextureParameter.IsBound() || SceneDepthTextureParameterSampler.IsBound())
{
const FTexture2DRHIRef* DepthTexture = SceneContext.GetActualDepthTexture();
if (SceneContext.IsSeparateTranslucencyPass() && SceneContext.IsSeparateTranslucencyDepthValid())
{
FIntPoint OutScaledSize;
float OutScale;
SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale);
if (OutScale < 1.0f)
{
DepthTexture = &SceneContext.GetSeparateTranslucencyDepthSurface();
}
}
SetTextureParameter(
RHICmdList,
ShaderRHI,
SceneDepthTextureParameter,
SceneDepthTextureParameterSampler,
TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
*DepthTexture
);
}
const auto FeatureLevel = View.GetFeatureLevel();
if (FeatureLevel >= ERHIFeatureLevel::SM5)
{
SetTextureParameter(RHICmdList, ShaderRHI, SceneColorSurfaceParameter, SceneContext.GetSceneColorSurface());
}
if (FeatureLevel >= ERHIFeatureLevel::SM4)
{
if(GSupportsDepthFetchDuringDepthTest)
{
if(SceneDepthSurfaceParameter.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, SceneContext.GetSceneDepthSurface());
}
if(SceneDepthTextureNonMS.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, SceneContext.GetSceneDepthTexture());
}
}
else
{
if(SceneDepthSurfaceParameter.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, SceneContext.GetAuxiliarySceneDepthSurface());
}
if(SceneDepthTextureNonMS.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, SceneContext.GetAuxiliarySceneDepthSurface());
}
}
}
}
else if (TextureMode == ESceneRenderTargetsMode::DontSet)
{
// Verify that none of these were bound if we were told not to set them
ensure(!SceneColorTextureParameter.IsBound()
&& !SceneDepthTextureParameter.IsBound()
&& !SceneColorSurfaceParameter.IsBound()
&& !SceneDepthSurfaceParameter.IsBound()
&& !SceneDepthTextureNonMS.IsBound());
}
else if (TextureMode == ESceneRenderTargetsMode::DontSetIgnoreBoundByEditorCompositing)
{
// Verify that none of these were bound if we were told not to set them
// ignore SceneDepthTextureNonMS
ensure(!SceneColorTextureParameter.IsBound()
&& !SceneDepthTextureParameter.IsBound()
&& !SceneColorSurfaceParameter.IsBound()
&& !SceneDepthSurfaceParameter.IsBound());
}
if( DirectionalOcclusionSampler.IsBound() )
{
bool bDirectionalOcclusion = false;
FSceneViewState* ViewState = (FSceneViewState*)View.State;
if (ViewState != nullptr)
{
FLightPropagationVolume* Lpv = ViewState->GetLightPropagationVolume(View.GetFeatureLevel());
if(Lpv != nullptr)
{
bDirectionalOcclusion = Lpv->IsDirectionalOcclusionEnabled();
}
}
FTextureRHIParamRef DirectionalOcclusion = nullptr;
if( bDirectionalOcclusion )
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
DirectionalOcclusion = SceneContext.GetDirectionalOcclusionTexture();
}
else
{
DirectionalOcclusion = GWhiteTexture->TextureRHI;
}
FSamplerStateRHIRef Filter;
Filter = TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
SetTextureParameter(
RHICmdList,
ShaderRHI,
DirectionalOcclusionTexture,
DirectionalOcclusionSampler,
Filter,
DirectionalOcclusion
);
}
}
#define IMPLEMENT_SCENE_TEXTURE_PARAM_SET( ShaderRHIParamRef ) \
template void FSceneTextureShaderParameters::Set< ShaderRHIParamRef >( \
FRHICommandList& RHICmdList, \
const ShaderRHIParamRef& ShaderRHI, \
const FSceneView& View, \
ESceneRenderTargetsMode::Type TextureMode, \
ESamplerFilter ColorFilter \
) const;
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FVertexShaderRHIParamRef );
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FHullShaderRHIParamRef );
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FDomainShaderRHIParamRef );
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FGeometryShaderRHIParamRef );
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FPixelShaderRHIParamRef );
IMPLEMENT_SCENE_TEXTURE_PARAM_SET( FComputeShaderRHIParamRef );
FArchive& operator<<(FArchive& Ar,FSceneTextureShaderParameters& Parameters)
{
Ar << Parameters.SceneColorTextureParameter;
Ar << Parameters.SceneColorTextureParameterSampler;
Ar << Parameters.SceneAlphaCopyTextureParameter;
Ar << Parameters.SceneAlphaCopyTextureParameterSampler;
Ar << Parameters.SceneColorSurfaceParameter;
Ar << Parameters.SceneDepthTextureParameter;
Ar << Parameters.SceneDepthTextureParameterSampler;
Ar << Parameters.SceneDepthSurfaceParameter;
Ar << Parameters.SceneDepthTextureNonMS;
Ar << Parameters.DirectionalOcclusionSampler;
Ar << Parameters.DirectionalOcclusionTexture;
return Ar;
}
// Note this is not just for Deferred rendering, it also applies to mobile rendering.
void FDeferredPixelShaderParameters::Bind(const FShaderParameterMap& ParameterMap)
{
SceneTextureParameters.Bind(ParameterMap);
GBufferResources.Bind(ParameterMap,TEXT("GBuffers"));
DBufferATextureMS.Bind(ParameterMap,TEXT("DBufferATextureMS"));
DBufferBTextureMS.Bind(ParameterMap,TEXT("DBufferBTextureMS"));
DBufferCTextureMS.Bind(ParameterMap,TEXT("DBufferCTextureMS"));
ScreenSpaceAOTextureMS.Bind(ParameterMap,TEXT("ScreenSpaceAOTextureMS"));
DBufferATextureNonMS.Bind(ParameterMap,TEXT("DBufferATextureNonMS"));
DBufferBTextureNonMS.Bind(ParameterMap,TEXT("DBufferBTextureNonMS"));
DBufferCTextureNonMS.Bind(ParameterMap,TEXT("DBufferCTextureNonMS"));
ScreenSpaceAOTextureNonMS.Bind(ParameterMap,TEXT("ScreenSpaceAOTextureNonMS"));
CustomDepthTextureNonMS.Bind(ParameterMap,TEXT("CustomDepthTextureNonMS"));
DBufferATexture.Bind(ParameterMap,TEXT("DBufferATexture"));
DBufferATextureSampler.Bind(ParameterMap,TEXT("DBufferATextureSampler"));
DBufferBTexture.Bind(ParameterMap,TEXT("DBufferBTexture"));
DBufferBTextureSampler.Bind(ParameterMap,TEXT("DBufferBTextureSampler"));
DBufferCTexture.Bind(ParameterMap,TEXT("DBufferCTexture"));
DBufferCTextureSampler.Bind(ParameterMap,TEXT("DBufferCTextureSampler"));
ScreenSpaceAOTexture.Bind(ParameterMap,TEXT("ScreenSpaceAOTexture"));
ScreenSpaceAOTextureSampler.Bind(ParameterMap,TEXT("ScreenSpaceAOTextureSampler"));
CustomDepthTexture.Bind(ParameterMap,TEXT("CustomDepthTexture"));
CustomDepthTextureSampler.Bind(ParameterMap,TEXT("CustomDepthTextureSampler"));
CustomStencilTexture.Bind(ParameterMap,TEXT("CustomStencilTexture"));
}
bool IsDBufferEnabled();
template< typename ShaderRHIParamRef, typename TRHICmdList >
void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FSceneView& View, ESceneRenderTargetsMode::Type TextureMode) const
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// This is needed on PC ES2 for SceneAlphaCopy, probably should be refactored for performance.
SceneTextureParameters.Set(RHICmdList, ShaderRHI, View, TextureMode, SF_Point);
// if() is purely an optimization and could be removed
if(IsDBufferEnabled())
{
IPooledRenderTarget* DBufferA = SceneContext.DBufferA ? SceneContext.DBufferA : GSystemTextures.BlackDummy;
IPooledRenderTarget* DBufferB = SceneContext.DBufferB ? SceneContext.DBufferB : GSystemTextures.BlackDummy;
IPooledRenderTarget* DBufferC = SceneContext.DBufferC ? SceneContext.DBufferC : GSystemTextures.BlackDummy;
// todo: optimize out when not needed
SetTextureParameter(RHICmdList, ShaderRHI, DBufferATexture, DBufferATextureSampler, TStaticSamplerState<>::GetRHI(), DBufferA->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferBTexture, DBufferBTextureSampler, TStaticSamplerState<>::GetRHI(), DBufferB->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferCTexture, DBufferCTextureSampler, TStaticSamplerState<>::GetRHI(), DBufferC->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferATextureMS, DBufferA->GetRenderTargetItem().TargetableTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferBTextureMS, DBufferB->GetRenderTargetItem().TargetableTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferCTextureMS, DBufferC->GetRenderTargetItem().TargetableTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferATextureNonMS, DBufferA->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferBTextureNonMS, DBufferB->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, DBufferCTextureNonMS, DBufferC->GetRenderTargetItem().ShaderResourceTexture);
}
const auto FeatureLevel = View.GetFeatureLevel();
if (TextureMode == ESceneRenderTargetsMode::SetTextures && FeatureLevel >= ERHIFeatureLevel::SM4)
{
// if there is no ambient occlusion it's better to have white there
IPooledRenderTarget* ScreenSpaceAO = SceneContext.ScreenSpaceAO;
if(!SceneContext.bScreenSpaceAOIsValid)
{
ScreenSpaceAO = GSystemTextures.WhiteDummy;
}
// if there is no custom depth it's better to have the far distance there
IPooledRenderTarget* CustomDepth = SceneContext.bCustomDepthIsValid ? SceneContext.CustomDepth.GetReference() : 0;
if(!CustomDepth)
{
CustomDepth = GSystemTextures.BlackDummy;
}
if (FeatureLevel >= ERHIFeatureLevel::SM4)
{
if (GBufferResources.IsBound())
{
SetUniformBufferParameter(RHICmdList, ShaderRHI, GBufferResources, SceneContext.GetGBufferResourcesUniformBuffer());
}
SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTexture, ScreenSpaceAOTextureSampler, TStaticSamplerState<>::GetRHI(), ScreenSpaceAO->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureMS, ScreenSpaceAO->GetRenderTargetItem().TargetableTexture);
SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureNonMS, ScreenSpaceAO->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTexture, CustomDepthTextureSampler, TStaticSamplerState<>::GetRHI(), CustomDepth->GetRenderTargetItem().ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTextureNonMS, CustomDepth->GetRenderTargetItem().ShaderResourceTexture);
if (CustomStencilTexture.IsBound())
{
if (SceneContext.bCustomDepthIsValid && SceneContext.CustomStencilSRV.GetReference())
{
SetSRVParameter(RHICmdList, ShaderRHI, CustomStencilTexture, SceneContext.CustomStencilSRV);
}
else
{
SetTextureParameter(RHICmdList, ShaderRHI, CustomStencilTexture, GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture);
}
}
}
}
else if (TextureMode == ESceneRenderTargetsMode::DontSet ||
TextureMode == ESceneRenderTargetsMode::DontSetIgnoreBoundByEditorCompositing)
{
// Verify that none of these are actually bound
checkSlow(!GBufferResources.IsBound());
}
}
#define IMPLEMENT_DEFERRED_PARAMETERS_SET( ShaderRHIParamRef, TRHICmdList ) \
template void FDeferredPixelShaderParameters::Set< ShaderRHIParamRef, TRHICmdList >(\
TRHICmdList& RHICmdList, \
const ShaderRHIParamRef ShaderRHI, \
const FSceneView& View, \
ESceneRenderTargetsMode::Type TextureMode \
) const;
IMPLEMENT_DEFERRED_PARAMETERS_SET( FVertexShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET( FHullShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET( FDomainShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET( FGeometryShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET( FPixelShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET( FComputeShaderRHIParamRef, FRHICommandList );
IMPLEMENT_DEFERRED_PARAMETERS_SET(FVertexShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FHullShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FDomainShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FGeometryShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FPixelShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FComputeShaderRHIParamRef, FRHICommandListImmediate);
IMPLEMENT_DEFERRED_PARAMETERS_SET(FComputeShaderRHIParamRef, FRHIAsyncComputeCommandListImmediate );
FArchive& operator<<(FArchive& Ar,FDeferredPixelShaderParameters& Parameters)
{
Ar << Parameters.SceneTextureParameters;
Ar << Parameters.GBufferResources;
Ar << Parameters.DBufferATextureMS;
Ar << Parameters.DBufferBTextureMS;
Ar << Parameters.DBufferCTextureMS;
Ar << Parameters.ScreenSpaceAOTextureMS;
Ar << Parameters.DBufferATextureNonMS;
Ar << Parameters.DBufferBTextureNonMS;
Ar << Parameters.DBufferCTextureNonMS;
Ar << Parameters.ScreenSpaceAOTextureNonMS;
Ar << Parameters.CustomDepthTextureNonMS;
Ar << Parameters.DBufferATexture;
Ar << Parameters.DBufferATextureSampler;
Ar << Parameters.DBufferBTexture;
Ar << Parameters.DBufferBTextureSampler;
Ar << Parameters.DBufferCTexture;
Ar << Parameters.DBufferCTextureSampler;
Ar << Parameters.ScreenSpaceAOTexture;
Ar << Parameters.ScreenSpaceAOTextureSampler;
Ar << Parameters.CustomDepthTexture;
Ar << Parameters.CustomDepthTextureSampler;
Ar << Parameters.CustomStencilTexture;
return Ar;
}