Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp
Marcus Wassmer 2826204161 Copying //UE4/Dev-Rendering to //UE4/Dev-Main (Source: //UE4/Dev-Rendering @ 3357411)
#lockdown Nick.Penwarden
#rb none

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

Change 3244756 on 2017/01/03 by Marcus.Wassmer

	Copying //Tasks/UE4/Dev-Niagara@3244743 to Dev-Rendering (//UE4/Dev-Rendering)

Change 3248667 on 2017/01/05 by Olaf.Piesche

	Resaving default asset because of engine verison issue; maybe unnecessary, but resaving niagara engine content to be sure

	#jira UE-40160

Change 3249324 on 2017/01/06 by Marcus.Wassmer

	Resave with an actual version to stop cook warning

Change 3249611 on 2017/01/06 by Marcus.Wassmer

	Just remove warning-causing niagara data for now.

Change 3308052 on 2017/02/16 by Rolando.Caloca

	DR - Check for Vulkan SDK, and only use it if it's newer or the same as the headers we distribute

Change 3308109 on 2017/02/16 by Rolando.Caloca

	DR - Upgrade glslang to 1.0.39.1

Change 3308111 on 2017/02/16 by Rolando.Caloca

	DR - Update Vulkan distribution to 1.0.39.1

Change 3308153 on 2017/02/16 by Rolando.Caloca

	DR - Updated glslang libs

Change 3308842 on 2017/02/17 by Rolando.Caloca

	DR - Fixed copy/paste

Change 3310007 on 2017/02/17 by Chris.Bunner

	Back out CL 3221219 - causing MIC generation issues and superseded by CL 3273971.

	#jira UE-37792

Change 3310154 on 2017/02/17 by Chris.Bunner

	Assert when attempting to add a custom material attribute already in the base attributes list.

Change 3310155 on 2017/02/17 by Chris.Bunner

	PR #3231: Validate material index before accessing (Contributed by projectgheist)

	#jira UE-41774, UE-41788

Change 3310162 on 2017/02/17 by Chris.Bunner

	PR #3252: Added MobileMaterialInterface to UsedMaterials (Contributed by projectgheist)

	#jira UE-41823, UE-41950

Change 3310176 on 2017/02/17 by Chris.Bunner

	Merging CL 3233886: AMD HDR support (requires r.AMDSupportsHDRDisplayOutput=1 in ini).
	Update to AGS 5.0.5.
	Partial code tidy up.

Change 3310187 on 2017/02/17 by Chris.Bunner

	Preserve constant expressions rather than always casting after translating a material attribute. Losing the notion of constant means we can't correctly detect used properties and falsely enable e.g. PDO. Happened because of the incorrect component masks in BreakMaterialNodes which then had to be downcast to the correct type which is done as an inline fragment rather than swizzle expression.

	#jira UE-41594

Change 3310215 on 2017/02/17 by Chris.Bunner

	Prevent SpeedTree node compiling for skeletal meshes (not supported as uses more UV sets than available).
	More descriptive error for missing Cubemap UV input on TextureSample material node .

	#jira UE-33098

Change 3310838 on 2017/02/18 by Joe.Graf

	Moved some private functions to public for a licensee

	#CodeReview: matt.kuhlenschmidt
	#rb: n/a

Change 3311876 on 2017/02/20 by Rolando.Caloca

	DR - Expose skin cache cvar r.SkinCache.AccumulationBufferSizeInKB

	#jira UE-42014

Change 3314139 on 2017/02/21 by Rolando.Caloca

	DR - Minor cleanup pass
	- Remove FVulkanPendingState
	- Renamed some classes for clarity
	- Hoist pending UAVs for flush out to pending compute state

Change 3314642 on 2017/02/21 by Rolando.Caloca

	DR - Some more renaming

Change 3315431 on 2017/02/21 by Ben.Salem

	Properly set default values for test time out and tick. We now will default to ticking once per second, and tracking the macro stats of GPU/Render/Game thread time.

	#tests Ran showdown demo several times

Change 3316710 on 2017/02/22 by Rolando.Caloca

	DR - hlslcc - Fix refract intrinsic

Change 3316718 on 2017/02/22 by Rolando.Caloca

	DR - hlslcc - Built libs to pick up change from 3316710 - refract fix

Change 3316820 on 2017/02/22 by Benjamin.Hyder

	updating Tm-TrigNodes map

Change 3317192 on 2017/02/22 by Benjamin.Hyder

	Updating QA-Decals map

Change 3317528 on 2017/02/22 by Benjamin.Hyder

	Updating QA-Decals map

Change 3317639 on 2017/02/22 by Benjamin.Hyder

	Updating Decal on Complex Mesh example in QA-Decals

Change 3317764 on 2017/02/22 by Benjamin.Hyder

	Final updates to QA-Decals

Change 3318319 on 2017/02/22 by Rolando.Caloca

	DR - minor reorg/rename

Change 3318379 on 2017/02/22 by Rolando.Caloca

	DR - more cleanup

Change 3321181 on 2017/02/24 by Rolando.Caloca

	DR - Fix GL bug

Change 3321247 on 2017/02/24 by Rolando.Caloca

	DR - Fix misc bugs

Change 3321898 on 2017/02/24 by Chris.Bunner

	Only issue clear TLV dispatch if required.

	#jira UERNDR-193

Change 3321904 on 2017/02/24 by Chris.Bunner

	Added comment for potential future optimization.

Change 3322013 on 2017/02/24 by Uriel.Doyon

	Fixed separate translucency being affected by Gaussian DOF
	#jira UE-40489

Change 3322517 on 2017/02/24 by Uriel.Doyon

	Fixed issue with InvestigateTexture command removing budget limit.
	Fixed StreamingBounds show flag not working. It nows shows the streaming bound for the currently selected textures.
	#jira UE-40485

Change 3323470 on 2017/02/27 by Chad.Garyet

	Removing DDC job from dev-rendering

Change 3323479 on 2017/02/27 by Chad.Garyet

	Removing RDU agent type

Change 3323519 on 2017/02/27 by Chad.Garyet

	removing NCL/LHR/SEA agent types to clean up space

Change 3323639 on 2017/02/27 by Benjamin.Hyder

	More updates to QA-Decals

Change 3324207 on 2017/02/27 by Uriel.Doyon

	Fixed typo ScaleTexturesByGlobalMyBias ->  ScaleTexturesByGlobalMipBias
	Removed bad merge in FStreamingTextureLevelContext::GetBuildDataIndexRef

Change 3324396 on 2017/02/27 by Uriel.Doyon

	Fixed an issue with the Streaming Bounds show flag interferring with the static level data initialization
	#jira UE-40485

Change 3325227 on 2017/02/28 by Chris.Bunner

	Fix-up AMD AGS libs.

Change 3325566 on 2017/02/28 by Uriel.Doyon

	Fixed possible out-of-bound access in GetUsedTexture() when passing ERHIFeatureLevel::Num

Change 3326009 on 2017/02/28 by Uriel.Doyon

	Better fix for 3325566, as the previous fix would ignore the material instance overrides.

Change 3327058 on 2017/03/01 by Benjamin.Hyder

	Preparing TM_Shadermodels map for automation

Change 3328222 on 2017/03/01 by Chris.Bunner

	Prevent decals from drawing in separate translucency pass. Whilst user control and material relevance were already removed, if the flag was checked before being disabled (by swapping to decal domain) this was still being read in the render loop, now explicitly ignores decals.

	#jira UE-42449, UE-42446

Change 3329848 on 2017/03/02 by Uriel.Doyon

	Added some extra logs to help track UE-42168

Change 3329977 on 2017/03/02 by Rolando.Caloca

	DR - Fix bad clear value

Change 3330008 on 2017/03/02 by Benjamin.Hyder

	More preparations for QA-Decals automation

Change 3330754 on 2017/03/02 by Daniel.Wright

	Prominent comment explaining reflection env async compute usage and why it's not overlapped with anything

Change 3331451 on 2017/03/03 by Marc.Olano

	Manually unroll simplex noise loop to avoid PSO bug on AMD/Metal

Change 3331839 on 2017/03/03 by Rolando.Caloca

	DR - hlslcc - add missing file to project

Change 3332247 on 2017/03/03 by Rolando.Caloca

	DR - Fix for integrated intel
	PR #3305
	#jira UE-42393

Change 3332259 on 2017/03/03 by Rolando.Caloca

	DR - Fix bad index into pixel formats
	PR #3237
	#jira UE-41855

Change 3332305 on 2017/03/03 by Rolando.Caloca

	DR - OpenGL SRV for index buffers
	PR #3271
	#jira UE-32618

Change 3332313 on 2017/03/03 by Rolando.Caloca

	DR - Fix for integrated intel (properly)
	PR #3305
	#jira UE-42393

Change 3332317 on 2017/03/03 by Rolando.Caloca

	DR - OpenGL SRV for index buffers (properly)
	PR #3271
	#jira UE-32618

Change 3332368 on 2017/03/03 by Rolando.Caloca

	DR - Minor fixes so -sm4 and -sm5 can be used on windows with OpenGL/Vulkan

Change 3333690 on 2017/03/06 by Daniel.Wright

	[Copy] Changing movable skylight properties no longer affects static draw lists

Change 3333693 on 2017/03/06 by Daniel.Wright

	[Copy] Added 'r.AOListMeshDistanceFields' which dumps out mesh distance fields sorted by memory size, useful for directing content optimizations

Change 3333705 on 2017/03/06 by Daniel.Wright

	[Copy] Mesh distance fields are now 8 bit fixed point by default, but can be changed back to 16 bit floating piont with a project setting.
	* 8 bit uses half memory but introduces error for thin surfaces or large meshes.

Change 3333721 on 2017/03/06 by David.Hill

	DecalProxy:
	Copy float FadeScreenSize to FDeferredDecalProxy for use in the render thread.  This avoids  pointer chasing to the UDecalComponent (game thread component).

Change 3333772 on 2017/03/06 by Daniel.Wright

	[Copy] Scene motion blur data is only updated for the main renderer frames.  Fixes scene captures and planar reflections breaking object motion blur.

Change 3333790 on 2017/03/06 by Daniel.Wright

	[Copy] Mesh distance field generation uses Embree, for a 2.5x speedup
	* Can switch back to old kDOP generation with 'r.DistanceFieldBuild.UseEmbree 0' for debugging

Change 3333822 on 2017/03/06 by Daniel.Wright

	[Copy] Moved mesh distance field code into MeshDistanceFieldUtilities.cpp
	* Moved FMeshUtilities to its own header so the 8k line MeshUtilites.cpp file can be further split up

Change 3333827 on 2017/03/06 by Daniel.Wright

	[Copy] Range compress 8bit distance fields - gets one extra bit of precision on average

Change 3333828 on 2017/03/06 by Daniel.Wright

	[Copy] Raised High ShadowQuality to 2048 as 1024 for CSM is way too low

Change 3333831 on 2017/03/06 by Daniel.Wright

	Non-editor compile fix

Change 3333836 on 2017/03/06 by Daniel.Wright

	[Copy] Workaround for gobal distance field volume textures being bloated by 4x on PS4 due to the recommended tiling modes.  They now use a 2d tiling mode which avoids the bloat, saving 96Mb.

Change 3333843 on 2017/03/06 by Daniel.Wright

	[Copy] Added OcclusionExponent to skylight component
	* Useful for brightening up indoors without losing contact shadows as MinOcclusion does

Change 3333845 on 2017/03/06 by Daniel.Wright

	[Copy] Capsule shadow BP functions

Change 3333850 on 2017/03/06 by Daniel.Wright

	[Copy] Added OcclusionCombineMode to skylight component

Change 3333854 on 2017/03/06 by Daniel.Wright

	[Copy] Gnm properly registers clears as GPU work so those events show up in profilegpu

Change 3333857 on 2017/03/06 by Daniel.Wright

	[Copy] Clear light attenuation for local lights with a quad covering their screen extents
	* Clearing the entire light attenuation buffer costs .1ms on PS4.  This optimization lowers the minimum cost of a shadow casting light from .15ms -> .03ms.
	* Shadowed lights in Fortnite with 25 lights 3.7ms -> 1.42ms on PS4

Change 3333860 on 2017/03/06 by Daniel.Wright

	[Copy] Flush deferred deletes when reallocating distance field atlas to reduce peak memory

Change 3333861 on 2017/03/06 by Daniel.Wright

	[Copy] Disable all distance field features on Intel cards as HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas

Change 3333869 on 2017/03/06 by Daniel.Wright

	[Copy] Volumetric Fog using a volume texture mapped to the camera frustum
	* Volumetric fog can be enabled on an Exponential Height Fog component with additional controls
	* Lights have a VolumetricScatteringIntensity
	* New cvars r.VolumetricFog, r.VolumetricFog.GridPixelSize, r.VolumetricFog.GridSizeZ, r.VolumetricFog.DepthDistributionScale
	* Lighting features supported:
	   * Directional light with CSM and a light function
	   * Point / spot lights without shadows / light functions / IES profiles
	   * Skylight with occlusion from distance fields
	* Analytical height fog covers the view range past where the volumetric fog ends
	* Temporal reprojection is used on the volumetric fog scattering and extinction to achieve stability
	* Translucency integrates properly into volumetric fog
	* Height fog StartDistance is not supported by volumetric fog and should be set to 0.

Change 3333894 on 2017/03/06 by Daniel.Wright

	[Copy] Initialize GDummyVolumetricFogGlobalDataUniformBuffer outside of parallel rendering

Change 3333902 on 2017/03/06 by Daniel.Wright

	[Copy] Better handling of volumetric fog enabled with distance of 0

Change 3333903 on 2017/03/06 by Daniel.Wright

	[Copy] Fixed volumetric fog trying to render light functions for a point light

Change 3333908 on 2017/03/06 by Daniel.Wright

	[Copy] Volumetric materials
	* Added new material domain Volume, which can output Scattering, Absorption and Emissive.  All properties are in world space densities.
	* Particle systems using the Volume domain are voxelized based on their ParticlePosition and ParticleRadius
	* Volumetric fog integration is now energy conservative - scattering is integrated against transmission over the depth of each slice.
	* Added bOverrideLightColorsWithFogInscatteringColors to exponential height fog, which can be enabled to make Volumetric Fog match Height fog more closely

Change 3334134 on 2017/03/06 by Daniel.Wright

	[Copy from Michael Trepka] Added Embree 2.14.0 and changed MeshUtilities to use it as this solves issues with Embree leaking TLS keys. UnrealLightmass is still using older Embree 2.7.0 until we can find time to properly test it with the new version. Also, invalidated distance field DDC to force it to rebuild with updated Embree.

Change 3334420 on 2017/03/06 by Daniel.Wright

	Fixed RTDF shadows

Change 3335467 on 2017/03/07 by Benjamin.Hyder

	Initial submission of QA-Decals map to EngineTest

Change 3335556 on 2017/03/07 by Daniel.Wright

	Changed mesh distance field default format back to R16f

Change 3338020 on 2017/03/08 by Daniel.Wright

	Disable volumetric fog in vertex shaders for feature levels which don't support it

Change 3339394 on 2017/03/09 by Chris.Bunner

	Correctly handle material texture translation error edge case.

	#jira UE-42579, UE-42670

Change 3339992 on 2017/03/09 by Daniel.Wright

	Only compile volumetric fog shaders on supporting platforms

Change 3341858 on 2017/03/10 by Arne.Schober

	Copying //UE4/Dev-Rendering-PSO to Dev-Rendering (//UE4/Dev-Rendering)

	#RB Rolando.Caloca, Marcus.Wassmer, Daniel.Wright, Nick.Penwarden, Mark.Satterthwaite

Change 3342004 on 2017/03/10 by Arne.Schober

	Copying //UE4/Dev-Rendering-PSO to Dev-Rendering (//UE4/Dev-Rendering)
	Fix unity build

	#RB Marcus.Wassmer

Change 3343307 on 2017/03/13 by Marcus.Wassmer

	Update showflags when we are guaranteed it will happen in all possible ways to spawn the scenecapture. (drag into editor, PIE, -game, etc)

Change 3343732 on 2017/03/13 by Rolando.Caloca

	DR - Vulkan compute pipeline & refactor

Change 3344846 on 2017/03/14 by Rolando.Caloca

	DR - Android compile fixes

Change 3344883 on 2017/03/14 by Rolando.Caloca

	DR - Add missing stencil load/store to PSO initializer

Change 3344985 on 2017/03/14 by Rolando.Caloca

	DR - Made load/store actions uint8

Change 3345141 on 2017/03/14 by Rolando.Caloca

	DR - vk - Rework render pass hash

Change 3345304 on 2017/03/14 by Benjamin.Hyder

	Updating TM-Distancefields map to include TemplateFloor mesh

Change 3345387 on 2017/03/14 by Rolando.Caloca

	DR - Add _RenderThread calls for Create*Shader so RHIs can choose not to stall when creating

Change 3345388 on 2017/03/14 by Rolando.Caloca

	DR - Do not stall when creating shaders on Vulkan

Change 3345722 on 2017/03/14 by Chris.Bunner

	PR #3357: MinimalAPI add to many material expressions (Contributed by DeanoC)

	#jira UE-42752

Change 3345723 on 2017/03/14 by Chris.Bunner

	Reduce log verbosity causing spamming during  landscape editing.

	#jira UE-42714

Change 3345725 on 2017/03/14 by Chris.Bunner

	[Duplicate 3341860] Fixed material translation error with multiple connections from custom interpolator nodes.

Change 3345726 on 2017/03/14 by Chris.Bunner

	Typo fixes.

Change 3345732 on 2017/03/14 by Rolando.Caloca

	DR - Decouple vertex declaration off BSS

Change 3345746 on 2017/03/14 by Chris.Bunner

	Added sign() intrinsic material graph node and delisted material function workaround.

Change 3346042 on 2017/03/14 by Chris.Bunner

	Implement missing size query interface for FRenderTargetResources.

	#jira UE-41672

Change 3346387 on 2017/03/14 by Daniel.Wright

	[Copy] Added VolumetricScatteringIntensity to particle lights

Change 3346389 on 2017/03/14 by Daniel.Wright

	[Copy] Clamp Volumetric material attributes to fp16 range to avoid INFs
	Disable volumetric fog when the fog show flag is disabled

Change 3346392 on 2017/03/14 by Daniel.Wright

	[Copy] Fixed skylight being much too bright on volumetric fog

Change 3346406 on 2017/03/14 by Daniel.Wright

	[Copy] CSM resolution is now controlled by r.Shadow.MaxCSMResolution.
	* Changed HighPC to use 1024 MaxShadowResolution (max for all non-CSM shadows), saves 60Mb in Fortnite

Change 3346412 on 2017/03/14 by Daniel.Wright

	[Copy] TexCreate_ReduceMemoryWithTilingMode for translucency lighting 3d textures, saves 13Mb

Change 3346414 on 2017/03/14 by Daniel.Wright

	[Copy] TexCreate_ReduceMemoryWithTilingMode for volumetric fog 3d textures, saves 13Mb

Change 3346415 on 2017/03/14 by Daniel.Wright

	[Copy] Missing file from cl 3338451

Change 3346421 on 2017/03/14 by Daniel.Wright

	[Copy] Fixed NaNs in volumetric fog due to rendering when height fog is disabled
	* Volumetric fog converts NaNs to black now so they don't spread

Change 3346422 on 2017/03/14 by Daniel.Wright

	[Copy] Fixed NaN in volumetric fog with low density values

Change 3346423 on 2017/03/14 by Daniel.Wright

	[Copy] Changed default VolumetricFogScatteringDistribution to .2

Change 3346430 on 2017/03/14 by Daniel.Wright

	[Copy] New translucent material option to compute fog per pixel instead of the default per vertex

Change 3346432 on 2017/03/14 by Daniel.Wright

	[Copy] Moved Volumetric Fog parameters to view uniform buffer for translucency pass
	Fixed lifetimes of temporary Volumetric Fog render targets

Change 3346526 on 2017/03/14 by Daniel.Wright

	[Copy] Volumetric Fog supports point and spot light shadows
	* These lights are injected separately so that per-light resources can be bound (shadow depth map, static shadow depth map)
	* Forward lighting of local lights can be forced with 'r.VolumetricFog.InjectShadowedLightsSeparately 0'
	* Shadowed lights come at a cost: 2.9ms for volumetric fog on 970 -> 4.2ms with shadowing

Change 3347053 on 2017/03/15 by Rolando.Caloca

	DR - android compile fix

Change 3347384 on 2017/03/15 by Rolando.Caloca

	DR - Fix merge issue

Change 3347643 on 2017/03/15 by Marcus.Wassmer

	Fix some bugs with the 'disable stationary skylight ffor the project' feature.
	Fixes lighting in Persona on Paragon.

Change 3347979 on 2017/03/15 by Rolando.Caloca

	DR - Allow to automatically apply cached rendertargets to PSO initializer

Change 3348024 on 2017/03/15 by Rolando.Caloca

	DR - Remove NullPS on Vulkan to avoid deadlock

Change 3348303 on 2017/03/15 by Rolando.Caloca

	DR - Fix for debugging SCW with material SRT

Change 3348357 on 2017/03/15 by Marcus.Wassmer

	Fix stencildither and a stencilref bug that was probably breaking decals sometimes.

Change 3348549 on 2017/03/15 by Marcus.Wassmer

	Hopefully fix static analysis for potential nullptr access.

Change 3348614 on 2017/03/15 by Marcus.Wassmer

	Duplicate some switch changes to fix crash on launch.

Change 3349369 on 2017/03/16 by Gil.Gribb

	Fixed botched merge

Change 3349947 on 2017/03/16 by Rolando.Caloca

	DR - Fix for mismatched primitive type

Change 3349956 on 2017/03/16 by Benjamin.Hyder

	initial updates to TM-DistanceFields map

Change 3350151 on 2017/03/16 by Rolando.Caloca

	DR - Fix UT compile issue

Change 3350155 on 2017/03/16 by Rolando.Caloca

	DR - Catch mismatched primitive type on PSOs on D3D11

Change 3350192 on 2017/03/16 by Daniel.Wright

	Fix for point light shadow depths rendering with wrong cull mode due to PSO refactor

Change 3350736 on 2017/03/16 by Daniel.Wright

	Fixed formatting from merge

Change 3350881 on 2017/03/16 by Rolando.Caloca

	DR - Fix texture arrays as UAVs on Metal

Change 3350927 on 2017/03/16 by Rolando.Caloca

	DR - Fix warning

Change 3350935 on 2017/03/16 by Daniel.Wright

	Fix for materials with non-Surface domains being skipped in mesh passes

Change 3351583 on 2017/03/17 by Marcus.Wassmer

	Fix clang platforms

Change 3351917 on 2017/03/17 by Marcus.Wassmer

	Fix linux compile

Change 3351973 on 2017/03/17 by Marcus.Wassmer

	Fix mismatched rendertargetformat

Change 3352038 on 2017/03/17 by Daniel.Wright

	Enabled GetAndOrCreateGraphicsPipelineState ensures in Development for testing

Change 3352110 on 2017/03/17 by Marcus.Wassmer

	Fix missing RT PSO apply

Change 3352695 on 2017/03/17 by Arne.Schober

	DR - Remove PSO Rendertarget check in DX12 Resolve with Shader.
	#RB Rolando.Caloca

Change 3352960 on 2017/03/17 by Arne.Schober

	DR - Fix some things that slipped trough the PSO merge
	#RB none

Change 3353150 on 2017/03/18 by Rolando.Caloca

	DR - compile fix

Change 3353205 on 2017/03/18 by Arne.Schober

	DR - Fix Incremental Compile and PS4 runtime error where CMASK is not allowed for ThickTile Mode

	#RB none

Change 3353207 on 2017/03/18 by Arne.Schober

	DR - Fix Confusion

	#RB none

Change 3355183 on 2017/03/20 by Nick.Bullard

	Fixed up Content orginzation for Decals automation tests in EngineTest

Change 3355627 on 2017/03/20 by Arne.Schober

	DR - [UE-43094] - removed ensure in comporiton graph as control of the clear color cannot be gurantueed.

Change 3356342 on 2017/03/21 by Marcus.Wassmer

	Fix clang errors

Change 3356591 on 2017/03/21 by Arne.Schober

	DR - Fix ensure message
	#RB none

Change 3356873 on 2017/03/21 by Arne.Schober

	DR - Fix comparission of undefined values in RendertargetApply Check

Change 3357261 on 2017/03/21 by Marcus.Wassmer

	Fix LinuxEditor compile

Change 3357294 on 2017/03/21 by Marcus.Wassmer

	Add missing SSE functions

Change 3357351 on 2017/03/21 by Frank.Fella

	Fix win32 and linux compiler errors

Change 3357370 on 2017/03/21 by Arne.Schober

	DR - disable ensure in test builds

	#RB Marcus.Wassmer

[CL 3357449 by Marcus Wassmer in Main branch]
2017-03-21 17:46:52 -04:00

2445 lines
98 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ShadowDepthRendering.cpp: Shadow depth rendering implementation
=============================================================================*/
#include "CoreMinimal.h"
#include "Stats/Stats.h"
#include "Misc/MemStack.h"
#include "RHIDefinitions.h"
#include "HAL/IConsoleManager.h"
#include "Async/TaskGraphInterfaces.h"
#include "RHI.h"
#include "HitProxies.h"
#include "ShaderParameters.h"
#include "RenderResource.h"
#include "RendererInterface.h"
#include "PrimitiveViewRelevance.h"
#include "UniformBuffer.h"
#include "Shader.h"
#include "StaticBoundShaderState.h"
#include "SceneUtils.h"
#include "Materials/Material.h"
#include "RHIStaticStates.h"
#include "PostProcess/SceneRenderTargets.h"
#include "GlobalShader.h"
#include "MaterialShaderType.h"
#include "MaterialShader.h"
#include "DrawingPolicy.h"
#include "MeshMaterialShader.h"
#include "ShaderBaseClasses.h"
#include "ShadowRendering.h"
#include "SceneRendering.h"
#include "LightPropagationVolume.h"
#include "ScenePrivate.h"
#include "PostProcess/SceneFilterRendering.h"
#include "ScreenRendering.h"
#include "ClearQuad.h"
#include "PipelineStateCache.h"
DECLARE_FLOAT_COUNTER_STAT(TEXT("Shadow Depths"), Stat_GPU_ShadowDepths, STATGROUP_GPU);
/**
* A vertex shader for rendering the depth of a mesh.
*/
class FShadowDepthVS : public FMeshMaterialShader
{
DECLARE_SHADER_TYPE(FShadowDepthVS,MeshMaterial);
public:
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
return false;
}
FShadowDepthVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FMeshMaterialShader(Initializer)
{
ShadowParameters.Bind(Initializer.ParameterMap);
ShadowViewProjectionMatrices.Bind(Initializer.ParameterMap, TEXT("ShadowViewProjectionMatrices"));
MeshVisibleToFace.Bind(Initializer.ParameterMap, TEXT("MeshVisibleToFace"));
InstanceCount.Bind(Initializer.ParameterMap, TEXT("InstanceCount"));
}
FShadowDepthVS() {}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
Ar << ShadowParameters;
Ar << ShadowViewProjectionMatrices;
Ar << MeshVisibleToFace;
Ar << InstanceCount;
return bShaderHasOutdatedParameters;
}
void SetParameters(
FRHICommandList& RHICmdList,
const FMaterialRenderProxy* MaterialRenderProxy,
const FMaterial& Material,
const FSceneView& View,
const FProjectedShadowInfo* ShadowInfo
)
{
FMeshMaterialShader::SetParameters(RHICmdList, GetVertexShader(),MaterialRenderProxy,Material,View,View.ViewUniformBuffer,ESceneRenderTargetsMode::DontSet);
ShadowParameters.SetVertexShader(RHICmdList, this, View, ShadowInfo, MaterialRenderProxy);
if(ShadowViewProjectionMatrices.IsBound())
{
const FMatrix Translation = FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation());
FMatrix TranslatedShadowViewProjectionMatrices[6];
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
{
// Have to apply the pre-view translation to the view - projection matrices
TranslatedShadowViewProjectionMatrices[FaceIndex] = Translation * ShadowInfo->OnePassShadowViewProjectionMatrices[FaceIndex];
}
// Set the view projection matrices that will transform positions from world to cube map face space
SetShaderValueArray<FVertexShaderRHIParamRef, FMatrix>(RHICmdList,
GetVertexShader(),
ShadowViewProjectionMatrices,
TranslatedShadowViewProjectionMatrices,
ARRAY_COUNT(TranslatedShadowViewProjectionMatrices)
);
}
}
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FDrawingPolicyRenderState& DrawRenderState,FProjectedShadowInfo const* ShadowInfo)
{
FMeshMaterialShader::SetMesh(RHICmdList, GetVertexShader(),VertexFactory,View,Proxy,BatchElement,DrawRenderState);
if (MeshVisibleToFace.IsBound())
{
const FBoxSphereBounds& PrimitiveBounds = Proxy->GetBounds();
FVector4 MeshVisibleToFaceValue[6];
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
{
MeshVisibleToFaceValue[FaceIndex] = FVector4(ShadowInfo->OnePassShadowFrustums[FaceIndex].IntersectBox(PrimitiveBounds.Origin,PrimitiveBounds.BoxExtent), 0, 0, 0);
}
// Set the view projection matrices that will transform positions from world to cube map face space
SetShaderValueArray<FVertexShaderRHIParamRef, FVector4>(
RHICmdList,
GetVertexShader(),
MeshVisibleToFace,
MeshVisibleToFaceValue,
ARRAY_COUNT(MeshVisibleToFaceValue)
);
}
}
void SetDrawInstanceCount(FRHICommandList& RHICmdList, uint32 NumInstances)
{
if(InstanceCount.IsBound())
{
SetShaderValue(RHICmdList, GetVertexShader(), InstanceCount, NumInstances);
}
}
private:
FShadowDepthShaderParameters ShadowParameters;
FShaderParameter ShadowViewProjectionMatrices;
FShaderParameter MeshVisibleToFace;
FShaderParameter InstanceCount;
};
enum EShadowDepthVertexShaderMode
{
VertexShadowDepth_PerspectiveCorrect,
VertexShadowDepth_OutputDepth,
VertexShadowDepth_OnePassPointLight
};
/**
* A vertex shader for rendering the depth of a mesh.
*/
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap, bool bUsePositionOnlyStream, bool bIsForGeometryShader=false>
class TShadowDepthVS : public FShadowDepthVS
{
DECLARE_SHADER_TYPE(TShadowDepthVS,MeshMaterial);
public:
TShadowDepthVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FShadowDepthVS(Initializer)
{
}
TShadowDepthVS() {}
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
if (bIsForGeometryShader && !RHISupportsGeometryShaders(Platform) && !RHISupportsVertexShaderLayer(Platform))
{
return false;
}
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
// Compile for special engine materials.
if(bRenderReflectiveShadowMap)
{
// Reflective shadow map shaders must be compiled for every material because they access the material normal
return !bUsePositionOnlyStream
// Don't render ShadowDepth for translucent unlit materials, unless we're injecting emissive
&& ((!IsTranslucentBlendMode(Material->GetBlendMode()) && Material->GetShadingModel() != MSM_Unlit) || Material->ShouldInjectEmissiveIntoLPV()
|| Material->ShouldBlockGI() )
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
}
else
{
return (Material->IsSpecialEngineMaterial()
// Masked and WPO materials need their shaders but cannot be used with a position only stream.
|| ((!Material->WritesEveryPixel(true) || Material->MaterialMayModifyMeshPosition()) && !bUsePositionOnlyStream))
// Only compile one pass point light shaders for feature levels >= SM4
&& (ShaderMode != VertexShadowDepth_OnePassPointLight || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
// Only compile position-only shaders for vertex factories that support it.
&& (!bUsePositionOnlyStream || VertexFactoryType->SupportsPositionOnly())
// Don't render ShadowDepth for translucent unlit materials
&& (!IsTranslucentBlendMode(Material->GetBlendMode()) && Material->GetShadingModel() != MSM_Unlit)
// Only compile perspective correct light shaders for feature levels >= SM4
&& (ShaderMode != VertexShadowDepth_PerspectiveCorrect || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4));
}
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
{
FShadowDepthVS::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == VertexShadowDepth_PerspectiveCorrect));
OutEnvironment.SetDefine(TEXT("ONEPASS_POINTLIGHT_SHADOW"), (uint32)(ShaderMode == VertexShadowDepth_OnePassPointLight));
OutEnvironment.SetDefine(TEXT("REFLECTIVE_SHADOW_MAP"), (uint32)bRenderReflectiveShadowMap);
OutEnvironment.SetDefine(TEXT("POSITION_ONLY"), (uint32)bUsePositionOnlyStream);
if( bIsForGeometryShader )
{
OutEnvironment.CompilerFlags.Add( CFLAG_VertexToGeometryShader );
}
}
};
/**
* A Hull shader for rendering the depth of a mesh.
*/
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
class TShadowDepthHS : public FBaseHS
{
DECLARE_SHADER_TYPE(TShadowDepthHS,MeshMaterial);
public:
TShadowDepthHS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FBaseHS(Initializer)
{}
TShadowDepthHS() {}
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
// Re-use ShouldCache from vertex shader
return FBaseHS::ShouldCache(Platform, Material, VertexFactoryType)
&& TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ShouldCache(Platform, Material, VertexFactoryType);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
{
// Re-use compilation env from vertex shader
TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
}
};
/**
* A domain shader for rendering the depth of a mesh.
*/
class FShadowDepthDS : public FBaseDS
{
DECLARE_SHADER_TYPE(FShadowDepthDS,MeshMaterial);
public:
FShadowDepthDS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FBaseDS(Initializer)
{
ShadowParameters.Bind(Initializer.ParameterMap);
ShadowViewProjectionMatrices.Bind(Initializer.ParameterMap, TEXT("ShadowViewProjectionMatrices"));
}
FShadowDepthDS() {}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FBaseDS::Serialize(Ar);
Ar << ShadowParameters;
Ar << ShadowViewProjectionMatrices;
return bShaderHasOutdatedParameters;
}
void SetParameters(
FRHICommandList& RHICmdList,
const FMaterialRenderProxy* MaterialRenderProxy,
const FSceneView& View,
const FProjectedShadowInfo* ShadowInfo
)
{
FBaseDS::SetParameters(RHICmdList, MaterialRenderProxy, View);
ShadowParameters.SetDomainShader(RHICmdList, this, View, ShadowInfo, MaterialRenderProxy);
if(ShadowViewProjectionMatrices.IsBound())
{
const FMatrix Translation = FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation());
FMatrix TranslatedShadowViewProjectionMatrices[6];
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
{
// Have to apply the pre-view translation to the view - projection matrices
TranslatedShadowViewProjectionMatrices[FaceIndex] = Translation * ShadowInfo->OnePassShadowViewProjectionMatrices[FaceIndex];
}
// Set the view projection matrices that will transform positions from world to cube map face space
SetShaderValueArray<FDomainShaderRHIParamRef, FMatrix>(RHICmdList,
GetDomainShader(),
ShadowViewProjectionMatrices,
TranslatedShadowViewProjectionMatrices,
ARRAY_COUNT(TranslatedShadowViewProjectionMatrices)
);
}
}
private:
FShadowDepthShaderParameters ShadowParameters;
FShaderParameter ShadowViewProjectionMatrices;
};
/**
* A Domain shader for rendering the depth of a mesh.
*/
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
class TShadowDepthDS : public FShadowDepthDS
{
DECLARE_SHADER_TYPE(TShadowDepthDS,MeshMaterial);
public:
TShadowDepthDS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FShadowDepthDS(Initializer)
{}
TShadowDepthDS() {}
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
// Re-use ShouldCache from vertex shader
return FBaseDS::ShouldCache(Platform, Material, VertexFactoryType)
&& TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ShouldCache(Platform, Material, VertexFactoryType);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
{
// Re-use compilation env from vertex shader
TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
}
};
/** Geometry shader that allows one pass point light shadows by cloning triangles to all faces of the cube map. */
class FOnePassPointShadowDepthGS : public FMeshMaterialShader
{
DECLARE_SHADER_TYPE(FOnePassPointShadowDepthGS,MeshMaterial);
public:
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
return RHISupportsGeometryShaders(Platform) && TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true>::ShouldCache(Platform, Material, VertexFactoryType);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
{
FMeshMaterialShader::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
}
FOnePassPointShadowDepthGS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FMeshMaterialShader(Initializer)
{
ShadowViewProjectionMatrices.Bind(Initializer.ParameterMap, TEXT("ShadowViewProjectionMatrices"));
MeshVisibleToFace.Bind(Initializer.ParameterMap, TEXT("MeshVisibleToFace"));
}
FOnePassPointShadowDepthGS() {}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
Ar << ShadowViewProjectionMatrices;
Ar << MeshVisibleToFace;
return bShaderHasOutdatedParameters;
}
void SetParameters(
FRHICommandList& RHICmdList,
const FSceneView& View,
const FProjectedShadowInfo* ShadowInfo
)
{
FMaterialShader::SetViewParameters(RHICmdList, GetGeometryShader(),View,View.ViewUniformBuffer);
const FMatrix Translation = FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation());
FMatrix TranslatedShadowViewProjectionMatrices[6];
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
{
// Have to apply the pre-view translation to the view - projection matrices
TranslatedShadowViewProjectionMatrices[FaceIndex] = Translation * ShadowInfo->OnePassShadowViewProjectionMatrices[FaceIndex];
}
// Set the view projection matrices that will transform positions from world to cube map face space
SetShaderValueArray<FGeometryShaderRHIParamRef, FMatrix>(
RHICmdList,
GetGeometryShader(),
ShadowViewProjectionMatrices,
TranslatedShadowViewProjectionMatrices,
ARRAY_COUNT(TranslatedShadowViewProjectionMatrices)
);
}
void SetMesh(FRHICommandList& RHICmdList, const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FProjectedShadowInfo* ShadowInfo, const FSceneView& View)
{
if (MeshVisibleToFace.IsBound())
{
const FBoxSphereBounds& PrimitiveBounds = PrimitiveSceneProxy->GetBounds();
FVector4 MeshVisibleToFaceValue[6];
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
{
MeshVisibleToFaceValue[FaceIndex] = FVector4(ShadowInfo->OnePassShadowFrustums[FaceIndex].IntersectBox(PrimitiveBounds.Origin,PrimitiveBounds.BoxExtent), 0, 0, 0);
}
// Set the view projection matrices that will transform positions from world to cube map face space
SetShaderValueArray<FGeometryShaderRHIParamRef, FVector4>(
RHICmdList,
GetGeometryShader(),
MeshVisibleToFace,
MeshVisibleToFaceValue,
ARRAY_COUNT(MeshVisibleToFaceValue)
);
}
}
private:
FShaderParameter ShadowViewProjectionMatrices;
FShaderParameter MeshVisibleToFace;
};
#define IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(ShaderMode,bRenderReflectiveShadowMap) \
typedef TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false> TShadowDepthVS##ShaderMode##bRenderReflectiveShadowMap; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVS##ShaderMode##bRenderReflectiveShadowMap,TEXT("ShadowDepthVertexShader"),TEXT("Main"),SF_Vertex); \
typedef TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false, true> TShadowDepthVSForGS##ShaderMode##bRenderReflectiveShadowMap; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSForGS##ShaderMode##bRenderReflectiveShadowMap,TEXT("ShadowDepthVertexShader"),TEXT("MainForGS"),SF_Vertex); \
typedef TShadowDepthHS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthHS##ShaderMode##bRenderReflectiveShadowMap; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthHS##ShaderMode##bRenderReflectiveShadowMap,TEXT("ShadowDepthVertexShader"),TEXT("MainHull"),SF_Hull); \
typedef TShadowDepthDS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthDS##ShaderMode##bRenderReflectiveShadowMap; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthDS##ShaderMode##bRenderReflectiveShadowMap,TEXT("ShadowDepthVertexShader"),TEXT("MainDomain"),SF_Domain);
IMPLEMENT_SHADER_TYPE(,FOnePassPointShadowDepthGS,TEXT("ShadowDepthVertexShader"),TEXT("MainOnePassPointLightGS"),SF_Geometry);
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_PerspectiveCorrect, true);
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_PerspectiveCorrect, false);
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OutputDepth, true);
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OutputDepth, false);
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OnePassPointLight, false);
// Position only vertex shaders.
typedef TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, true> TShadowDepthVSVertexShadowDepth_PerspectiveCorrectPositionOnly;
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSVertexShadowDepth_PerspectiveCorrectPositionOnly,TEXT("ShadowDepthVertexShader"),TEXT("PositionOnlyMain"),SF_Vertex);
typedef TShadowDepthVS<VertexShadowDepth_OutputDepth, false, true> TShadowDepthVSVertexShadowDepth_OutputDepthPositionOnly;
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSVertexShadowDepth_OutputDepthPositionOnly,TEXT("ShadowDepthVertexShader"),TEXT("PositionOnlyMain"),SF_Vertex);
typedef TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true> TShadowDepthVSVertexShadowDepth_OnePassPointLightPositionOnly;
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSVertexShadowDepth_OnePassPointLightPositionOnly,TEXT("ShadowDepthVertexShader"),TEXT("PositionOnlyMain"),SF_Vertex);
typedef TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true, true> TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightPositionOnly;
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightPositionOnly,TEXT("ShadowDepthVertexShader"),TEXT("PositionOnlyMainForGS"),SF_Vertex);
/**
* A pixel shader for rendering the depth of a mesh.
*/
template <bool bRenderReflectiveShadowMap>
class TShadowDepthBasePS : public FMeshMaterialShader
{
DECLARE_SHADER_TYPE(TShadowDepthBasePS,MeshMaterial);
public:
TShadowDepthBasePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FMeshMaterialShader(Initializer)
{
ShadowParams.Bind(Initializer.ParameterMap,TEXT("ShadowParams"));
ReflectiveShadowMapTextureResolution.Bind(Initializer.ParameterMap,TEXT("ReflectiveShadowMapTextureResolution"));
ProjectionMatrixParameter.Bind(Initializer.ParameterMap,TEXT("ProjectionMatrix"));
GvListBuffer.Bind(Initializer.ParameterMap,TEXT("RWGvListBuffer"));
GvListHeadBuffer.Bind(Initializer.ParameterMap,TEXT("RWGvListHeadBuffer"));
VplListBuffer.Bind(Initializer.ParameterMap,TEXT("RWVplListBuffer"));
VplListHeadBuffer.Bind(Initializer.ParameterMap,TEXT("RWVplListHeadBuffer"));
}
TShadowDepthBasePS() {}
void SetParameters(
FRHICommandList& RHICmdList,
const FMaterialRenderProxy* MaterialRenderProxy,
const FMaterial& Material,
const FSceneView& View,
const FProjectedShadowInfo* ShadowInfo
)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FMeshMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialRenderProxy, Material, View, View.ViewUniformBuffer, ESceneRenderTargetsMode::DontSet);
SetShaderValue(RHICmdList, ShaderRHI, ShadowParams, FVector2D(ShadowInfo->GetShaderDepthBias(), ShadowInfo->InvMaxSubjectDepth));
if(bRenderReflectiveShadowMap)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// LPV also propagates light transmission (for transmissive materials)
SetShaderValue(RHICmdList, ShaderRHI,ReflectiveShadowMapTextureResolution,
FVector2D(SceneContext.GetReflectiveShadowMapResolution(),
SceneContext.GetReflectiveShadowMapResolution()));
SetShaderValue(
RHICmdList,
ShaderRHI,
ProjectionMatrixParameter,
FTranslationMatrix(ShadowInfo->PreShadowTranslation - View.ViewMatrices.GetPreViewTranslation()) * ShadowInfo->SubjectAndReceiverMatrix
);
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
if(ViewState)
{
const FLightPropagationVolume* Lpv = ViewState->GetLightPropagationVolume(View.GetFeatureLevel());
if(Lpv)
{
SetUniformBufferParameter(RHICmdList, ShaderRHI, GetUniformBufferParameter<FLpvWriteUniformBufferParameters>(), Lpv->GetWriteUniformBuffer());
}
}
}
}
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FDrawingPolicyRenderState& DrawRenderState)
{
FMeshMaterialShader::SetMesh(RHICmdList, GetPixelShader(),VertexFactory,View,Proxy,BatchElement,DrawRenderState);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
Ar << ShadowParams;
Ar << ReflectiveShadowMapTextureResolution;
Ar << ProjectionMatrixParameter;
Ar << GvListBuffer;
Ar << GvListHeadBuffer;
Ar << VplListBuffer;
Ar << VplListHeadBuffer;
return bShaderHasOutdatedParameters;
}
private:
FShaderParameter ShadowParams;
FShaderParameter ReflectiveShadowMapTextureResolution;
FShaderParameter ProjectionMatrixParameter;
FRWShaderParameter GvListBuffer;
FRWShaderParameter GvListHeadBuffer;
FRWShaderParameter VplListBuffer;
FRWShaderParameter VplListHeadBuffer;
};
enum EShadowDepthPixelShaderMode
{
PixelShadowDepth_NonPerspectiveCorrect,
PixelShadowDepth_PerspectiveCorrect,
PixelShadowDepth_OnePassPointLight
};
template <EShadowDepthPixelShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
class TShadowDepthPS : public TShadowDepthBasePS<bRenderReflectiveShadowMap>
{
DECLARE_SHADER_TYPE(TShadowDepthPS, MeshMaterial);
public:
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
{
if (!IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
{
return (Material->IsSpecialEngineMaterial()
// Only compile for masked or lit translucent materials
|| !Material->WritesEveryPixel(true))
&& ShaderMode == PixelShadowDepth_NonPerspectiveCorrect
// Don't render ShadowDepth for translucent unlit materials
&& (!IsTranslucentBlendMode(Material->GetBlendMode()) && Material->GetShadingModel() != MSM_Unlit)
&& !bRenderReflectiveShadowMap;
}
if ( bRenderReflectiveShadowMap )
{
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
// Reflective shadow map shaders must be compiled for every material because they access the material normal
return
// Only compile one pass point light shaders for feature levels >= SM4
( (!IsTranslucentBlendMode(Material->GetBlendMode()) && Material->GetShadingModel() != MSM_Unlit) || Material->ShouldInjectEmissiveIntoLPV() || Material->ShouldBlockGI() )
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
}
else
{
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
return (Material->IsSpecialEngineMaterial()
// Only compile for masked or lit translucent materials
|| !Material->WritesEveryPixel(true)
|| (Material->MaterialMayModifyMeshPosition() && Material->IsUsedWithInstancedStaticMeshes())
// Perspective correct rendering needs a pixel shader and WPO materials can't be overridden with default material.
|| (ShaderMode == PixelShadowDepth_PerspectiveCorrect && Material->MaterialMayModifyMeshPosition()))
// Only compile one pass point light shaders for feature levels >= SM4
&& (ShaderMode != PixelShadowDepth_OnePassPointLight || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
// Don't render ShadowDepth for translucent unlit materials
&& (!IsTranslucentBlendMode(Material->GetBlendMode()) && Material->GetShadingModel() != MSM_Unlit)
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
{
TShadowDepthBasePS<bRenderReflectiveShadowMap>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == PixelShadowDepth_PerspectiveCorrect));
OutEnvironment.SetDefine(TEXT("ONEPASS_POINTLIGHT_SHADOW"), (uint32)(ShaderMode == PixelShadowDepth_OnePassPointLight));
OutEnvironment.SetDefine(TEXT("REFLECTIVE_SHADOW_MAP"), (uint32)bRenderReflectiveShadowMap);
}
TShadowDepthPS()
{
}
TShadowDepthPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: TShadowDepthBasePS<bRenderReflectiveShadowMap>(Initializer)
{
}
};
// typedef required to get around macro expansion failure due to commas in template argument list for TShadowDepthPixelShader
#define IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(ShaderMode, bRenderReflectiveShadowMap) \
typedef TShadowDepthPS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthPS##ShaderMode##bRenderReflectiveShadowMap; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthPS##ShaderMode##bRenderReflectiveShadowMap,TEXT("ShadowDepthPixelShader"),TEXT("Main"),SF_Pixel);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_NonPerspectiveCorrect, true);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_NonPerspectiveCorrect, false);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_PerspectiveCorrect, true);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_PerspectiveCorrect, false);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_OnePassPointLight, true);
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_OnePassPointLight, false);
/**
* Overrides a material used for shadow depth rendering with the default material when appropriate.
* Overriding in this manner can reduce state switches and the number of shaders that have to be compiled.
* This logic needs to stay in sync with shadow depth shader ShouldCache logic.
*/
void OverrideWithDefaultMaterialForShadowDepth(
const FMaterialRenderProxy*& InOutMaterialRenderProxy,
const FMaterial*& InOutMaterialResource,
bool bReflectiveShadowmap,
ERHIFeatureLevel::Type InFeatureLevel)
{
// Override with the default material when possible.
if (InOutMaterialResource->WritesEveryPixel(true) && // Don't override masked materials.
!InOutMaterialResource->MaterialModifiesMeshPosition_RenderThread() && // Don't override materials using world position offset.
!bReflectiveShadowmap) // Don't override when rendering reflective shadow maps.
{
const FMaterialRenderProxy* DefaultProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy(false);
const FMaterial* DefaultMaterialResource = DefaultProxy->GetMaterial(InFeatureLevel);
// Override with the default material for opaque materials that don't modify mesh position.
InOutMaterialRenderProxy = DefaultProxy;
InOutMaterialResource = DefaultMaterialResource;
}
}
/*-----------------------------------------------------------------------------
FShadowDepthDrawingPolicy
-----------------------------------------------------------------------------*/
template <bool bRenderingReflectiveShadowMaps>
void FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::UpdateElementState(FShadowStaticMeshElement& State, ERHIFeatureLevel::Type InFeatureLevel)
{
FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(*State.Mesh);
OverrideSettings.MeshOverrideFlags |= State.bIsTwoSided ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
// can be optimized
*this = FShadowDepthDrawingPolicy(
State.MaterialResource,
bDirectionalLight,
bOnePassPointLightShadow,
bPreShadow,
OverrideSettings,
InFeatureLevel,
State.Mesh->VertexFactory,
State.RenderProxy,
State.Mesh->ReverseCulling);
}
template <bool bRenderingReflectiveShadowMaps>
FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::FShadowDepthDrawingPolicy(
const FMaterial* InMaterialResource,
bool bInDirectionalLight,
bool bInOnePassPointLightShadow,
bool bInPreShadow,
const FMeshDrawingPolicyOverrideSettings& InOverrideSettings,
ERHIFeatureLevel::Type InFeatureLevel,
const FVertexFactory* InVertexFactory,
const FMaterialRenderProxy* InMaterialRenderProxy,
bool bInReverseCulling
):
FMeshDrawingPolicy(InVertexFactory,InMaterialRenderProxy,*InMaterialResource,InOverrideSettings,DVSM_None),
GeometryShader(NULL),
FeatureLevel(InFeatureLevel),
bDirectionalLight(bInDirectionalLight),
bReverseCulling(bInReverseCulling),
bOnePassPointLightShadow(bInOnePassPointLightShadow),
bPreShadow(bInPreShadow)
{
check(!bInOnePassPointLightShadow || !bRenderingReflectiveShadowMaps);
if(!InVertexFactory)
{
// dummy object, needs call to UpdateElementState() to be fully initialized
return;
}
// Use perspective correct shadow depths for shadow types which typically render low poly meshes into the shadow depth buffer.
// Depth will be interpolated to the pixel shader and written out, which disables HiZ and double speed Z.
// Directional light shadows use an ortho projection and can use the non-perspective correct path without artifacts.
// One pass point lights don't output a linear depth, so they are already perspective correct.
const bool bUsePerspectiveCorrectShadowDepths = !bInDirectionalLight && !bInOnePassPointLightShadow;
HullShader = NULL;
DomainShader = NULL;
FVertexFactoryType* VFType = InVertexFactory->GetType();
const bool bInitializeTessellationShaders =
MaterialResource->GetTessellationMode() != MTM_NoTessellation
&& RHISupportsTessellation(GShaderPlatformForFeatureLevel[InFeatureLevel])
&& VFType->SupportsTessellationShaders();
bUsePositionOnlyVS = !bRenderingReflectiveShadowMaps
&& VertexFactory->SupportsPositionOnlyStream()
&& MaterialResource->WritesEveryPixel(true)
&& !MaterialResource->MaterialModifiesMeshPosition_RenderThread();
// Vertex related shaders
if (bOnePassPointLightShadow)
{
if (bUsePositionOnlyVS)
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true, true> >(VFType);
}
else
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true> >(VFType);
}
if(RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[InFeatureLevel]))
{
// Use the geometry shader which will clone output triangles to all faces of the cube map
GeometryShader = MaterialResource->GetShader<FOnePassPointShadowDepthGS>(VFType);
}
if(bInitializeTessellationShaders)
{
HullShader = MaterialResource->GetShader<TShadowDepthHS<VertexShadowDepth_OnePassPointLight, false> >(VFType);
DomainShader = MaterialResource->GetShader<TShadowDepthDS<VertexShadowDepth_OnePassPointLight, false> >(VFType);
}
}
else if (bUsePerspectiveCorrectShadowDepths)
{
if (bRenderingReflectiveShadowMaps)
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, true, false> >(VFType);
}
else
{
if (bUsePositionOnlyVS)
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, true> >(VFType);
}
else
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, false> >(VFType);
}
}
if(bInitializeTessellationShaders)
{
HullShader = MaterialResource->GetShader<TShadowDepthHS<VertexShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
DomainShader = MaterialResource->GetShader<TShadowDepthDS<VertexShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
}
}
else
{
if (bRenderingReflectiveShadowMaps)
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, true, false> >(VFType);
if(bInitializeTessellationShaders)
{
HullShader = MaterialResource->GetShader<TShadowDepthHS<VertexShadowDepth_OutputDepth, true> >(VFType);
DomainShader = MaterialResource->GetShader<TShadowDepthDS<VertexShadowDepth_OutputDepth, true> >(VFType);
}
}
else
{
if (bUsePositionOnlyVS)
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, false, true> >(VFType);
}
else
{
VertexShader = MaterialResource->GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, false, false> >(VFType);
}
if(bInitializeTessellationShaders)
{
HullShader = MaterialResource->GetShader<TShadowDepthHS<VertexShadowDepth_OutputDepth, false> >(VFType);
DomainShader = MaterialResource->GetShader<TShadowDepthDS<VertexShadowDepth_OutputDepth, false> >(VFType);
}
}
}
// Pixel shaders
if (MaterialResource->WritesEveryPixel(true) && !bUsePerspectiveCorrectShadowDepths && !bRenderingReflectiveShadowMaps && VertexFactory->SupportsNullPixelShader())
{
// No pixel shader necessary.
PixelShader = NULL;
}
else
{
if (bUsePerspectiveCorrectShadowDepths)
{
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)MaterialResource->GetShader<TShadowDepthPS<PixelShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
}
else if (bOnePassPointLightShadow)
{
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)MaterialResource->GetShader<TShadowDepthPS<PixelShadowDepth_OnePassPointLight, false> >(VFType);
}
else
{
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)MaterialResource->GetShader<TShadowDepthPS<PixelShadowDepth_NonPerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
}
}
}
static void SetViewFlagsForShadowPass(FDrawingPolicyRenderState& DrawRenderState, const FSceneView& View, ERHIFeatureLevel::Type FeatureLevel, bool isTwoSided, bool isReflectiveShadowmap, bool isOnePassPointLightShadow)
{
// @TODO: only render directional light shadows as two sided, and only when blocking is enabled (required by geometry volume injection)
bool bIsTwoSided = isReflectiveShadowmap ? true : isTwoSided; //PolicyContext.ShadowInfo->bReflectiveShadowmap
// Invert culling order when mobile HDR == false.
auto ShaderPlatform = GShaderPlatformForFeatureLevel[FeatureLevel];
static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR"));
check(MobileHDRCvar);
const bool bPlatformReversesCulling = (RHINeedsToSwitchVerticalAxis(ShaderPlatform) && MobileHDRCvar->GetValueOnAnyThread() == 0);
DrawRenderState.ModifyViewOverrideFlags() |= (bIsTwoSided) ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
DrawRenderState.ModifyViewOverrideFlags() ^= (XOR(bPlatformReversesCulling, isOnePassPointLightShadow)) ? EDrawingPolicyOverrideFlags::ReverseCullMode : EDrawingPolicyOverrideFlags::None;
}
template <bool bRenderingReflectiveShadowMaps>
void FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::SetSharedState(FRHICommandList& RHICmdList, const FDrawingPolicyRenderState& DrawRenderState, const FSceneView* View, const ContextDataType PolicyContext) const
{
checkSlow(bDirectionalLight == PolicyContext.ShadowInfo->bDirectionalLight && bPreShadow == PolicyContext.ShadowInfo->bPreShadow);
VertexShader->SetParameters(RHICmdList, MaterialRenderProxy,*MaterialResource,*View,PolicyContext.ShadowInfo);
if (GeometryShader)
{
GeometryShader->SetParameters(RHICmdList, *View,PolicyContext.ShadowInfo);
}
if(HullShader && DomainShader)
{
HullShader->SetParameters(RHICmdList, MaterialRenderProxy,*View);
DomainShader->SetParameters(RHICmdList, MaterialRenderProxy,*View,PolicyContext.ShadowInfo);
}
if (PixelShader)
{
PixelShader->SetParameters(RHICmdList, MaterialRenderProxy,*MaterialResource,*View,PolicyContext.ShadowInfo);
}
// Set the shared mesh resources.
if (bUsePositionOnlyVS)
{
VertexFactory->SetPositionStream(RHICmdList);
}
else
{
FMeshDrawingPolicy::SetSharedState(RHICmdList, DrawRenderState, View, PolicyContext);
}
}
/**
* Create bound shader state using the vertex decl from the mesh draw policy
* as well as the shaders needed to draw the mesh
* @return new bound shader state object
*/
template <bool bRenderingReflectiveShadowMaps>
FBoundShaderStateInput FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::GetBoundShaderStateInput(ERHIFeatureLevel::Type InFeatureLevel) const
{
FVertexDeclarationRHIRef VertexDeclaration;
if (bUsePositionOnlyVS)
{
VertexDeclaration = VertexFactory->GetPositionDeclaration();
}
else
{
VertexDeclaration = FMeshDrawingPolicy::GetVertexDeclaration();
}
return FBoundShaderStateInput(
VertexDeclaration,
VertexShader->GetVertexShader(),
GETSAFERHISHADER_HULL(HullShader),
GETSAFERHISHADER_DOMAIN(DomainShader),
GETSAFERHISHADER_PIXEL(PixelShader),
GETSAFERHISHADER_GEOMETRY(GeometryShader));
}
template <bool bRenderingReflectiveShadowMaps>
void FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::SetMeshRenderState(
FRHICommandList& RHICmdList,
const FSceneView& View,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
const FMeshBatch& Mesh,
int32 BatchElementIndex,
const FDrawingPolicyRenderState& DrawRenderState,
const ElementDataType& ElementData,
const ContextDataType PolicyContext
) const
{
const FMeshBatchElement& BatchElement = Mesh.Elements[BatchElementIndex];
VertexShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState, PolicyContext.ShadowInfo);
if( HullShader && DomainShader )
{
HullShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState);
DomainShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState);
}
if (GeometryShader)
{
GeometryShader->SetMesh(RHICmdList, PrimitiveSceneProxy, PolicyContext.ShadowInfo, View);
}
if (PixelShader)
{
PixelShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState);
}
// Not calling FMeshDrawingPolicy::SetMeshRenderState as SetSharedState sets the rasterizer state
}
template <bool bRenderingReflectiveShadowMaps>
int32 CompareDrawingPolicy(const FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>& A,const FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>& B)
{
COMPAREDRAWINGPOLICYMEMBERS(VertexShader);
COMPAREDRAWINGPOLICYMEMBERS(HullShader);
COMPAREDRAWINGPOLICYMEMBERS(DomainShader);
COMPAREDRAWINGPOLICYMEMBERS(GeometryShader);
COMPAREDRAWINGPOLICYMEMBERS(PixelShader);
COMPAREDRAWINGPOLICYMEMBERS(VertexFactory);
COMPAREDRAWINGPOLICYMEMBERS(MaterialRenderProxy);
COMPAREDRAWINGPOLICYMEMBERS(bDirectionalLight);
COMPAREDRAWINGPOLICYMEMBERS(MeshPrimitiveType);
COMPAREDRAWINGPOLICYMEMBERS(bOnePassPointLightShadow);
COMPAREDRAWINGPOLICYMEMBERS(bUsePositionOnlyVS);
COMPAREDRAWINGPOLICYMEMBERS(bPreShadow);
return 0;
}
void FShadowDepthDrawingPolicyFactory::AddStaticMesh(FScene* Scene,FStaticMesh* StaticMesh)
{
if (StaticMesh->CastShadow)
{
const auto FeatureLevel = Scene->GetFeatureLevel();
const FMaterialRenderProxy* MaterialRenderProxy = StaticMesh->MaterialRenderProxy;
const FMaterial* Material = MaterialRenderProxy->GetMaterial(FeatureLevel);
const EBlendMode BlendMode = Material->GetBlendMode();
const EMaterialShadingModel ShadingModel = Material->GetShadingModel();
const bool bLightPropagationVolume = UseLightPropagationVolumeRT(FeatureLevel);
const bool bTwoSided = Material->IsTwoSided() || StaticMesh->PrimitiveSceneInfo->Proxy->CastsShadowAsTwoSided();
const bool bLitOpaque = !IsTranslucentBlendMode(BlendMode) && ShadingModel != MSM_Unlit;
FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(*StaticMesh);
OverrideSettings.MeshOverrideFlags |= bTwoSided ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
if (bLightPropagationVolume && ((!IsTranslucentBlendMode(BlendMode) && ShadingModel != MSM_Unlit) || Material->ShouldInjectEmissiveIntoLPV() || Material->ShouldBlockGI()))
{
// Add the static mesh to the shadow's subject draw list.
if ( StaticMesh->PrimitiveSceneInfo->Proxy->AffectsDynamicIndirectLighting() )
{
Scene->WholeSceneReflectiveShadowMapDrawList.AddMesh(
StaticMesh,
FShadowDepthDrawingPolicy<true>::ElementDataType(),
FShadowDepthDrawingPolicy<true>(
Material,
true,
false,
false,
OverrideSettings,
FeatureLevel,
StaticMesh->VertexFactory,
MaterialRenderProxy,
StaticMesh->ReverseCulling),
FeatureLevel
);
}
}
if ( bLitOpaque )
{
OverrideWithDefaultMaterialForShadowDepth(MaterialRenderProxy, Material, false, FeatureLevel);
// Add the static mesh to the shadow's subject draw list.
Scene->WholeSceneShadowDepthDrawList.AddMesh(
StaticMesh,
FShadowDepthDrawingPolicy<false>::ElementDataType(),
FShadowDepthDrawingPolicy<false>(
Material,
true,
false,
false,
OverrideSettings,
FeatureLevel,
StaticMesh->VertexFactory,
MaterialRenderProxy,
StaticMesh->ReverseCulling),
FeatureLevel
);
}
}
}
bool FShadowDepthDrawingPolicyFactory::DrawDynamicMesh(
FRHICommandList& RHICmdList,
const FSceneView& View,
ContextType Context,
const FMeshBatch& Mesh,
bool bPreFog,
const FDrawingPolicyRenderState& DrawRenderState,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
FHitProxyId HitProxyId
)
{
bool bDirty = false;
// Use a per-FMeshBatch check on top of the per-primitive check because dynamic primitives can submit multiple FMeshElements.
if (Mesh.CastShadow)
{
const auto FeatureLevel = View.GetFeatureLevel();
const FMaterialRenderProxy* MaterialRenderProxy = Mesh.MaterialRenderProxy;
const FMaterial* Material = MaterialRenderProxy->GetMaterial(FeatureLevel);
const EBlendMode BlendMode = Material->GetBlendMode();
const EMaterialShadingModel ShadingModel = Material->GetShadingModel();
const bool bLocalOnePassPointLightShadow = Context.ShadowInfo->bOnePassPointLightShadow;
const bool bReflectiveShadowmap = Context.ShadowInfo->bReflectiveShadowmap && !bLocalOnePassPointLightShadow;
bool bProcess = !IsTranslucentBlendMode(BlendMode) && ShadingModel != MSM_Unlit && ShouldIncludeDomainInMeshPass(Material->GetMaterialDomain());
if (bReflectiveShadowmap && Material->ShouldInjectEmissiveIntoLPV())
{
bProcess = true;
}
if (bProcess)
{
const bool bLocalDirectionalLight = Context.ShadowInfo->bDirectionalLight;
const bool bPreShadow = Context.ShadowInfo->bPreShadow;
const bool bTwoSided = Material->IsTwoSided() || PrimitiveSceneProxy->CastsShadowAsTwoSided();
const FShadowDepthDrawingPolicyContext PolicyContext(Context.ShadowInfo);
FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(Mesh);
OverrideSettings.MeshOverrideFlags |= bTwoSided ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
OverrideWithDefaultMaterialForShadowDepth(MaterialRenderProxy, Material, bReflectiveShadowmap, FeatureLevel);
if(bReflectiveShadowmap)
{
FShadowDepthDrawingPolicy<true> DrawingPolicy(
MaterialRenderProxy->GetMaterial(FeatureLevel),
bLocalDirectionalLight,
bLocalOnePassPointLightShadow,
bPreShadow,
OverrideSettings,
FeatureLevel,
Mesh.VertexFactory,
MaterialRenderProxy,
Mesh.ReverseCulling
);
//TODO MaybeRemovable if ShadowDepth never support LOD Transitions
FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState);
DrawRenderStateLocal.SetDitheredLODTransitionAlpha(Mesh.DitheredLODTransitionAlpha);
SetViewFlagsForShadowPass(DrawRenderStateLocal, View, View.GetFeatureLevel(), DrawingPolicy.IsTwoSided(), true, bLocalOnePassPointLightShadow);
DrawingPolicy.SetupPipelineState(DrawRenderStateLocal, View);
CommitGraphicsPipelineState(RHICmdList, DrawingPolicy, DrawRenderStateLocal, DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
DrawingPolicy.SetSharedState(RHICmdList, DrawRenderStateLocal, &View, PolicyContext);
for (int32 BatchElementIndex = 0, Num = Mesh.Elements.Num(); BatchElementIndex < Num; BatchElementIndex++)
{
TDrawEvent<FRHICommandList> MeshEvent;
BeginMeshDrawEvent(RHICmdList, PrimitiveSceneProxy, Mesh, MeshEvent);
DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,DrawRenderStateLocal,FMeshDrawingPolicy::ElementDataType(),PolicyContext);
DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex);
}
}
else
{
FShadowDepthDrawingPolicy<false> DrawingPolicy(
MaterialRenderProxy->GetMaterial(FeatureLevel),
bLocalDirectionalLight,
bLocalOnePassPointLightShadow,
bPreShadow,
OverrideSettings,
FeatureLevel,
Mesh.VertexFactory,
MaterialRenderProxy,
Mesh.ReverseCulling
);
//TODO MaybeRemovable if ShadowDepth never support LOD Transitions
FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState);
DrawRenderStateLocal.SetDitheredLODTransitionAlpha(Mesh.DitheredLODTransitionAlpha);
SetViewFlagsForShadowPass(DrawRenderStateLocal, View, View.GetFeatureLevel(), DrawingPolicy.IsTwoSided(), false, bLocalOnePassPointLightShadow);
DrawingPolicy.SetupPipelineState(DrawRenderStateLocal, View);
CommitGraphicsPipelineState(RHICmdList, DrawingPolicy, DrawRenderStateLocal, DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
DrawingPolicy.SetSharedState(RHICmdList, DrawRenderStateLocal, &View, PolicyContext);
for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++)
{
TDrawEvent<FRHICommandList> MeshEvent;
BeginMeshDrawEvent(RHICmdList, PrimitiveSceneProxy, Mesh, MeshEvent);
DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,DrawRenderStateLocal,FMeshDrawingPolicy::ElementDataType(),PolicyContext);
DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex);
}
}
bDirty = true;
}
}
return bDirty;
}
template <bool bRenderingReflectiveShadowMaps>
void FShadowDepthDrawingPolicy<bRenderingReflectiveShadowMaps>::DrawMesh(FRHICommandList& RHICmdList, const FMeshBatch& Mesh, int32 BatchElementIndex, const bool bIsInstancedStereo) const
{
if(!bOnePassPointLightShadow || RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[FeatureLevel]))
{
FMeshDrawingPolicy::DrawMesh(RHICmdList, Mesh, BatchElementIndex, bIsInstancedStereo);
}
else
{
INC_DWORD_STAT(STAT_MeshDrawCalls);
SCOPED_DRAW_EVENT(RHICmdList, OnePassPointLightMeshDraw);
const FMeshBatchElement& BatchElement = Mesh.Elements[BatchElementIndex];
if (Mesh.UseDynamicData)
{
check(Mesh.DynamicVertexData);
// @todo This code path *assumes* that DrawPrimitiveUP & DrawIndexedPrimitiveUP implicitly
// turn the following into instanced draw calls to route a draw to each face.
// This avoids adding anything to the public RHI API but is a filthy hack.
VertexShader->SetDrawInstanceCount(RHICmdList, 1);
if (BatchElement.DynamicIndexData)
{
DrawIndexedPrimitiveUP(
RHICmdList,
Mesh.Type,
BatchElement.MinVertexIndex,
BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1,
BatchElement.NumPrimitives,
BatchElement.DynamicIndexData,
BatchElement.DynamicIndexStride,
Mesh.DynamicVertexData,
Mesh.DynamicVertexStride
);
}
else
{
DrawPrimitiveUP(
RHICmdList,
Mesh.Type,
BatchElement.NumPrimitives,
Mesh.DynamicVertexData,
Mesh.DynamicVertexStride
);
}
}
else
{
if(BatchElement.IndexBuffer)
{
check(BatchElement.IndexBuffer->IsInitialized());
if (BatchElement.bIsInstanceRuns)
{
checkSlow(BatchElement.bIsInstanceRuns);
if (bUsePositionOnlyVS)
{
for (uint32 Run = 0; Run < BatchElement.NumInstances; Run++)
{
VertexFactory->OffsetPositionInstanceStreams(RHICmdList, BatchElement.InstanceRuns[Run * 2]);
uint32 Instances = 1 + BatchElement.InstanceRuns[Run * 2 + 1] - BatchElement.InstanceRuns[Run * 2];
VertexShader->SetDrawInstanceCount(RHICmdList, Instances);
RHICmdList.DrawIndexedPrimitive(
BatchElement.IndexBuffer->IndexBufferRHI,
Mesh.Type,
0,
0,
BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1,
BatchElement.FirstIndex,
BatchElement.NumPrimitives,
Instances
);
}
}
else
{
for (uint32 Run = 0; Run < BatchElement.NumInstances; Run++)
{
VertexFactory->OffsetInstanceStreams(RHICmdList, BatchElement.InstanceRuns[Run * 2]);
uint32 Instances = 1 + BatchElement.InstanceRuns[Run * 2 + 1] - BatchElement.InstanceRuns[Run * 2];
VertexShader->SetDrawInstanceCount(RHICmdList, Instances);
RHICmdList.DrawIndexedPrimitive(
BatchElement.IndexBuffer->IndexBufferRHI,
Mesh.Type,
0,
0,
BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1,
BatchElement.FirstIndex,
BatchElement.NumPrimitives,
Instances * 6
);
}
}
}
else
{
// Point light shadow cube maps shouldn't be rendered in stereo
check(!bIsInstancedStereo);
VertexShader->SetDrawInstanceCount(RHICmdList, BatchElement.NumInstances);
RHICmdList.DrawIndexedPrimitive(
BatchElement.IndexBuffer->IndexBufferRHI,
Mesh.Type,
0,
0,
BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1,
BatchElement.FirstIndex,
BatchElement.NumPrimitives,
BatchElement.NumInstances * 6
);
}
}
else
{
VertexShader->SetDrawInstanceCount(RHICmdList, BatchElement.NumInstances);
RHICmdList.DrawPrimitive(
Mesh.Type,
BatchElement.FirstIndex,
BatchElement.NumPrimitives,
BatchElement.NumInstances * 6
);
}
}
}
}
/*-----------------------------------------------------------------------------
FProjectedShadowInfo
-----------------------------------------------------------------------------*/
static void CheckShadowDepthMaterials(const FMaterialRenderProxy* InRenderProxy, const FMaterial* InMaterial, bool bReflectiveShadowmap, ERHIFeatureLevel::Type InFeatureLevel)
{
const FMaterialRenderProxy* RenderProxy = InRenderProxy;
const FMaterial* Material = InMaterial;
OverrideWithDefaultMaterialForShadowDepth(RenderProxy, Material, bReflectiveShadowmap, InFeatureLevel);
check(RenderProxy == InRenderProxy);
check(Material == InMaterial);
}
void FProjectedShadowInfo::ClearDepth(FRHICommandList& RHICmdList, class FSceneRenderer* SceneRenderer, int32 NumColorTextures, FTextureRHIParamRef* ColorTextures, FTextureRHIParamRef DepthTexture, bool bPerformClear)
{
uint32 ViewportMinX = X;
uint32 ViewportMinY = Y;
float ViewportMinZ = 0.0f;
uint32 ViewportMaxX = X + BorderSize * 2 + ResolutionX;
uint32 ViewportMaxY = Y + BorderSize * 2 + ResolutionY;
float ViewportMaxZ = 1.0f;
int32 NumClearColors;
bool bClearColor;
FLinearColor Colors[2];
// Translucent shadows use draw call clear
check(!bTranslucentShadow);
if (bReflectiveShadowmap)
{
// Clear color and depth targets
bClearColor = true;
Colors[0] = FLinearColor(0, 0, 1, 0);
Colors[1] = FLinearColor(0, 0, 0, 0);
NumClearColors = FMath::Min(2, NumColorTextures);
}
else
{
// Clear depth only.
bClearColor = false;
Colors[0] = FLinearColor::White;
NumClearColors = FMath::Min(1, NumColorTextures);
}
if (bPerformClear)
{
RHICmdList.SetViewport(
ViewportMinX,
ViewportMinY,
ViewportMinZ,
ViewportMaxX,
ViewportMaxY,
ViewportMaxZ
);
DrawClearQuadMRT(RHICmdList, SceneRenderer->FeatureLevel, bClearColor, NumClearColors, Colors, true, 1.0f, false, 0);
}
else
{
RHICmdList.BindClearMRTValues(bClearColor, true, false);
}
}
template <bool bReflectiveShadowmap>
void DrawMeshElements(FRHICommandList& RHICmdList, FShadowDepthDrawingPolicy<bReflectiveShadowmap>& SharedDrawingPolicy, const FShadowStaticMeshElement& State, const FViewInfo& View, FShadowDepthDrawingPolicyContext PolicyContext, const FDrawingPolicyRenderState& DrawRenderState, const FStaticMesh* Mesh)
{
#if UE_BUILD_DEBUG
// During shadow setup we should have already overridden materials with default material where needed.
// Make sure of it!
CheckShadowDepthMaterials(State.RenderProxy, State.MaterialResource, bReflectiveShadowmap, View.GetFeatureLevel());
#endif
#if UE_BUILD_DEBUG
FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(*State.Mesh);
OverrideSettings.MeshOverrideFlags |= State.bIsTwoSided ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
FShadowDepthDrawingPolicy<bReflectiveShadowmap> DebugPolicy(
State.MaterialResource,
SharedDrawingPolicy.bDirectionalLight,
SharedDrawingPolicy.bOnePassPointLightShadow,
SharedDrawingPolicy.bPreShadow,
OverrideSettings,
View.GetFeatureLevel(),
State.Mesh->VertexFactory,
State.RenderProxy,
State.Mesh->ReverseCulling);
// Verify that SharedDrawingPolicy can be used to draw this mesh without artifacts by checking the comparison functions that static draw lists use
checkSlow(DebugPolicy.Matches(SharedDrawingPolicy).Result());
checkSlow(CompareDrawingPolicy(DebugPolicy, SharedDrawingPolicy) == 0);
#endif
//TODO MaybeRemovable if ShadowDepth never support LOD Transitions
FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState);
SharedDrawingPolicy.ApplyDitheredLODTransitionState(DrawRenderStateLocal, View, *Mesh, false);
// Render only those batch elements that match the current LOD
uint64 BatchElementMask = Mesh->bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[Mesh->Id] : ((1ull << Mesh->Elements.Num()) - 1);
int32 BatchElementIndex = 0;
do
{
if(BatchElementMask & 1)
{
TDrawEvent<FRHICommandList> MeshEvent;
BeginMeshDrawEvent(RHICmdList, Mesh->PrimitiveSceneInfo->Proxy, *Mesh, MeshEvent);
SharedDrawingPolicy.SetMeshRenderState(RHICmdList, View, Mesh->PrimitiveSceneInfo->Proxy, *Mesh, BatchElementIndex, DrawRenderStateLocal, FMeshDrawingPolicy::ElementDataType(),PolicyContext);
SharedDrawingPolicy.DrawMesh(RHICmdList, *Mesh, BatchElementIndex);
INC_DWORD_STAT(STAT_ShadowDynamicPathDrawCalls);
}
BatchElementMask >>= 1;
BatchElementIndex++;
} while(BatchElementMask);
}
template <bool bReflectiveShadowmap>
void DrawShadowMeshElements(FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, const FProjectedShadowInfo& ShadowInfo)
{
FShadowDepthDrawingPolicyContext PolicyContext(&ShadowInfo);
const FShadowStaticMeshElement& FirstShadowMesh = ShadowInfo.StaticSubjectMeshElements[0];
const FMaterial* FirstMaterialResource = FirstShadowMesh.MaterialResource;
auto FeatureLevel = View.GetFeatureLevel();
FShadowDepthDrawingPolicy<bReflectiveShadowmap> SharedDrawingPolicy(
FirstMaterialResource,
ShadowInfo.bDirectionalLight,
ShadowInfo.bOnePassPointLightShadow,
ShadowInfo.bPreShadow,
ComputeMeshOverrideSettings(*FirstShadowMesh.Mesh),
FeatureLevel);
FShadowStaticMeshElement OldState;
FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState);
uint32 ElementCount = ShadowInfo.StaticSubjectMeshElements.Num();
for(uint32 ElementIndex = 0; ElementIndex < ElementCount; ++ElementIndex)
{
const FShadowStaticMeshElement& ShadowMesh = ShadowInfo.StaticSubjectMeshElements[ElementIndex];
if(!View.StaticMeshShadowDepthMap[ShadowMesh.Mesh->Id])
{
// not visible
continue;
}
FShadowStaticMeshElement CurrentState(ShadowMesh.RenderProxy, ShadowMesh.MaterialResource, ShadowMesh.Mesh, ShadowMesh.bIsTwoSided);
// Only call draw shared when the vertex factory or material have changed
if(OldState.DoesDeltaRequireADrawSharedCall(CurrentState))
{
OldState = CurrentState;
SharedDrawingPolicy.UpdateElementState(CurrentState, FeatureLevel);
DrawRenderStateLocal.SetDitheredLODTransitionAlpha(ShadowMesh.Mesh->DitheredLODTransitionAlpha);
SetViewFlagsForShadowPass(DrawRenderStateLocal, View, View.GetFeatureLevel(), SharedDrawingPolicy.IsTwoSided(), true, ShadowInfo.bOnePassPointLightShadow);
SharedDrawingPolicy.SetupPipelineState(DrawRenderStateLocal, View);
CommitGraphicsPipelineState(RHICmdList, SharedDrawingPolicy, DrawRenderStateLocal, SharedDrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
SharedDrawingPolicy.SetSharedState(RHICmdList, DrawRenderStateLocal, &View, PolicyContext);
}
DrawMeshElements(RHICmdList, SharedDrawingPolicy, OldState, View, PolicyContext, DrawRenderStateLocal, ShadowMesh.Mesh);
}
}
void FProjectedShadowInfo::RenderDepthDynamic(FRHICommandList& RHICmdList, FSceneRenderer* SceneRenderer, const FViewInfo* FoundView, const FDrawingPolicyRenderState& DrawRenderState)
{
// Draw the subject's dynamic elements.
SCOPE_CYCLE_COUNTER(STAT_WholeSceneDynamicShadowDepthsTime);
FShadowDepthDrawingPolicyFactory::ContextType Context(this);
for (int32 MeshBatchIndex = 0; MeshBatchIndex < DynamicSubjectMeshElements.Num(); MeshBatchIndex++)
{
const FMeshBatchAndRelevance& MeshBatchAndRelevance = DynamicSubjectMeshElements[MeshBatchIndex];
const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
FShadowDepthDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, *FoundView, Context, MeshBatch, true, DrawRenderState, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId);
}
}
class FDrawShadowMeshElementsThreadTask : public FRenderTask
{
FProjectedShadowInfo& ThisShadow;
FRHICommandList& RHICmdList;
const FViewInfo& View;
FDrawingPolicyRenderState DrawRenderState;
bool bReflective;
public:
FDrawShadowMeshElementsThreadTask(
FProjectedShadowInfo& InThisShadow,
FRHICommandList& InRHICmdList,
const FViewInfo& InView,
const FDrawingPolicyRenderState& InDrawRenderState,
bool InbReflective
)
: ThisShadow(InThisShadow)
, RHICmdList(InRHICmdList)
, View(InView)
, DrawRenderState(InDrawRenderState)
, bReflective(InbReflective)
{
}
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FDrawShadowMeshElementsThreadTask, STATGROUP_TaskGraphTasks);
}
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
SCOPE_CYCLE_COUNTER(STAT_WholeSceneStaticShadowDepthsTime);
if (bReflective)
{
// reflective shadow map
DrawShadowMeshElements<true>(RHICmdList, View, DrawRenderState, ThisShadow);
}
else
{
// normal shadow map
DrawShadowMeshElements<false>(RHICmdList, View, DrawRenderState, ThisShadow);
}
RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent);
}
};
class FRenderDepthDynamicThreadTask : public FRenderTask
{
FProjectedShadowInfo& ThisShadow;
FRHICommandList& RHICmdList;
const FViewInfo& View;
FDrawingPolicyRenderState DrawRenderState;
FSceneRenderer* SceneRenderer;
public:
FRenderDepthDynamicThreadTask(
FProjectedShadowInfo& InThisShadow,
FRHICommandList& InRHICmdList,
const FViewInfo& InView,
const FDrawingPolicyRenderState& InDrawRenderState,
FSceneRenderer* InSceneRenderer
)
: ThisShadow(InThisShadow)
, RHICmdList(InRHICmdList)
, View(InView)
, DrawRenderState(InDrawRenderState)
, SceneRenderer(InSceneRenderer)
{
}
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FRenderDepthDynamicThreadTask, STATGROUP_TaskGraphTasks);
}
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
ThisShadow.RenderDepthDynamic(RHICmdList, SceneRenderer, &View, DrawRenderState);
RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent);
}
};
void FProjectedShadowInfo::SetStateForDepth(FRHICommandList& RHICmdList, EShadowDepthRenderMode RenderMode, FDrawingPolicyRenderState& DrawRenderState)
{
check(bAllocated);
RHICmdList.SetViewport(
X + BorderSize,
Y + BorderSize,
0.0f,
X + BorderSize + ResolutionX,
Y + BorderSize + ResolutionY,
1.0f
);
// GIBlockingVolumes render mode only affects the reflective shadow map, using the opacity of the material to multiply against the existing color.
if (RenderMode == ShadowDepthRenderMode_GIBlockingVolumes)
{
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One,
CW_RGBA, BO_Add, BF_Zero, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI());
}
// The EmissiveOnly render mode shouldn't write into the reflective shadow map, only into the LPV.
else if (RenderMode == ShadowDepthRenderMode_EmissiveOnly)
{
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, CW_NONE>::GetRHI());
}
else if (bReflectiveShadowmap && !bOnePassPointLightShadow)
{
// Enable color writes to the reflective shadow map targets with opaque blending
DrawRenderState.SetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA>::GetRHI());
}
else
{
// Disable color writes
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI());
}
if (RenderMode == ShadowDepthRenderMode_EmissiveOnly || RenderMode == ShadowDepthRenderMode_GIBlockingVolumes)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_LessEqual>::GetRHI());
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_LessEqual>::GetRHI());
}
}
static TAutoConsoleVariable<int32> CVarParallelShadows(
TEXT("r.ParallelShadows"),
0,
TEXT("Toggles parallel shadow rendering. Parallel rendering must be enabled for this to have an effect."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarParallelShadowsNonWholeScene(
TEXT("r.ParallelShadowsNonWholeScene"),
0,
TEXT("Toggles parallel shadow rendering for non whole-scene shadows. r.ParallelShadows must be enabled for this to have an effect."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarRHICmdShadowDeferredContexts(
TEXT("r.RHICmdShadowDeferredContexts"),
1,
TEXT("True to use deferred contexts to parallelize shadow command list execution."));
static TAutoConsoleVariable<int32> CVarRHICmdFlushRenderThreadTasksShadowPass(
TEXT("r.RHICmdFlushRenderThreadTasksShadowPass"),
0,
TEXT("Wait for completion of parallel render thread tasks at the end of each shadow pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksShadowPass is > 0 we will flush."));
DECLARE_CYCLE_STAT(TEXT("Shadow"), STAT_CLP_Shadow, STATGROUP_ParallelCommandListMarkers);
class FShadowParallelCommandListSet : public FParallelCommandListSet
{
FProjectedShadowInfo& ProjectedShadowInfo;
FSetShadowRenderTargetFunction SetShadowRenderTargets;
EShadowDepthRenderMode RenderMode;
public:
FShadowParallelCommandListSet(const FViewInfo& InView, FRHICommandListImmediate& InParentCmdList, bool bInParallelExecute, bool bInCreateSceneContext, FProjectedShadowInfo& InProjectedShadowInfo, FSetShadowRenderTargetFunction InSetShadowRenderTargets, EShadowDepthRenderMode RenderModeIn )
: FParallelCommandListSet(GET_STATID(STAT_CLP_Shadow), InView, InParentCmdList, bInParallelExecute, bInCreateSceneContext)
, ProjectedShadowInfo(InProjectedShadowInfo)
, SetShadowRenderTargets(InSetShadowRenderTargets)
, RenderMode(RenderModeIn)
{
SetStateOnCommandList(ParentCmdList);
}
virtual ~FShadowParallelCommandListSet()
{
Dispatch();
}
virtual void SetStateOnCommandList(FRHICommandList& CmdList) override
{
FParallelCommandListSet::SetStateOnCommandList(CmdList);
SetShadowRenderTargets(CmdList, false);
ProjectedShadowInfo.SetStateForDepth(CmdList,RenderMode, DrawRenderState);
}
};
class FCopyShadowMapsCubeGS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FCopyShadowMapsCubeGS,Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return RHISupportsGeometryShaders(Platform) && IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
FCopyShadowMapsCubeGS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FGlobalShader(Initializer)
{
}
FCopyShadowMapsCubeGS() {}
};
IMPLEMENT_SHADER_TYPE(,FCopyShadowMapsCubeGS,TEXT("CopyShadowMaps"),TEXT("CopyCubeDepthGS"),SF_Geometry);
class FCopyShadowMapsCubePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FCopyShadowMapsCubePS,Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
}
FCopyShadowMapsCubePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FGlobalShader(Initializer)
{
ShadowDepthTexture.Bind(Initializer.ParameterMap,TEXT("ShadowDepthCubeTexture"));
ShadowDepthSampler.Bind(Initializer.ParameterMap,TEXT("ShadowDepthSampler"));
}
FCopyShadowMapsCubePS() {}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, IPooledRenderTarget* SourceShadowMap)
{
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetPixelShader(), View.ViewUniformBuffer);
SetTextureParameter(RHICmdList, GetPixelShader(), ShadowDepthTexture, ShadowDepthSampler, TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), SourceShadowMap->GetRenderTargetItem().ShaderResourceTexture);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << ShadowDepthTexture;
Ar << ShadowDepthSampler;
return bShaderHasOutdatedParameters;
}
FShaderResourceParameter ShadowDepthTexture;
FShaderResourceParameter ShadowDepthSampler;
};
IMPLEMENT_SHADER_TYPE(,FCopyShadowMapsCubePS,TEXT("CopyShadowMaps"),TEXT("CopyCubeDepthPS"),SF_Pixel);
/** */
class FCopyShadowMaps2DPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FCopyShadowMaps2DPS,Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
}
FCopyShadowMaps2DPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FGlobalShader(Initializer)
{
ShadowDepthTexture.Bind(Initializer.ParameterMap,TEXT("ShadowDepthTexture"));
ShadowDepthSampler.Bind(Initializer.ParameterMap,TEXT("ShadowDepthSampler"));
}
FCopyShadowMaps2DPS() {}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, IPooledRenderTarget* SourceShadowMap)
{
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetPixelShader(), View.ViewUniformBuffer);
SetTextureParameter(RHICmdList, GetPixelShader(), ShadowDepthTexture, ShadowDepthSampler, TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), SourceShadowMap->GetRenderTargetItem().ShaderResourceTexture);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << ShadowDepthTexture;
Ar << ShadowDepthSampler;
return bShaderHasOutdatedParameters;
}
FShaderResourceParameter ShadowDepthTexture;
FShaderResourceParameter ShadowDepthSampler;
};
IMPLEMENT_SHADER_TYPE(,FCopyShadowMaps2DPS,TEXT("CopyShadowMaps"),TEXT("Copy2DDepthPS"),SF_Pixel);
void FProjectedShadowInfo::CopyCachedShadowMap(FRHICommandList& RHICmdList, const FDrawingPolicyRenderState& DrawRenderState, FSceneRenderer* SceneRenderer, const FViewInfo& View, FSetShadowRenderTargetFunction SetShadowRenderTargets)
{
check(CacheMode == SDCM_MovablePrimitivesOnly);
const FCachedShadowMapData& CachedShadowMapData = SceneRenderer->Scene->CachedShadowMaps.FindChecked(GetLightSceneInfo().Id);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
DrawRenderState.ApplyToPSO(GraphicsPSOInit);
uint32 StencilRef = DrawRenderState.GetStencilRef();
if (CachedShadowMapData.bCachedShadowMapHasPrimitives)
{
SCOPED_DRAW_EVENT(RHICmdList, CopyCachedShadowMap);
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
// No depth tests, so we can replace the clear
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<true, CF_Always>::GetRHI();
extern TGlobalResource<FFilterVertexDeclaration> GFilterVertexDeclaration;
if (bOnePassPointLightShadow)
{
if (RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[SceneRenderer->FeatureLevel]))
{
// Set shaders and texture
TShaderMapRef<TScreenVSForGS<false>> ScreenVertexShader(View.ShaderMap);
TShaderMapRef<FCopyShadowMapsCubeGS> GeometryShader(View.ShaderMap);
TShaderMapRef<FCopyShadowMapsCubePS> PixelShader(View.ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
GraphicsPSOInit.BoundShaderState.GeometryShaderRHI = GETSAFERHISHADER_GEOMETRY(*GeometryShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
RHICmdList.SetStencilRef(StencilRef);
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
DrawRectangle(
RHICmdList,
0, 0,
ResolutionX, ResolutionY,
BorderSize, BorderSize,
ResolutionX, ResolutionY,
FIntPoint(ResolutionX, ResolutionY),
CachedShadowMapData.ShadowMap.GetSize(),
*ScreenVertexShader,
EDRF_Default);
}
else
{
check(RHISupportsVertexShaderLayer(GShaderPlatformForFeatureLevel[SceneRenderer->FeatureLevel]));
// Set shaders and texture
TShaderMapRef<TScreenVSForGS<true>> ScreenVertexShader(View.ShaderMap);
TShaderMapRef<FCopyShadowMapsCubePS> PixelShader(View.ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
RHICmdList.SetStencilRef(StencilRef);
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
DrawRectangle(
RHICmdList,
0, 0,
ResolutionX, ResolutionY,
BorderSize, BorderSize,
ResolutionX, ResolutionY,
FIntPoint(ResolutionX, ResolutionY),
CachedShadowMapData.ShadowMap.GetSize(),
*ScreenVertexShader,
EDRF_Default,
6);
}
}
else
{
// Set shaders and texture
TShaderMapRef<FScreenVS> ScreenVertexShader(View.ShaderMap);
TShaderMapRef<FCopyShadowMaps2DPS> PixelShader(View.ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
RHICmdList.SetStencilRef(StencilRef);
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
DrawRectangle(
RHICmdList,
0, 0,
ResolutionX, ResolutionY,
BorderSize, BorderSize,
ResolutionX, ResolutionY,
FIntPoint(ResolutionX, ResolutionY),
CachedShadowMapData.ShadowMap.GetSize(),
*ScreenVertexShader,
EDRF_Default);
}
}
}
void FProjectedShadowInfo::RenderDepthInner(FRHICommandList& RHICmdList, FSceneRenderer* SceneRenderer, const FViewInfo* FoundView, FSetShadowRenderTargetFunction SetShadowRenderTargets, EShadowDepthRenderMode RenderMode)
{
FDrawingPolicyRenderState DrawRenderState(*FoundView);
SetStateForDepth(RHICmdList, RenderMode, DrawRenderState);
if (CacheMode == SDCM_MovablePrimitivesOnly)
{
// Copy in depths of static primitives before we render movable primitives
CopyCachedShadowMap(RHICmdList, DrawRenderState, SceneRenderer, *FoundView, SetShadowRenderTargets);
}
FShadowDepthDrawingPolicyContext StackPolicyContext(this);
FShadowDepthDrawingPolicyContext* PolicyContext(&StackPolicyContext);
bool bIsWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
if (RHICmdList.IsImmediate() && // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread() &&
(bIsWholeSceneDirectionalShadow || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread() > 0)
)
{
check(IsInRenderingThread());
// parallel version
bool bFlush = CVarRHICmdFlushRenderThreadTasksShadowPass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0;
FScopedCommandListWaitForTasks Flusher(bFlush);
if (!bFlush)
{
/** CAUTION, this is assumed to be a POD type. We allocate the on the scene allocator and NEVER CALL A DESTRUCTOR.
If you want to add non-pod data, not a huge problem, we just need to track and destruct them at the end of the scene.
**/
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
PolicyContext = new (FMemStack::Get()) FShadowDepthDrawingPolicyContext(this);
}
{
check(RHICmdList.IsImmediate());
FRHICommandListImmediate& Immed = static_cast<FRHICommandListImmediate&>(RHICmdList);
FShadowParallelCommandListSet ParallelCommandListSet(*FoundView, Immed, CVarRHICmdShadowDeferredContexts.GetValueOnRenderThread() > 0, !bFlush, *this, SetShadowRenderTargets, RenderMode);
// Draw the subject's static elements using static draw lists
if (bIsWholeSceneDirectionalShadow && RenderMode != ShadowDepthRenderMode_EmissiveOnly && RenderMode != ShadowDepthRenderMode_GIBlockingVolumes)
{
SCOPE_CYCLE_COUNTER(STAT_WholeSceneStaticDrawListShadowDepthsTime);
if (bReflectiveShadowmap)
{
SceneRenderer->Scene->WholeSceneReflectiveShadowMapDrawList.DrawVisibleParallel(*PolicyContext, StaticMeshWholeSceneShadowDepthMap, StaticMeshWholeSceneShadowBatchVisibility, ParallelCommandListSet);
}
else
{
// Use the scene's shadow depth draw list with this shadow's visibility map
SceneRenderer->Scene->WholeSceneShadowDepthDrawList.DrawVisibleParallel(*PolicyContext, StaticMeshWholeSceneShadowDepthMap, StaticMeshWholeSceneShadowBatchVisibility, ParallelCommandListSet);
}
}
// Draw the subject's static elements using manual state filtering
else if (StaticSubjectMeshElements.Num() > 0)
{
FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList();
FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FDrawShadowMeshElementsThreadTask>::CreateTask(ParallelCommandListSet.GetPrereqs(), ENamedThreads::RenderThread)
.ConstructAndDispatchWhenReady(*this, *CmdList, *FoundView, DrawRenderState, bReflectiveShadowmap && !bOnePassPointLightShadow);
ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent, StaticSubjectMeshElements.Num());
}
if (DynamicSubjectMeshElements.Num())
{
FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList();
FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FRenderDepthDynamicThreadTask>::CreateTask(ParallelCommandListSet.GetPrereqs(), ENamedThreads::RenderThread)
.ConstructAndDispatchWhenReady(*this, *CmdList, *FoundView, DrawRenderState, SceneRenderer);
ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent, DynamicSubjectMeshElements.Num());
}
}
}
else
{
// single threaded version
SetStateForDepth(RHICmdList, RenderMode, DrawRenderState);
// Draw the subject's static elements using static draw lists
if (bIsWholeSceneDirectionalShadow && RenderMode != ShadowDepthRenderMode_EmissiveOnly && RenderMode != ShadowDepthRenderMode_GIBlockingVolumes)
{
SCOPE_CYCLE_COUNTER(STAT_WholeSceneStaticDrawListShadowDepthsTime);
if (bReflectiveShadowmap)
{
SceneRenderer->Scene->WholeSceneReflectiveShadowMapDrawList.DrawVisible(RHICmdList, *FoundView, *PolicyContext, DrawRenderState, StaticMeshWholeSceneShadowDepthMap, StaticMeshWholeSceneShadowBatchVisibility);
}
else
{
// Use the scene's shadow depth draw list with this shadow's visibility map
SceneRenderer->Scene->WholeSceneShadowDepthDrawList.DrawVisible(RHICmdList, *FoundView, *PolicyContext, DrawRenderState, StaticMeshWholeSceneShadowDepthMap, StaticMeshWholeSceneShadowBatchVisibility);
}
}
// Draw the subject's static elements using manual state filtering
else if (StaticSubjectMeshElements.Num() > 0)
{
SCOPE_CYCLE_COUNTER(STAT_WholeSceneStaticShadowDepthsTime);
if (bReflectiveShadowmap && !bOnePassPointLightShadow)
{
// reflective shadow map
DrawShadowMeshElements<true>(RHICmdList, *FoundView, DrawRenderState, *this);
}
else
{
// normal shadow map
DrawShadowMeshElements<false>(RHICmdList, *FoundView, DrawRenderState, *this);
}
}
RenderDepthDynamic(RHICmdList, SceneRenderer, FoundView, DrawRenderState);
}
}
void FProjectedShadowInfo::ModifyViewForShadow(FRHICommandList& RHICmdList, FViewInfo* FoundView) const
{
FIntRect OriginalViewRect = FoundView->ViewRect;
FoundView->ViewRect.Min.X = 0;
FoundView->ViewRect.Min.Y = 0;
FoundView->ViewRect.Max.X = ResolutionX;
FoundView->ViewRect.Max.Y = ResolutionY;
FoundView->ViewMatrices.HackRemoveTemporalAAProjectionJitter();
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
FoundView->CachedViewUniformShaderParameters = MakeUnique<FViewUniformShaderParameters>();
// Override the view matrix so that billboarding primitives will be aligned to the light
FoundView->ViewMatrices.HackOverrideViewMatrixForShadows(ShadowViewMatrix);
FBox VolumeBounds[TVC_MAX];
FoundView->SetupUniformBufferParameters(
SceneContext,
VolumeBounds,
TVC_MAX,
*FoundView->CachedViewUniformShaderParameters);
FoundView->ViewUniformBuffer = TUniformBufferRef<FViewUniformShaderParameters>::CreateUniformBufferImmediate(*FoundView->CachedViewUniformShaderParameters, UniformBuffer_SingleFrame);
// we are going to set this back now because we only want the correct view rect for the uniform buffer. For LOD calculations, we want the rendering viewrect and proj matrix.
FoundView->ViewRect = OriginalViewRect;
extern int32 GPreshadowsForceLowestLOD;
if (bPreShadow && GPreshadowsForceLowestLOD)
{
FoundView->DrawDynamicFlags = EDrawDynamicFlags::ForceLowestLOD;
}
}
FViewInfo* FProjectedShadowInfo::FindViewForShadow(FSceneRenderer* SceneRenderer) const
{
// Choose an arbitrary view where this shadow's subject is relevant.
FViewInfo* FoundView = NULL;
for(int32 ViewIndex = 0;ViewIndex < SceneRenderer->Views.Num();ViewIndex++)
{
FViewInfo* CheckView = &SceneRenderer->Views[ViewIndex];
const FVisibleLightViewInfo& VisibleLightViewInfo = CheckView->VisibleLightInfos[LightSceneInfo->Id];
FPrimitiveViewRelevance ViewRel = VisibleLightViewInfo.ProjectedShadowViewRelevanceMap[ShadowId];
if (ViewRel.bShadowRelevance)
{
FoundView = CheckView;
break;
}
}
check(FoundView);
return FoundView;
}
void FProjectedShadowInfo::RenderDepth(FRHICommandList& RHICmdList, FSceneRenderer* SceneRenderer, FSetShadowRenderTargetFunction SetShadowRenderTargets, EShadowDepthRenderMode RenderMode)
{
// Select the correct set of arrays for the current render mode
TArray<FShadowStaticMeshElement,SceneRenderingAllocator>* PtrCurrentMeshElements = nullptr;
PrimitiveArrayType* PtrCurrentPrimitives = nullptr;
switch(RenderMode)
{
case ShadowDepthRenderMode_Normal:
PtrCurrentMeshElements = &StaticSubjectMeshElements;
PtrCurrentPrimitives = &DynamicSubjectPrimitives;
break;
case ShadowDepthRenderMode_EmissiveOnly:
PtrCurrentMeshElements = &EmissiveOnlyMeshElements;
PtrCurrentPrimitives = &EmissiveOnlyPrimitives;
break;
case ShadowDepthRenderMode_GIBlockingVolumes:
PtrCurrentMeshElements = &GIBlockingMeshElements;
PtrCurrentPrimitives = &GIBlockingPrimitives;
break;
default:
check(0);
}
TArray<FShadowStaticMeshElement,SceneRenderingAllocator>& CurrentMeshElements = *PtrCurrentMeshElements;
PrimitiveArrayType& CurrentPrimitives = *PtrCurrentPrimitives;
#if WANTS_DRAW_MESH_EVENTS
FString EventName;
GetShadowTypeNameForDrawEvent(EventName);
if (GEmitDrawEvents)
{
EventName += FString(TEXT(" ")) + FString::FromInt(ResolutionX) + TEXT("x") + FString::FromInt(ResolutionY);
}
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepthActor, *EventName);
#endif
CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderWholeSceneShadowDepthsTime, bWholeSceneShadow);
CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderPerObjectShadowDepthsTime, !bWholeSceneShadow);
// Exit early if there are no meshes or primitives to render in the emissive only render mode.
if (RenderMode != ShadowDepthRenderMode_Normal && CurrentMeshElements.Num() == 0 && CurrentPrimitives.Num() == 0)
{
return;
}
RenderDepthInner(RHICmdList, SceneRenderer, ShadowDepthView, SetShadowRenderTargets, RenderMode);
}
void FProjectedShadowInfo::SetupShadowDepthView(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer)
{
FViewInfo* FoundView = FindViewForShadow(SceneRenderer);
check(FoundView && IsInRenderingThread());
FViewInfo* DepthPassView = FoundView->CreateSnapshot();
ModifyViewForShadow(RHICmdList, DepthPassView);
ShadowDepthView = DepthPassView;
}
void FProjectedShadowInfo::SortSubjectMeshElements()
{
// Note: this should match the criteria in FProjectedShadowInfo::RenderDepth for deciding when to call SetSharedState on a static mesh element for best performance
struct FCompareFShadowStaticMeshElement
{
FORCEINLINE bool operator()( const FShadowStaticMeshElement& A, const FShadowStaticMeshElement& B ) const
{
if( A.Mesh->VertexFactory != B.Mesh->VertexFactory ) return A.Mesh->VertexFactory < B.Mesh->VertexFactory;
if( A.RenderProxy != B.RenderProxy ) return A.RenderProxy < B.RenderProxy;
if( A.bIsTwoSided != B.bIsTwoSided ) return A.bIsTwoSided < B.bIsTwoSided;
if( A.Mesh->ReverseCulling != B.Mesh->ReverseCulling ) return A.Mesh->ReverseCulling < B.Mesh->ReverseCulling;
return false;
}
};
StaticSubjectMeshElements.Sort( FCompareFShadowStaticMeshElement() );
}
void FProjectedShadowInfo::GetShadowTypeNameForDrawEvent(FString& TypeName) const
{
if (GEmitDrawEvents)
{
const FName ParentName = ParentSceneInfo ? ParentSceneInfo->Proxy->GetOwnerName() : NAME_None;
if (bWholeSceneShadow)
{
if (CascadeSettings.ShadowSplitIndex >= 0)
{
TypeName = FString(TEXT("WholeScene split")) + FString::FromInt(CascadeSettings.ShadowSplitIndex);
}
else
{
if (CacheMode == SDCM_MovablePrimitivesOnly)
{
TypeName = FString(TEXT("WholeScene MovablePrimitives"));
}
else if (CacheMode == SDCM_StaticPrimitivesOnly)
{
TypeName = FString(TEXT("WholeScene StaticPrimitives"));
}
else
{
TypeName = FString(TEXT("WholeScene"));
}
}
}
else if (bPreShadow)
{
TypeName = FString(TEXT("PreShadow ")) + ParentName.ToString();
}
else
{
TypeName = FString(TEXT("PerObject ")) + ParentName.ToString();
}
}
}
void FSceneRenderer::RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICmdList)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.ShadowMapAtlases.Num(); AtlasIndex++)
{
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.ShadowMapAtlases[AtlasIndex];
FSceneRenderTargetItem& RenderTarget = ShadowMapAtlas.RenderTargets.DepthTarget->GetRenderTargetItem();
FIntPoint AtlasSize = ShadowMapAtlas.RenderTargets.DepthTarget->GetDesc().Extent;
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, ShadowMapAtlas.RenderTargets.DepthTarget.GetReference());
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("Atlas%u %ux%u"), AtlasIndex, AtlasSize.X, AtlasSize.Y);
auto SetShadowRenderTargets = [this, &RenderTarget, &SceneContext](FRHICommandList& InRHICmdList, bool bPerformClear)
{
FRHISetRenderTargetsInfo Info(0, nullptr, FRHIDepthRenderTargetView(RenderTarget.TargetableTexture,
bPerformClear ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad,
ERenderTargetStoreAction::EStore,
ERenderTargetLoadAction::ELoad,
ERenderTargetStoreAction::EStore));
check(Info.DepthStencilRenderTarget.Texture->GetDepthClearValue() == 1.0f);
Info.ColorRenderTarget[0].StoreAction = ERenderTargetStoreAction::ENoAction;
if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
{
Info.NumColorRenderTargets = 1;
Info.ColorRenderTarget[0].Texture = SceneContext.GetOptionalShadowDepthColorSurface(InRHICmdList, Info.DepthStencilRenderTarget.Texture->GetTexture2D()->GetSizeX(), Info.DepthStencilRenderTarget.Texture->GetTexture2D()->GetSizeY());
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Info.ColorRenderTarget[0].Texture);
}
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Info.DepthStencilRenderTarget.Texture);
InRHICmdList.SetRenderTargetsAndClear(Info);
};
{
SCOPED_DRAW_EVENT(RHICmdList, Clear);
SetShadowRenderTargets(RHICmdList, true);
}
FLightSceneProxy* CurrentLightForDrawEvent = NULL;
#if WANTS_DRAW_MESH_EVENTS
TDrawEvent<FRHICommandList> LightEvent;
#endif
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
{
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
if (!CurrentLightForDrawEvent || ProjectedShadowInfo->GetLightSceneInfo().Proxy != CurrentLightForDrawEvent)
{
if (CurrentLightForDrawEvent)
{
STOP_DRAW_EVENT(LightEvent);
}
CurrentLightForDrawEvent = ProjectedShadowInfo->GetLightSceneInfo().Proxy;
FString LightNameWithLevel;
GetLightNameForDrawEvent(CurrentLightForDrawEvent, LightNameWithLevel);
BEGIN_DRAW_EVENTF(
RHICmdList,
LightNameEvent,
LightEvent,
*LightNameWithLevel);
}
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_Normal);
}
if (CurrentLightForDrawEvent)
{
STOP_DRAW_EVENT(LightEvent);
CurrentLightForDrawEvent = NULL;
}
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
}
}
void FSceneRenderer::BeginRenderRayTracedDistanceFieldProjections(FRHICommandListImmediate& RHICmdList)
{
for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt)
{
const FLightSceneInfoCompact& LightSceneInfoCompact = *LightIt;
const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo;
FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo.ShadowsToProject.Num(); ShadowIndex++)
{
FProjectedShadowInfo* ProjectedShadowInfo = VisibleLightInfo.ShadowsToProject[ShadowIndex];
if (ProjectedShadowInfo->bRayTracedDistanceField)
{
ProjectedShadowInfo->BeginRenderRayTracedDistanceFieldProjection(RHICmdList, View);
}
}
}
}
}
void FSceneRenderer::RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SCOPED_DRAW_EVENT(RHICmdList, ShadowDepths);
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ShadowDepths);
BeginRenderRayTracedDistanceFieldProjections(RHICmdList);
FSceneRenderer::RenderShadowDepthMapAtlases(RHICmdList);
for (int32 CubemapIndex = 0; CubemapIndex < SortedShadowsForShadowDepthPass.ShadowMapCubemaps.Num(); CubemapIndex++)
{
const FSortedShadowMapAtlas& ShadowMap = SortedShadowsForShadowDepthPass.ShadowMapCubemaps[CubemapIndex];
FSceneRenderTargetItem& RenderTarget = ShadowMap.RenderTargets.DepthTarget->GetRenderTargetItem();
FIntPoint TargetSize = ShadowMap.RenderTargets.DepthTarget->GetDesc().Extent;
check(ShadowMap.Shadows.Num() == 1);
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMap.Shadows[0];
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, ShadowMap.RenderTargets.DepthTarget.GetReference());
FString LightNameWithLevel;
GetLightNameForDrawEvent(ProjectedShadowInfo->GetLightSceneInfo().Proxy, LightNameWithLevel);
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("Cubemap %s %u^2"), *LightNameWithLevel, TargetSize.X, TargetSize.Y);
auto SetShadowRenderTargets = [this, &RenderTarget, &SceneContext](FRHICommandList& InRHICmdList, bool bPerformClear)
{
FRHISetRenderTargetsInfo Info(0, nullptr, FRHIDepthRenderTargetView(RenderTarget.TargetableTexture,
bPerformClear ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad,
ERenderTargetStoreAction::EStore,
ERenderTargetLoadAction::ELoad,
ERenderTargetStoreAction::EStore));
check(Info.DepthStencilRenderTarget.Texture->GetDepthClearValue() == 1.0f);
Info.ColorRenderTarget[0].StoreAction = ERenderTargetStoreAction::ENoAction;
if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
{
Info.NumColorRenderTargets = 1;
Info.ColorRenderTarget[0].Texture = SceneContext.GetOptionalShadowDepthColorSurface(InRHICmdList, Info.DepthStencilRenderTarget.Texture->GetTexture2D()->GetSizeX(), Info.DepthStencilRenderTarget.Texture->GetTexture2D()->GetSizeY());
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Info.ColorRenderTarget[0].Texture);
}
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Info.DepthStencilRenderTarget.Texture);
InRHICmdList.SetRenderTargetsAndClear(Info);
};
{
bool bDoClear = true;
if (ProjectedShadowInfo->CacheMode == SDCM_MovablePrimitivesOnly
&& Scene->CachedShadowMaps.FindChecked(ProjectedShadowInfo->GetLightSceneInfo().Id).bCachedShadowMapHasPrimitives)
{
// Skip the clear when we'll copy from a cached shadowmap
bDoClear = false;
}
SCOPED_CONDITIONAL_DRAW_EVENT(RHICmdList, Clear, bDoClear);
SetShadowRenderTargets(RHICmdList, bDoClear);
}
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_Normal);
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
}
if (SortedShadowsForShadowDepthPass.PreshadowCache.Shadows.Num() > 0)
{
FSceneRenderTargetItem& RenderTarget = SortedShadowsForShadowDepthPass.PreshadowCache.RenderTargets.DepthTarget->GetRenderTargetItem();
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SortedShadowsForShadowDepthPass.PreshadowCache.RenderTargets.DepthTarget.GetReference());
SCOPED_DRAW_EVENT(RHICmdList, PreshadowCache);
for (int32 ShadowIndex = 0; ShadowIndex < SortedShadowsForShadowDepthPass.PreshadowCache.Shadows.Num(); ShadowIndex++)
{
FProjectedShadowInfo* ProjectedShadowInfo = SortedShadowsForShadowDepthPass.PreshadowCache.Shadows[ShadowIndex];
if (!ProjectedShadowInfo->bDepthsCached)
{
auto SetShadowRenderTargets = [this, ProjectedShadowInfo](FRHICommandList& InRHICmdList, bool bPerformClear)
{
FTextureRHIParamRef PreShadowCacheDepthZ = Scene->PreShadowCacheDepthZ->GetRenderTargetItem().TargetableTexture.GetReference();
InRHICmdList.TransitionResources(EResourceTransitionAccess::EWritable, &PreShadowCacheDepthZ, 1);
// Must preserve existing contents as the clear will be scissored
SetRenderTarget(InRHICmdList, FTextureRHIRef(), PreShadowCacheDepthZ, ESimpleRenderTargetMode::EExistingColorAndDepth);
ProjectedShadowInfo->ClearDepth(InRHICmdList, this, 0, nullptr, PreShadowCacheDepthZ, bPerformClear);
};
SetShadowRenderTargets(RHICmdList, true);
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_Normal);
ProjectedShadowInfo->bDepthsCached = true;
}
}
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
}
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.TranslucencyShadowMapAtlases.Num(); AtlasIndex++)
{
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.TranslucencyShadowMapAtlases[AtlasIndex];
FIntPoint TargetSize = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetDesc().Extent;
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("TranslucencyAtlas%u %u^2"), AtlasIndex, TargetSize.X, TargetSize.Y);
FSceneRenderTargetItem ColorTarget0 = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetRenderTargetItem();
FSceneRenderTargetItem ColorTarget1 = ShadowMapAtlas.RenderTargets.ColorTargets[1]->GetRenderTargetItem();
FTextureRHIParamRef RenderTargetArray[2] =
{
ColorTarget0.TargetableTexture,
ColorTarget1.TargetableTexture
};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargetArray), RenderTargetArray, FTextureRHIParamRef(), 0, NULL, true);
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
{
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
ProjectedShadowInfo->RenderTranslucencyDepths(RHICmdList, this);
}
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, ColorTarget0.TargetableTexture);
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, ColorTarget1.TargetableTexture);
}
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.RSMAtlases.Num(); AtlasIndex++)
{
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.RSMAtlases[AtlasIndex];
FSceneRenderTargetItem ColorTarget0 = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetRenderTargetItem();
FSceneRenderTargetItem ColorTarget1 = ShadowMapAtlas.RenderTargets.ColorTargets[1]->GetRenderTargetItem();
FSceneRenderTargetItem DepthTarget = ShadowMapAtlas.RenderTargets.DepthTarget->GetRenderTargetItem();
FIntPoint TargetSize = ShadowMapAtlas.RenderTargets.DepthTarget->GetDesc().Extent;
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("RSM%u %ux%u"), AtlasIndex, TargetSize.X, TargetSize.Y);
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
{
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
FSceneViewState* ViewState = (FSceneViewState*)ProjectedShadowInfo->DependentView->State;
FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume(FeatureLevel);
auto SetShadowRenderTargets = [this, LightPropagationVolume, ProjectedShadowInfo, &ColorTarget0, &ColorTarget1, &DepthTarget](FRHICommandList& InRHICmdList, bool bPerformClear)
{
FTextureRHIParamRef RenderTargets[2];
RenderTargets[0] = ColorTarget0.TargetableTexture;
RenderTargets[1] = ColorTarget1.TargetableTexture;
// Hook up the geometry volume UAVs
FUnorderedAccessViewRHIParamRef Uavs[4];
Uavs[0] = LightPropagationVolume->GetGvListBufferUav();
Uavs[1] = LightPropagationVolume->GetGvListHeadBufferUav();
Uavs[2] = LightPropagationVolume->GetVplListBufferUav();
Uavs[3] = LightPropagationVolume->GetVplListHeadBufferUav();
InRHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToGfx, Uavs, ARRAY_COUNT(Uavs));
SetRenderTargets(InRHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, DepthTarget.TargetableTexture, ARRAY_COUNT(Uavs), Uavs);
ProjectedShadowInfo->ClearDepth(InRHICmdList, this, ARRAY_COUNT(RenderTargets), RenderTargets, DepthTarget.TargetableTexture, bPerformClear);
};
{
SCOPED_DRAW_EVENT(RHICmdList, Clear);
SetShadowRenderTargets(RHICmdList, true);
}
LightPropagationVolume->SetVplInjectionConstants(*ProjectedShadowInfo, ProjectedShadowInfo->GetLightSceneInfo().Proxy);
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_Normal);
// Render emissive only meshes as they are held in a separate list.
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_EmissiveOnly);
// Render gi blocking volume meshes.
ProjectedShadowInfo->RenderDepth(RHICmdList, this, SetShadowRenderTargets, ShadowDepthRenderMode_GIBlockingVolumes);
{
// Resolve the shadow depth z surface.
RHICmdList.CopyToResolveTarget(DepthTarget.TargetableTexture, DepthTarget.ShaderResourceTexture, false, FResolveParams());
RHICmdList.CopyToResolveTarget(ColorTarget0.TargetableTexture, ColorTarget0.ShaderResourceTexture, false, FResolveParams());
RHICmdList.CopyToResolveTarget(ColorTarget1.TargetableTexture, ColorTarget1.ShaderResourceTexture, false, FResolveParams());
FUnorderedAccessViewRHIParamRef UavsToReadable[2];
UavsToReadable[0] = LightPropagationVolume->GetGvListBufferUav();
UavsToReadable[1] = LightPropagationVolume->GetGvListHeadBufferUav();
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToGfx, UavsToReadable, ARRAY_COUNT(UavsToReadable));
// Unset render targets
FTextureRHIParamRef RenderTargets[2] = {NULL};
FUnorderedAccessViewRHIParamRef Uavs[2] = {NULL};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIParamRef(), ARRAY_COUNT(Uavs), Uavs);
}
}
}
}