1261 lines
63 KiB
C#
1261 lines
63 KiB
C#
using Unity.Scripting.LifecycleManagement;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using UnityEngine.Rendering.Universal.Internal;
|
|
using UnityEngine.Rendering.Universal.U2D.Profiler;
|
|
using static UnityEngine.Rendering.Universal.UniversalResourceDataBase;
|
|
using CommonResourceData = UnityEngine.Rendering.Universal.UniversalResourceData;
|
|
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
internal sealed partial class Renderer2D : ScriptableRenderer
|
|
{
|
|
private struct RenderPassInputSummary
|
|
{
|
|
internal bool requiresDepthTexture;
|
|
internal bool requiresColorTexture;
|
|
}
|
|
|
|
private struct ImportResourceSummary
|
|
{
|
|
internal RenderTargetInfo importInfo;
|
|
internal RenderTargetInfo importInfoDepth;
|
|
internal ImportResourceParams cameraColorParams;
|
|
internal ImportResourceParams cameraDepthParams;
|
|
internal ImportResourceParams backBufferColorParams;
|
|
internal ImportResourceParams backBufferDepthParams;
|
|
}
|
|
|
|
const int k_FinalBlitPassQueueOffset = 1;
|
|
const int k_AfterFinalBlitPassQueueOffset = k_FinalBlitPassQueueOffset + 1;
|
|
|
|
// TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we should remove all RTHandles and use per frame RG textures.
|
|
// We use 2 camera color handles so we can handle the edge case when a pass might want to read and write the same target.
|
|
// This is not allowed so we just swap the current target, this keeps camera stacking working and avoids an extra blit pass.
|
|
[NoAutoStaticsCleanup] static int s_CurrentColorHandle = 0;
|
|
[NoAutoStaticsCleanup] static readonly RTHandle[] s_RenderGraphCameraColorHandles = { null, null };
|
|
[NoAutoStaticsCleanup] internal static RTHandle s_RenderGraphCameraDepthHandle;
|
|
[NoAutoStaticsCleanup] static RTHandle s_OffscreenUIColorHandle;
|
|
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
[NoAutoStaticsCleanup] static bool s_CanProfilerCapture;
|
|
#if UNITY_2D_URP_TESTS
|
|
// Do not do any capture in test due to the current profiling requires memory allocation which causes tests to fail.
|
|
// We should look into a way to capture profiler data without allocations in the future and re-enable this for tests as well.
|
|
internal static bool canProfilerCapture => false && s_CanProfilerCapture;
|
|
#else
|
|
internal static bool canProfilerCapture => s_CanProfilerCapture && UnityEngine.Profiling.Profiler.enabled;
|
|
#endif
|
|
#endif
|
|
|
|
RTHandle m_RenderGraphBackbufferColorHandle;
|
|
RTHandle m_RenderGraphBackbufferDepthHandle;
|
|
RTHandle m_CameraSortingLayerHandle;
|
|
|
|
Material m_BlitMaterial;
|
|
Material m_BlitHDRMaterial;
|
|
Material m_BlitOffscreenUICoverMaterial;
|
|
Material m_SamplingMaterial;
|
|
Material m_BackdropFilterCompositeMaterial;
|
|
|
|
// 2D specific render passes
|
|
CameraRenderingLayerMaskPass m_RenderingLayerMaskPass = new CameraRenderingLayerMaskPass();
|
|
DrawNormal2DPass m_NormalPass = new DrawNormal2DPass();
|
|
DrawLight2DPass m_LightPass = new DrawLight2DPass();
|
|
DrawShadow2DPass m_ShadowPass = new DrawShadow2DPass();
|
|
DrawRenderer2DPass m_RendererPass = new DrawRenderer2DPass();
|
|
|
|
CopyDepthPass m_CopyDepthPass;
|
|
UpscalePass m_UpscalePass;
|
|
CopyCameraSortingLayerPass m_CopyCameraSortingLayerPass;
|
|
CapturePass m_CapturePass;
|
|
FinalBlitPass m_FinalBlitPass;
|
|
FinalBlitPass m_OffscreenUICoverPrepass;
|
|
DrawScreenSpaceUIPass m_DrawOffscreenUIPass;
|
|
DrawScreenSpaceUIPass m_DrawOverlayUIPass; // from HDRP code
|
|
|
|
Renderer2DData m_Renderer2DData;
|
|
|
|
internal bool m_CreateColorTexture;
|
|
internal bool m_CreateDepthTexture;
|
|
bool ppcUpscaleRT = false;
|
|
|
|
PostProcess m_PostProcess;
|
|
ColorGradingLutPass m_ColorGradingLutPassRenderGraph;
|
|
|
|
private RTHandle currentRenderGraphCameraColorHandle
|
|
{
|
|
get
|
|
{
|
|
return s_RenderGraphCameraColorHandles[s_CurrentColorHandle];
|
|
}
|
|
}
|
|
|
|
// get the next m_RenderGraphCameraColorHandles and make it the new current for future accesses
|
|
private RTHandle nextRenderGraphCameraColorHandle
|
|
{
|
|
get
|
|
{
|
|
s_CurrentColorHandle = (s_CurrentColorHandle + 1) % 2;
|
|
return currentRenderGraphCameraColorHandle;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int SupportedCameraStackingTypes()
|
|
{
|
|
return 1 << (int)CameraRenderType.Base | 1 << (int)CameraRenderType.Overlay;
|
|
}
|
|
|
|
public Renderer2D(Renderer2DData data) : base(data)
|
|
{
|
|
if (GraphicsSettings.TryGetRenderPipelineSettings<UniversalRenderPipelineRuntimeShaders>(out var shadersResources))
|
|
{
|
|
m_BlitMaterial = CoreUtils.CreateEngineMaterial(shadersResources.coreBlitPS);
|
|
m_BlitHDRMaterial = CoreUtils.CreateEngineMaterial(shadersResources.blitHDROverlay);
|
|
m_BlitOffscreenUICoverMaterial = CoreUtils.CreateEngineMaterial(shadersResources.blitHDROverlay);
|
|
m_SamplingMaterial = CoreUtils.CreateEngineMaterial(shadersResources.samplingPS);
|
|
m_BackdropFilterCompositeMaterial = CoreUtils.CreateEngineMaterial(shadersResources.uiBackdropFilterCompositePS);
|
|
}
|
|
|
|
if (GraphicsSettings.TryGetRenderPipelineSettings<Renderer2DResources>(out var renderer2DResources))
|
|
{
|
|
m_CopyDepthPass = new CopyDepthPass(
|
|
RenderPassEvent.AfterRenderingTransparents,
|
|
renderer2DResources.copyDepthPS,
|
|
shouldClear: true);
|
|
}
|
|
|
|
m_UpscalePass = new UpscalePass(RenderPassEvent.AfterRenderingPostProcessing, m_BlitMaterial);
|
|
m_CopyCameraSortingLayerPass = new CopyCameraSortingLayerPass(m_BlitMaterial);
|
|
m_CapturePass = new CapturePass(RenderPassEvent.AfterRendering);
|
|
m_FinalBlitPass = new FinalBlitPass(RenderPassEvent.AfterRendering + k_FinalBlitPassQueueOffset, m_BlitMaterial, m_BlitHDRMaterial);
|
|
m_OffscreenUICoverPrepass = new FinalBlitPass(RenderPassEvent.BeforeRenderingPostProcessing, m_BlitMaterial, m_BlitOffscreenUICoverMaterial);
|
|
|
|
m_DrawOffscreenUIPass = new DrawScreenSpaceUIPass(RenderPassEvent.BeforeRenderingPostProcessing);
|
|
m_DrawOverlayUIPass = new DrawScreenSpaceUIPass(RenderPassEvent.AfterRendering + k_AfterFinalBlitPassQueueOffset, m_BackdropFilterCompositeMaterial, m_BlitMaterial); // after m_FinalBlitPass
|
|
|
|
m_Renderer2DData = data;
|
|
m_Renderer2DData.lightCullResult = new Light2DCullResult();
|
|
|
|
UpdateSupportedRenderingFeatures();
|
|
|
|
LensFlareCommonSRP.mergeNeeded = 0;
|
|
LensFlareCommonSRP.maxLensFlareWithOcclusionTemporalSample = 1;
|
|
LensFlareCommonSRP.Initialize();
|
|
|
|
Light2DManager.Initialize();
|
|
|
|
if (data.postProcessData != null)
|
|
{
|
|
m_PostProcess = new PostProcess(data.postProcessData);
|
|
m_ColorGradingLutPassRenderGraph = new ColorGradingLutPass(RenderPassEvent.BeforeRenderingPrePasses, data.postProcessData);
|
|
}
|
|
|
|
PlatformAutoDetect.Initialize();
|
|
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
if (GraphicsSettings.TryGetRenderPipelineSettings<UniversalRenderPipelineRuntimeXRResources>(out var xrResources))
|
|
{
|
|
XRSystem.Initialize(XRPassUniversal.Create, xrResources.xrOcclusionMeshPS, xrResources.xrMirrorViewPS);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
internal override void UpdateSupportedRenderingFeatures()
|
|
{
|
|
// Only set supported rendering features that apply to 2D
|
|
supportedRenderingFeatures.supportsHDR = true;
|
|
supportedRenderingFeatures.postProcessing = m_Renderer2DData.postProcessData != null;
|
|
supportedRenderingFeatures.cameraDepthTexture = true;
|
|
supportedRenderingFeatures.upscaling = true;
|
|
supportedRenderingFeatures.antiAliasing = true;
|
|
supportedRenderingFeatures.overlayCamera = true;
|
|
supportedRenderingFeatures.msaa = true;
|
|
|
|
foreach (var feature in rendererFeatures)
|
|
{
|
|
if (feature.isActive)
|
|
{
|
|
supportedRenderingFeatures.postProcessing |= feature.supportedRenderingFeatures.postProcessing;
|
|
}
|
|
}
|
|
|
|
// Setting the engine wide feature flags here as well. We can likely phase these out.
|
|
SupportedRenderingFeatures.active.supportsHDR = supportedRenderingFeatures.supportsHDR;
|
|
}
|
|
|
|
internal static bool IsDepthUsageAllowed(ContextContainer frameData, Renderer2DData rendererData)
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
// Renderer2DData.useDepthStencilBuffer
|
|
bool allowDepth = rendererData.useDepthStencilBuffer;
|
|
|
|
// 3D Render Textures with depth/stencil buffer are not supported
|
|
if (cameraData.targetTexture != null)
|
|
allowDepth &= cameraData.targetTexture.dimension != TextureDimension.Tex3D;
|
|
|
|
// The back buffer has none when PlayerSettings.disableDepthAndStencilBuffers is enabled on a graphics API that acts on it
|
|
allowDepth &= Graphics.backBufferHasDepthStencil;
|
|
|
|
return allowDepth;
|
|
}
|
|
|
|
private bool IsPixelPerfectCameraEnabled(UniversalCameraData cameraData, out PixelPerfectCamera ppc)
|
|
{
|
|
ppc = null;
|
|
|
|
// Pixel Perfect Camera doesn't support camera stacking.
|
|
if (cameraData.renderType == CameraRenderType.Base && cameraData.resolveFinalTarget)
|
|
cameraData.camera.TryGetComponent(out ppc);
|
|
|
|
return ppc != null && ppc.enabled;
|
|
}
|
|
|
|
private RenderPassInputSummary GetRenderPassInputs()
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
RenderPassInputSummary inputSummary = new RenderPassInputSummary();
|
|
|
|
for (int i = 0; i < activeRenderPassQueue.Count; ++i)
|
|
{
|
|
ScriptableRenderPass pass = activeRenderPassQueue[i];
|
|
bool needsDepth = (pass.input & ScriptableRenderPassInput.Depth) != ScriptableRenderPassInput.None;
|
|
bool needsColor = (pass.input & ScriptableRenderPassInput.Color) != ScriptableRenderPassInput.None;
|
|
|
|
inputSummary.requiresDepthTexture |= needsDepth;
|
|
inputSummary.requiresColorTexture |= needsColor;
|
|
inputSummary.requiresColorTexture |= pass.requiresIntermediateTexture;
|
|
}
|
|
|
|
// Volumetric shadow pass requires intermediate texture
|
|
bool hasVolumetricShadowPass = false;
|
|
var layerBatches = frameData.Get<Universal2DRenderingData>().layerBatches;
|
|
var batchCount = frameData.Get<Universal2DRenderingData>().batchCount;
|
|
for (int i = 0; i < batchCount; ++i)
|
|
hasVolumetricShadowPass |= layerBatches[i].lightStats.useVolumetricShadowLights;
|
|
|
|
inputSummary.requiresColorTexture |= cameraData.postProcessEnabled
|
|
|| cameraData.isHdrEnabled
|
|
|| cameraData.isSceneViewCamera
|
|
|| !cameraData.isDefaultViewport
|
|
|| cameraData.requireSrgbConversion
|
|
|| !cameraData.resolveFinalTarget
|
|
|| cameraData.cameraTargetDescriptor.msaaSamples > 1 && UniversalRenderer.PlatformRequiresExplicitMsaaResolve()
|
|
|| m_Renderer2DData.useCameraSortingLayerTexture
|
|
|| !Mathf.Approximately(cameraData.renderScale, 1.0f)
|
|
|| (DebugHandler != null && DebugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget))
|
|
|| cameraData.captureActions != null
|
|
|| hasVolumetricShadowPass;
|
|
|
|
return inputSummary;
|
|
}
|
|
|
|
ImportResourceSummary GetImportResourceSummary(RenderGraph renderGraph, UniversalCameraData cameraData)
|
|
{
|
|
ImportResourceSummary output = new ImportResourceSummary();
|
|
|
|
bool clearColor = cameraData.renderType == CameraRenderType.Base;
|
|
bool clearDepth = cameraData.renderType == CameraRenderType.Base || cameraData.clearDepth;
|
|
|
|
// Clear back buffer color if pixel perfect crop frame is used
|
|
// Non-base cameras the back buffer should never be cleared
|
|
bool ppcEnabled = IsPixelPerfectCameraEnabled(cameraData, out var ppc) && ppc.cropFrame != PixelPerfectCamera.CropFrame.None;
|
|
bool clearColorBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && (!m_CreateColorTexture || ppcEnabled);
|
|
bool clearDepthBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_CreateColorTexture;
|
|
|
|
// if the camera background type is "uninitialized" clear using a yellow color, so users can clearly understand the underlying behaviour
|
|
Color cameraBackgroundColor = (cameraData.camera.clearFlags == CameraClearFlags.Nothing) ? Color.yellow : cameraData.backgroundColor;
|
|
Color backBufferBackgroundColor = ppcEnabled ? Color.black : cameraBackgroundColor;
|
|
|
|
if (IsSceneFilteringEnabled(cameraData.camera))
|
|
{
|
|
cameraBackgroundColor.a = 0;
|
|
clearDepth = false;
|
|
}
|
|
|
|
// Certain debug modes (e.g. wireframe/overdraw modes) require that we override clear flags and clear everything.
|
|
var debugHandler = cameraData.renderer.DebugHandler;
|
|
if (debugHandler != null && debugHandler.IsActiveForCamera(cameraData.isPreviewCamera) && debugHandler.IsScreenClearNeeded)
|
|
{
|
|
clearColor = true;
|
|
clearDepth = true;
|
|
debugHandler.TryGetScreenClearColor(ref cameraBackgroundColor);
|
|
}
|
|
|
|
output.cameraColorParams.clearOnFirstUse = clearColor;
|
|
output.cameraColorParams.clearColor = cameraBackgroundColor;
|
|
output.cameraColorParams.discardOnLastUse = false;
|
|
|
|
output.cameraDepthParams.clearOnFirstUse = clearDepth;
|
|
output.cameraDepthParams.clearColor = cameraBackgroundColor;
|
|
output.cameraDepthParams.discardOnLastUse = false;
|
|
|
|
output.backBufferColorParams.clearOnFirstUse = clearColorBackbufferOnFirstUse;
|
|
output.backBufferColorParams.clearColor = backBufferBackgroundColor;
|
|
output.backBufferColorParams.discardOnLastUse = false;
|
|
|
|
output.backBufferDepthParams.clearOnFirstUse = clearDepthBackbufferOnFirstUse;
|
|
output.backBufferDepthParams.clearColor = backBufferBackgroundColor;
|
|
output.backBufferDepthParams.discardOnLastUse = true;
|
|
|
|
bool isBuiltInTexture = cameraData.targetTexture == null;
|
|
|
|
TextureUVOrigin backbufferTextureUVOrigin = RenderingUtils.GetBackBufferUVOrientation(cameraData);
|
|
|
|
output.backBufferColorParams.textureUVOrigin = backbufferTextureUVOrigin;
|
|
output.backBufferDepthParams.textureUVOrigin = backbufferTextureUVOrigin;
|
|
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
if (cameraData.xr.enabled)
|
|
{
|
|
isBuiltInTexture = false;
|
|
}
|
|
#endif
|
|
|
|
if (!isBuiltInTexture)
|
|
{
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
if (cameraData.xr.enabled)
|
|
{
|
|
output.importInfo.width = cameraData.xr.renderTargetDesc.width;
|
|
output.importInfo.height = cameraData.xr.renderTargetDesc.height;
|
|
output.importInfo.volumeDepth = cameraData.xr.renderTargetDesc.volumeDepth;
|
|
output.importInfo.msaaSamples = cameraData.xr.renderTargetDesc.msaaSamples;
|
|
output.importInfo.format = cameraData.xr.renderTargetDesc.graphicsFormat;
|
|
if (!UniversalRenderer.PlatformRequiresExplicitMsaaResolve())
|
|
output.importInfo.bindMS = output.importInfo.msaaSamples > 1;
|
|
|
|
output.importInfoDepth = output.importInfo;
|
|
output.importInfoDepth.format = cameraData.xr.renderTargetDesc.depthStencilFormat;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
output.importInfo.width = cameraData.targetTexture.width;
|
|
output.importInfo.height = cameraData.targetTexture.height;
|
|
output.importInfo.volumeDepth = cameraData.targetTexture.volumeDepth;
|
|
output.importInfo.msaaSamples = cameraData.targetTexture.antiAliasing;
|
|
output.importInfo.format = cameraData.targetTexture.graphicsFormat;
|
|
|
|
output.importInfoDepth = output.importInfo;
|
|
output.importInfoDepth.format = cameraData.targetTexture.depthStencilFormat;
|
|
|
|
// We let users know that a depth format is required for correct usage, but we fallback to the old default depth format behaviour to avoid regressions
|
|
if (output.importInfoDepth.format == GraphicsFormat.None)
|
|
{
|
|
output.importInfoDepth.format = SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil);
|
|
Debug.LogWarning("In the render graph API, the output Render Texture must have a depth buffer. When you select a Render Texture in any camera's Output Texture property, the Depth Stencil Format property of the texture must be set to a value other than None.");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Import the live back buffer sample count; it always matches the real surface even when a
|
|
// pending Screen.SetMSAASamples request hasn't been applied yet (deferred reallocation).
|
|
int numSamples = Screen.currentBackbufferMSAASamples;
|
|
|
|
//NOTE: Careful what you use here as many of the properties bake-in the camera rect so for example
|
|
//cameraData.cameraTargetDescriptor.width is the width of the rectangle but not the actual render target
|
|
//same with cameraData.camera.pixelWidth
|
|
output.importInfo.width = Screen.width;
|
|
output.importInfo.height = Screen.height;
|
|
output.importInfo.volumeDepth = 1;
|
|
output.importInfo.msaaSamples = numSamples;
|
|
output.importInfo.format = cameraData.cameraTargetDescriptor.graphicsFormat;
|
|
|
|
output.importInfoDepth = output.importInfo;
|
|
output.importInfoDepth.format = SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
public override void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters, ref CameraData cameraData)
|
|
{
|
|
cullingParameters.cullingOptions = CullingOptions.None;
|
|
cullingParameters.isOrthographic = cameraData.camera.orthographic;
|
|
cullingParameters.shadowDistance = 0.0f;
|
|
|
|
var cullResult = m_Renderer2DData.lightCullResult as Light2DCullResult;
|
|
cullResult.SetupCulling(ref cullingParameters, cameraData.camera);
|
|
}
|
|
|
|
void InitializeLayerBatches()
|
|
{
|
|
Universal2DResourceData resourceData = frameData.Get<Universal2DResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
Universal2DRenderingData renderData = frameData.Get<Universal2DRenderingData>();
|
|
ref var layerBatches = ref renderData.layerBatches;
|
|
|
|
layerBatches = LayerUtility.CalculateBatches(renderData.renderingData, out var batchCount);
|
|
renderData.batchCount = batchCount;
|
|
|
|
// Initialize textures dependent on batch size
|
|
if (resourceData.normalsTexture.Length != batchCount)
|
|
resourceData.normalsTexture = new TextureHandle[batchCount];
|
|
|
|
if (resourceData.shadowTextures.Length != batchCount)
|
|
resourceData.shadowTextures = new TextureHandle[batchCount][];
|
|
|
|
if (resourceData.lightTextures.Length != batchCount)
|
|
resourceData.lightTextures = new TextureHandle[batchCount][];
|
|
|
|
// Initialize light textures based on active blend styles to save on resources
|
|
for (int i = 0; i < resourceData.lightTextures.Length; ++i)
|
|
{
|
|
if (resourceData.lightTextures[i] == null || resourceData.lightTextures[i].Length != layerBatches[i].activeBlendStylesIndices.Length)
|
|
resourceData.lightTextures[i] = new TextureHandle[layerBatches[i].activeBlendStylesIndices.Length];
|
|
}
|
|
|
|
for (int i = 0; i < resourceData.shadowTextures.Length; ++i)
|
|
{
|
|
if (resourceData.shadowTextures[i] == null || resourceData.shadowTextures[i].Length != layerBatches[i].shadowIndices.Count)
|
|
resourceData.shadowTextures[i] = new TextureHandle[layerBatches[i].shadowIndices.Count];
|
|
}
|
|
}
|
|
|
|
void CreateResources(RenderGraph renderGraph)
|
|
{
|
|
Universal2DResourceData universal2DResourceData = frameData.Get<Universal2DResourceData>();
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor;
|
|
var cameraTargetFilterMode = FilterMode.Bilinear;
|
|
bool lastCameraInTheStack = cameraData.resolveFinalTarget;
|
|
|
|
#if UNITY_EDITOR
|
|
// The scene view camera cannot be uninitialized or skybox when using the 2D renderer.
|
|
if (cameraData.cameraType == CameraType.SceneView)
|
|
{
|
|
cameraData.camera.clearFlags = CameraClearFlags.SolidColor;
|
|
}
|
|
#endif
|
|
|
|
bool forceCreateColorTexture = false;
|
|
|
|
// Pixel Perfect Camera doesn't support camera stacking.
|
|
if (cameraData.renderType == CameraRenderType.Base && lastCameraInTheStack)
|
|
{
|
|
cameraData.camera.TryGetComponent<PixelPerfectCamera>(out var ppc);
|
|
if (ppc != null && ppc.enabled)
|
|
{
|
|
if (ppc.offscreenRTSize != Vector2Int.zero)
|
|
{
|
|
forceCreateColorTexture = true;
|
|
|
|
// Pixel Perfect Camera may request a different RT size than camera VP size.
|
|
// In that case we need to modify cameraTargetDescriptor here so that all the passes would use the same size.
|
|
cameraTargetDescriptor.width = ppc.offscreenRTSize.x;
|
|
cameraTargetDescriptor.height = ppc.offscreenRTSize.y;
|
|
}
|
|
|
|
cameraTargetFilterMode = FilterMode.Point;
|
|
ppcUpscaleRT = ppc.gridSnapping == PixelPerfectCamera.GridSnapping.UpscaleRenderTexture || ppc.requiresUpscalePass;
|
|
|
|
if (ppc.requiresUpscalePass)
|
|
{
|
|
var upscaleDescriptor = cameraTargetDescriptor;
|
|
upscaleDescriptor.width = ppc.refResolutionX * ppc.pixelRatio;
|
|
upscaleDescriptor.height = ppc.refResolutionY * ppc.pixelRatio;
|
|
upscaleDescriptor.depthStencilFormat = GraphicsFormat.None;
|
|
|
|
universal2DResourceData.upscaleTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, upscaleDescriptor, "_UpscaleTexture", true, ppc.finalBlitFilterMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Account for Quality->Render Scale and Light Texture Render Scale
|
|
var renderTextureScale = m_Renderer2DData.lightRenderTextureScale;
|
|
var width = (int)Mathf.Max(1, cameraTargetDescriptor.width * renderTextureScale);
|
|
var height = (int)Mathf.Max(1, cameraTargetDescriptor.height * renderTextureScale);
|
|
|
|
// Normals and Light textures have to be of the same renderTextureScale, to prevent any sampling artifacts during lighting calculations
|
|
CreateCameraNormalsTextures(renderGraph, cameraTargetDescriptor, width, height);
|
|
|
|
CreateLightTextures(renderGraph, width, height);
|
|
|
|
CreateShadowTextures(renderGraph, width, height);
|
|
|
|
CreateCameraSortingLayerTexture(renderGraph, cameraTargetDescriptor);
|
|
|
|
CreateRenderingLayersTexture(renderGraph, width, height);
|
|
|
|
// Create the attachments
|
|
if (cameraData.renderType == CameraRenderType.Base) // require intermediate textures
|
|
{
|
|
RenderPassInputSummary renderPassInputs = GetRenderPassInputs();
|
|
m_CreateColorTexture = renderPassInputs.requiresColorTexture;
|
|
m_CreateDepthTexture = renderPassInputs.requiresDepthTexture;
|
|
|
|
m_CreateColorTexture |= forceCreateColorTexture;
|
|
|
|
// Backdrop-filter compositing needs an intermediate color target to sample.
|
|
m_CreateColorTexture |= m_DrawOverlayUIPass.RequiresComposition();
|
|
|
|
// RTHandles do not support combining color and depth in the same texture so we create them separately
|
|
m_CreateDepthTexture |= m_CreateColorTexture;
|
|
m_CreateDepthTexture &= IsDepthUsageAllowed(frameData, m_Renderer2DData);
|
|
|
|
// Camera Target Color
|
|
if (m_CreateColorTexture)
|
|
{
|
|
cameraTargetDescriptor.useMipMap = false;
|
|
cameraTargetDescriptor.autoGenerateMips = false;
|
|
cameraTargetDescriptor.depthStencilFormat = GraphicsFormat.None;
|
|
|
|
RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraColorHandles[0], cameraTargetDescriptor, cameraTargetFilterMode, TextureWrapMode.Clamp, name: "_CameraTargetAttachmentA");
|
|
RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraColorHandles[1], cameraTargetDescriptor, cameraTargetFilterMode, TextureWrapMode.Clamp, name: "_CameraTargetAttachmentB");
|
|
commonResourceData.activeColorID = ActiveID.Camera;
|
|
}
|
|
else
|
|
commonResourceData.activeColorID = ActiveID.BackBuffer;
|
|
|
|
// Camera Target Depth
|
|
if (m_CreateDepthTexture)
|
|
{
|
|
var depthDescriptor = cameraData.cameraTargetDescriptor;
|
|
depthDescriptor.useMipMap = false;
|
|
depthDescriptor.autoGenerateMips = false;
|
|
|
|
bool hasMSAA = depthDescriptor.msaaSamples > 1;
|
|
depthDescriptor.bindMS = hasMSAA && RenderingUtils.ShouldDepthAttachmentBindMS();
|
|
|
|
depthDescriptor.graphicsFormat = GraphicsFormat.None;
|
|
depthDescriptor.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat();
|
|
|
|
RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraDepthHandle, depthDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_CameraDepthAttachment");
|
|
commonResourceData.activeDepthID = ActiveID.Camera;
|
|
}
|
|
else
|
|
commonResourceData.activeDepthID = ActiveID.BackBuffer;
|
|
}
|
|
else // Overlay camera
|
|
{
|
|
cameraData.baseCamera.TryGetComponent<UniversalAdditionalCameraData>(out var baseCameraData);
|
|
var baseRenderer = (Renderer2D)baseCameraData.scriptableRenderer;
|
|
|
|
m_RenderGraphBackbufferColorHandle = baseRenderer.m_RenderGraphBackbufferColorHandle;
|
|
m_RenderGraphBackbufferDepthHandle = baseRenderer.m_RenderGraphBackbufferDepthHandle;
|
|
|
|
m_CreateColorTexture = baseRenderer.m_CreateColorTexture;
|
|
m_CreateDepthTexture = baseRenderer.m_CreateDepthTexture;
|
|
|
|
commonResourceData.activeColorID = m_CreateColorTexture ? ActiveID.Camera : ActiveID.BackBuffer;
|
|
commonResourceData.activeDepthID = m_CreateDepthTexture ? ActiveID.Camera : ActiveID.BackBuffer;
|
|
}
|
|
|
|
// Report this camera's real back buffer MSAA need; a 2D camera renders directly to it only when
|
|
// no intermediate color texture is created (m_CreateColorTexture == false).
|
|
ReportRealBackbufferMSAA(cameraData, m_CreateColorTexture);
|
|
|
|
ImportResourceSummary importSummary = GetImportResourceSummary(renderGraph, cameraData);
|
|
|
|
if (m_CreateColorTexture)
|
|
{
|
|
importSummary.cameraColorParams.discardOnLastUse = lastCameraInTheStack;
|
|
commonResourceData.cameraColor = renderGraph.ImportTexture(currentRenderGraphCameraColorHandle, importSummary.cameraColorParams);
|
|
}
|
|
|
|
if (m_CreateDepthTexture)
|
|
{
|
|
importSummary.cameraDepthParams.discardOnLastUse = lastCameraInTheStack;
|
|
commonResourceData.cameraDepth = renderGraph.ImportTexture(s_RenderGraphCameraDepthHandle, importSummary.cameraDepthParams);
|
|
}
|
|
|
|
RenderTargetIdentifier targetColorId = cameraData.targetTexture != null ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;
|
|
RenderTargetIdentifier targetDepthId = cameraData.targetTexture != null ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.Depth;
|
|
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
if (cameraData.xr.enabled)
|
|
{
|
|
targetColorId = cameraData.xr.renderTarget;
|
|
targetDepthId = cameraData.xr.renderTarget;
|
|
}
|
|
#endif
|
|
|
|
if (m_RenderGraphBackbufferColorHandle == null)
|
|
{
|
|
m_RenderGraphBackbufferColorHandle = RTHandles.Alloc(targetColorId, "Backbuffer color");
|
|
}
|
|
else if (m_RenderGraphBackbufferColorHandle.nameID != targetColorId)
|
|
{
|
|
RTHandleStaticHelpers.SetRTHandleUserManagedWrapper(ref m_RenderGraphBackbufferColorHandle, targetColorId);
|
|
}
|
|
|
|
commonResourceData.backBufferColor = renderGraph.ImportTexture(m_RenderGraphBackbufferColorHandle, importSummary.importInfo, importSummary.backBufferColorParams);
|
|
|
|
if (IsDepthUsageAllowed(frameData, m_Renderer2DData))
|
|
{
|
|
if (m_RenderGraphBackbufferDepthHandle == null)
|
|
{
|
|
m_RenderGraphBackbufferDepthHandle = RTHandles.Alloc(targetDepthId, "Backbuffer depth");
|
|
}
|
|
else if (m_RenderGraphBackbufferDepthHandle.nameID != targetDepthId)
|
|
{
|
|
RTHandleStaticHelpers.SetRTHandleUserManagedWrapper(ref m_RenderGraphBackbufferDepthHandle, targetDepthId);
|
|
}
|
|
|
|
commonResourceData.backBufferDepth = renderGraph.ImportTexture(m_RenderGraphBackbufferDepthHandle, importSummary.importInfoDepth, importSummary.backBufferDepthParams);
|
|
}
|
|
|
|
if (RequiresDepthCopyPass())
|
|
CreateCameraDepthCopyTexture(renderGraph, cameraTargetDescriptor);
|
|
|
|
if (cameraData.isHDROutputActive && cameraData.rendersOverlayUI)
|
|
CreateOffscreenUITexture(renderGraph, cameraTargetDescriptor);
|
|
}
|
|
|
|
void CreateCameraNormalsTextures(RenderGraph renderGraph, RenderTextureDescriptor descriptor, int width, int height)
|
|
{
|
|
Universal2DResourceData resourceData = frameData.Get<Universal2DResourceData>();
|
|
var layerBatches = frameData.Get<Universal2DRenderingData>().layerBatches;
|
|
|
|
var desc = new RenderTextureDescriptor(width, height);
|
|
desc.graphicsFormat = RendererLighting.GetRenderTextureFormat();
|
|
desc.autoGenerateMips = false;
|
|
desc.msaaSamples = descriptor.msaaSamples;
|
|
bool useNormals = false;
|
|
|
|
for (int i = 0; i < resourceData.normalsTexture.Length; ++i)
|
|
{
|
|
useNormals |= layerBatches[i].useNormals;
|
|
if (layerBatches[i].useNormals)
|
|
{
|
|
resourceData.normalsTexture[i] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_NormalMap", true, RendererLighting.k_NormalClearColor);
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
if (canProfilerCapture)
|
|
ProfilerMarkers.s_U2DNormalMapProfilerCounterValue.Value++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (useNormals && IsDepthUsageAllowed(frameData, m_Renderer2DData))
|
|
{
|
|
// Normals pass can reuse active depth if same dimensions, if not create a new depth texture
|
|
#if !(ENABLE_VR && ENABLE_XR_MODULE)
|
|
if (descriptor.width != width || descriptor.height != height)
|
|
#endif
|
|
{
|
|
var normalsDepthDesc = new RenderTextureDescriptor(width, height);
|
|
normalsDepthDesc.graphicsFormat = GraphicsFormat.None;
|
|
normalsDepthDesc.autoGenerateMips = false;
|
|
normalsDepthDesc.msaaSamples = descriptor.msaaSamples;
|
|
normalsDepthDesc.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat();
|
|
|
|
resourceData.normalsDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, normalsDepthDesc, "_NormalDepth", false, FilterMode.Bilinear);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CreateLightTextures(RenderGraph renderGraph, int width, int height)
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
Universal2DResourceData resourceData = frameData.Get<Universal2DResourceData>();
|
|
var layerBatches = frameData.Get<Universal2DRenderingData>().layerBatches;
|
|
|
|
var desc = new RenderTextureDescriptor(width, height);
|
|
desc.graphicsFormat = RendererLighting.GetRenderTextureFormat();
|
|
desc.autoGenerateMips = false;
|
|
|
|
for (int i = 0; i < resourceData.lightTextures.Length; ++i)
|
|
{
|
|
for (var j = 0; j < layerBatches[i].activeBlendStylesIndices.Length; ++j)
|
|
{
|
|
var index = layerBatches[i].activeBlendStylesIndices[j];
|
|
if (!Light2DManager.GetGlobalColor(layerBatches[i].startLayerID, index, cameraData.camera, out var clearColor))
|
|
clearColor = Color.black;
|
|
|
|
resourceData.lightTextures[i][j] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, RendererLighting.k_ShapeLightTextureIDs[index], true, clearColor, FilterMode.Bilinear);
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
if (canProfilerCapture)
|
|
ProfilerMarkers.s_U2DLightProfilerCounterValue.Value++;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void CreateShadowTextures(RenderGraph renderGraph, int width, int height)
|
|
{
|
|
Universal2DResourceData resourceData = frameData.Get<Universal2DResourceData>();
|
|
var layerBatches = frameData.Get<Universal2DRenderingData>().layerBatches;
|
|
|
|
var shadowDesc = new RenderTextureDescriptor(width, height);
|
|
shadowDesc.graphicsFormat = GraphicsFormat.B10G11R11_UFloatPack32;
|
|
shadowDesc.autoGenerateMips = false;
|
|
|
|
for (int i = 0; i < resourceData.shadowTextures.Length; ++i)
|
|
{
|
|
for (var j = 0; j < layerBatches[i].shadowIndices.Count; ++j)
|
|
{
|
|
resourceData.shadowTextures[i][j] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, shadowDesc, "_ShadowTex", false, FilterMode.Bilinear);
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
if (canProfilerCapture)
|
|
ProfilerMarkers.s_U2DShadowProfilerCounterValue.Value++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
var shadowDepthDesc = new RenderTextureDescriptor(width, height);
|
|
shadowDepthDesc.graphicsFormat = GraphicsFormat.None;
|
|
shadowDepthDesc.autoGenerateMips = false;
|
|
shadowDepthDesc.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat();
|
|
|
|
resourceData.shadowDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, shadowDepthDesc, "_ShadowDepth", false, FilterMode.Bilinear);
|
|
}
|
|
|
|
void CreateCameraSortingLayerTexture(RenderGraph renderGraph, RenderTextureDescriptor cameraDesc)
|
|
{
|
|
if (m_Renderer2DData.useCameraSortingLayerTexture)
|
|
{
|
|
Universal2DResourceData resourceData = frameData.Get<Universal2DResourceData>();
|
|
|
|
CopyCameraSortingLayerPass.ConfigureDescriptor(m_Renderer2DData.cameraSortingLayerDownsamplingMethod, ref cameraDesc, out var filterMode);
|
|
RenderingUtils.ReAllocateHandleIfNeeded(ref m_CameraSortingLayerHandle, cameraDesc, filterMode, TextureWrapMode.Clamp, name: CopyCameraSortingLayerPass.k_CameraSortingLayerTexture);
|
|
resourceData.cameraSortingLayerTexture = renderGraph.ImportTexture(m_CameraSortingLayerHandle);
|
|
}
|
|
}
|
|
|
|
void CreateRenderingLayersTexture(RenderGraph renderGraph, int width, int height)
|
|
{
|
|
if (m_Renderer2DData.useRenderingLayers)
|
|
{
|
|
var resourceData = frameData.Get<Universal2DResourceData>();
|
|
|
|
int count = RenderingLayerMask.GetRenderingLayerCount();
|
|
m_Renderer2DData.renderingLayersMaskSize = RenderingLayerUtils.GetMaskSize(count);
|
|
|
|
var desc = new RenderTextureDescriptor(width, height);
|
|
desc.graphicsFormat = RenderingLayerUtils.GetFormat(m_Renderer2DData.renderingLayersMaskSize);
|
|
desc.autoGenerateMips = false;
|
|
|
|
resourceData.renderingLayersTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, CameraRenderingLayerMaskPass.k_RenderingLayersTextureName, true);
|
|
}
|
|
}
|
|
|
|
bool RequiresDepthCopyPass()
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
var renderPassInputs = GetRenderPassInputs();
|
|
bool requiresDepthTexture = cameraData.requiresDepthTexture || renderPassInputs.requiresDepthTexture;
|
|
bool cameraHasPostProcessingWithDepth = cameraData.postProcessEnabled && m_PostProcess != null && (cameraData.postProcessingRequiresDepthTexture || !LensFlareCommonSRP.Instance.IsEmpty());
|
|
bool requiresDepthCopyPass = (cameraHasPostProcessingWithDepth || requiresDepthTexture) && m_CreateDepthTexture;
|
|
|
|
return requiresDepthCopyPass;
|
|
}
|
|
|
|
void CreateCameraDepthCopyTexture(RenderGraph renderGraph, RenderTextureDescriptor descriptor)
|
|
{
|
|
CommonResourceData resourceData = frameData.Get<CommonResourceData>();
|
|
|
|
var depthDescriptor = descriptor;
|
|
depthDescriptor.msaaSamples = 1;// Depth-Only pass don't use MSAA
|
|
if (PlatformAutoDetect.hasRenderToR32F)
|
|
{
|
|
depthDescriptor.graphicsFormat = GraphicsFormat.R32_SFloat;
|
|
depthDescriptor.depthStencilFormat = GraphicsFormat.None;
|
|
}
|
|
else
|
|
{
|
|
depthDescriptor.graphicsFormat = GraphicsFormat.None;
|
|
depthDescriptor.depthStencilFormat = CoreUtils.GetDefaultDepthOnlyFormat();
|
|
}
|
|
|
|
resourceData.cameraDepthTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDescriptor, "_CameraDepthTexture", true);
|
|
}
|
|
|
|
void CreateOffscreenUITexture(RenderGraph renderGraph, in RenderTextureDescriptor descriptor)
|
|
{
|
|
UniversalResourceData resourceData = frameData.Get<CommonResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
TextureDesc textureDesc = new TextureDesc(descriptor);
|
|
DrawScreenSpaceUIPass.ConfigureOffscreenUITextureDesc(ref textureDesc);
|
|
RenderingUtils.ReAllocateHandleIfNeeded(ref s_OffscreenUIColorHandle, textureDesc, name: "_OverlayUITexture");
|
|
|
|
// Clear the texture to avoid stale data from previous frames
|
|
ImportResourceParams importParams = new ImportResourceParams();
|
|
importParams.clearOnFirstUse = cameraData.rendersOffscreenUI;
|
|
importParams.clearColor = Color.clear;
|
|
importParams.discardOnLastUse = false;
|
|
resourceData.overlayUITexture = renderGraph.ImportTexture(s_OffscreenUIColorHandle, importParams);
|
|
}
|
|
|
|
public override void OnBeginRenderGraphFrame()
|
|
{
|
|
Universal2DResourceData universal2DResourceData = frameData.Create<Universal2DResourceData>();
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
frameData.Create<Universal2DRenderingData>().renderingData = m_Renderer2DData;
|
|
|
|
universal2DResourceData.InitFrame();
|
|
commonResourceData.InitFrame();
|
|
}
|
|
|
|
internal void RecordCustomRenderGraphPasses(RenderGraph renderGraph, RenderPassEvent2D eventStart, int batchIndex = -1)
|
|
{
|
|
foreach (ScriptableRenderPass pass in activeRenderPassQueue)
|
|
{
|
|
var batchCount = frameData.Get<Universal2DRenderingData>().batchCount;
|
|
var isBatchValid = batchIndex >= 0 && batchIndex < batchCount;
|
|
|
|
pass.GetInjectionPoint2D(out RenderPassEvent2D rpEvent, out int layerID);
|
|
int range = ScriptableRenderPass2D.GetRenderPassEventRange(eventStart);
|
|
|
|
// Account for render passes in between events.
|
|
if (rpEvent >= eventStart && rpEvent < eventStart + range)
|
|
{
|
|
// Invalid sorting layer specified for render pass
|
|
if (!SortingLayer.IsValid(layerID) && ScriptableRenderPass2D.IsSortingLayerEvent(rpEvent))
|
|
{
|
|
Debug.Assert(SortingLayer.IsValid(layerID), SortingLayer.IDToName(layerID) + " is not a valid Sorting Layer.");
|
|
}
|
|
// BatchIndex is valid
|
|
else if (isBatchValid)
|
|
{
|
|
var layerBatch = frameData.Get<Universal2DRenderingData>().layerBatches[batchIndex];
|
|
|
|
if (layerBatch.IsValueWithinLayerRange(SortingLayer.GetLayerValueFromID(layerID)))
|
|
pass.RecordRenderGraph(renderGraph, frameData);
|
|
}
|
|
else
|
|
pass.RecordRenderGraph(renderGraph, frameData);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void OnRecordRenderGraph(RenderGraph renderGraph, ScriptableRenderContext context)
|
|
{
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
// canProfilerCapture is initialized here and can only be used after
|
|
s_CanProfilerCapture = cameraData.isGameCamera;
|
|
#endif
|
|
|
|
InitializeLayerBatches();
|
|
|
|
// Before CreateResources: it reads RequiresComposition() to force an intermediate color target.
|
|
m_DrawOverlayUIPass.Setup(cameraData);
|
|
|
|
CreateResources(renderGraph);
|
|
|
|
DebugHandler?.Setup(renderGraph, cameraData.isPreviewCamera);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRendering);
|
|
|
|
SetupRenderGraphCameraProperties(renderGraph, commonResourceData.activeColorTexture);
|
|
|
|
#if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER
|
|
ProcessVFXCameraCommand(renderGraph);
|
|
#endif
|
|
|
|
OnBeforeRendering(renderGraph);
|
|
|
|
BeginRenderGraphXRRendering(renderGraph);
|
|
|
|
OnMainRendering(renderGraph);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingPostProcessing);
|
|
|
|
OnAfterRendering(renderGraph);
|
|
|
|
EndRenderGraphXRRendering(renderGraph);
|
|
}
|
|
|
|
public override void OnEndRenderGraphFrame()
|
|
{
|
|
Universal2DResourceData universal2DResourceData = frameData.Get<Universal2DResourceData>();
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
universal2DResourceData.EndFrame();
|
|
commonResourceData.EndFrame();
|
|
}
|
|
|
|
internal override void OnFinishRenderGraphRendering(CommandBuffer cmd)
|
|
{
|
|
m_CopyDepthPass?.OnCameraCleanup(cmd);
|
|
}
|
|
|
|
private void OnBeforeRendering(RenderGraph renderGraph)
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
var renderingData = frameData.Get<Universal2DRenderingData>().renderingData;
|
|
|
|
m_LightPass.Setup(renderGraph, frameData);
|
|
|
|
// Before rendering the lights cache some values that are expensive to get/calculate
|
|
var culledLights = renderingData.lightCullResult.visibleLights;
|
|
for (var i = 0; i < culledLights.Count; i++)
|
|
{
|
|
culledLights[i].CacheValues();
|
|
}
|
|
|
|
ShadowCasterGroup2DManager.CacheValues();
|
|
ShadowRendering.CallOnBeforeRender(cameraData.camera, renderingData.lightCullResult);
|
|
|
|
RendererLighting.lightBatch.Reset();
|
|
}
|
|
|
|
private void OnMainRendering(RenderGraph renderGraph)
|
|
{
|
|
Universal2DResourceData universal2DResourceData = frameData.Get<Universal2DResourceData>();
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
var layerBatches = frameData.Get<Universal2DRenderingData>().layerBatches;
|
|
var batchCount = frameData.Get<Universal2DRenderingData>().batchCount;
|
|
|
|
// Color Grading LUT
|
|
bool requiredColorGradingLutPass = cameraData.postProcessEnabled && m_PostProcess != null;
|
|
|
|
if (requiredColorGradingLutPass)
|
|
{
|
|
TextureHandle internalColorLut = TextureHandle.nullHandle;
|
|
m_ColorGradingLutPassRenderGraph.Render(renderGraph, frameData, out internalColorLut);
|
|
commonResourceData.internalColorLut = internalColorLut;
|
|
}
|
|
|
|
var cameraSortingLayerBoundsIndex = m_Renderer2DData.GetCameraSortingLayerBoundsIndex();
|
|
|
|
bool useLights = false;
|
|
for (int i = 0; i < batchCount; ++i)
|
|
useLights |= layerBatches[i].lightStats.useLights;
|
|
|
|
// Set Global Properties and Textures
|
|
GlobalPropertiesPass.Setup(renderGraph, frameData, useLights);
|
|
|
|
// Main render passes
|
|
|
|
// Rendering Layer Mask Prepass
|
|
m_RenderingLayerMaskPass.Render(renderGraph, frameData);
|
|
|
|
// Normal Pass
|
|
for (var i = 0; i < batchCount; i++)
|
|
{
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingNormals, i);
|
|
|
|
m_NormalPass.Render(renderGraph, frameData, i);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingNormals, i);
|
|
}
|
|
|
|
// Shadow Pass (TODO: Optimize RT swapping between shadow and light textures)
|
|
for (var i = 0; i < batchCount; i++)
|
|
{
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingShadows, i);
|
|
|
|
m_ShadowPass.Render(renderGraph, frameData, i);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingShadows, i);
|
|
}
|
|
|
|
// Light Pass
|
|
for (var i = 0; i < batchCount; i++)
|
|
{
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingLights, i);
|
|
|
|
m_LightPass.Render(renderGraph, frameData, i);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingLights, i);
|
|
}
|
|
|
|
#if ENABLE_PROFILER && PROFILER_INSTALLED
|
|
if (canProfilerCapture)
|
|
{
|
|
ProfilerMarkers.s_ShadowMeshFrameData.Emit();
|
|
ProfilerMarkers.s_ShadowRenderFrameData.Emit();
|
|
|
|
ProfilerMarkers.s_LightMeshFrameData.Emit();
|
|
ProfilerMarkers.s_LightRenderFrameData.Emit();
|
|
}
|
|
#endif
|
|
|
|
// Default Render Pass
|
|
for (var i = 0; i < batchCount; i++)
|
|
{
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingSprites, i);
|
|
|
|
LayerUtility.GetFilterSettings(m_Renderer2DData, layerBatches[i], out var filterSettings);
|
|
m_RendererPass.Render(renderGraph, frameData, i, ref filterSettings);
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingSprites, i);
|
|
|
|
// Shadow Volumetric Pass
|
|
m_ShadowPass.Render(renderGraph, frameData, i, true);
|
|
|
|
// Light Volumetric Pass
|
|
m_LightPass.Render(renderGraph, frameData, i, true);
|
|
|
|
// Camera Sorting Layer Pass
|
|
if (m_Renderer2DData.useCameraSortingLayerTexture)
|
|
{
|
|
ref var layerBatch = ref layerBatches[i];
|
|
|
|
if (layerBatch.IsValueWithinLayerRange(cameraSortingLayerBoundsIndex))
|
|
{
|
|
m_CopyCameraSortingLayerPass.Render(renderGraph, frameData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RequiresDepthCopyPass())
|
|
m_CopyDepthPass?.Render(renderGraph, frameData, commonResourceData.cameraDepthTexture, commonResourceData.activeDepthTexture, true);
|
|
|
|
bool shouldRenderUI = cameraData.rendersOverlayUI;
|
|
bool outputToHDR = cameraData.isHDROutputActive;
|
|
if (shouldRenderUI && outputToHDR)
|
|
{
|
|
if (cameraData.rendersOffscreenUI)
|
|
{
|
|
m_DrawOffscreenUIPass.RenderOffscreen(renderGraph, frameData, CoreUtils.GetDefaultDepthStencilFormat(), commonResourceData.overlayUITexture);
|
|
if (cameraData.blitsOffscreenUICover)
|
|
m_OffscreenUICoverPrepass.Render(renderGraph, cameraData, commonResourceData, renderGraph.defaultResources.blackTexture, true);
|
|
}
|
|
else
|
|
{
|
|
// When the first camera renders the shared offscreen UI texture, register it as a global texture so subsequent cameras can use it in their final passes.
|
|
RenderGraphUtils.SetGlobalTexture(renderGraph, ShaderPropertyId.overlayUITexture, commonResourceData.overlayUITexture);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnAfterRendering(RenderGraph renderGraph)
|
|
{
|
|
Universal2DResourceData universal2DResourceData = frameData.Get<Universal2DResourceData>();
|
|
CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalPostProcessingData postProcessingData = frameData.Get<UniversalPostProcessingData>();
|
|
|
|
bool drawGizmos = UniversalRenderPipelineDebugDisplaySettings.Instance.renderingSettings.sceneOverrideMode == DebugSceneOverrideMode.None;
|
|
|
|
if (drawGizmos)
|
|
DrawRenderGraphGizmos(renderGraph, frameData, commonResourceData.activeColorTexture, commonResourceData.activeDepthTexture, GizmoSubset.PreImageEffects);
|
|
|
|
DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData);
|
|
bool resolveToDebugScreen = debugHandler != null && debugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget);
|
|
|
|
//When the debughandler displays HDR debug views, it needs to redirect (final) post-process output to an intermediate color target (debugScreenTexture).
|
|
//Therefore, we swap the backbuffer textures for the debug screen textures such that the next post processing passes don't need to be aware of the debug handler at all.
|
|
//At the end, when the handler is active, we swap them back. This isolates the debug handler code from the sequence of post process passes and is a common pattern to
|
|
//use the resourceData.
|
|
var debugRealBackBufferColor = TextureHandle.nullHandle;
|
|
var debugRealBackBufferDepth = TextureHandle.nullHandle;
|
|
|
|
// Allocate debug screen texture if the debug mode needs it.
|
|
if (resolveToDebugScreen)
|
|
{
|
|
debugRealBackBufferColor = commonResourceData.backBufferColor;
|
|
debugRealBackBufferDepth = commonResourceData.backBufferDepth;
|
|
|
|
RenderTextureDescriptor colorDesc = cameraData.cameraTargetDescriptor;
|
|
DebugHandler.ConfigureColorDescriptorForDebugScreen(ref colorDesc, cameraData.pixelWidth, cameraData.pixelHeight);
|
|
commonResourceData.backBufferColor = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_DebugScreenColor", false);
|
|
|
|
RenderTextureDescriptor depthDesc = cameraData.cameraTargetDescriptor;
|
|
DebugHandler.ConfigureDepthDescriptorForDebugScreen(ref depthDesc, CoreUtils.GetDefaultDepthStencilFormat(), cameraData.pixelWidth, cameraData.pixelHeight);
|
|
commonResourceData.backBufferDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_DebugScreenDepth", false);
|
|
}
|
|
|
|
bool applyPostProcessing = cameraData.postProcessEnabled && m_PostProcess != null;
|
|
bool anyPostProcessing = postProcessingData.isEnabled && m_PostProcess != null;
|
|
|
|
#if ENABLE_UPSCALER_FRAMEWORK
|
|
bool fsr1Enabled = cameraData.resolvedUpscalerHash == UniversalRenderPipeline.k_UpscalerHash_FSR1;
|
|
#else
|
|
bool fsr1Enabled = cameraData.upscalingFilter == ImageUpscalingFilter.FSR;
|
|
#endif
|
|
|
|
bool requirePixelPerfectUpscale = IsPixelPerfectCameraEnabled(cameraData, out var ppc) && ppc.requiresUpscalePass;
|
|
|
|
// When using Upscale Render Texture on a Pixel Perfect Camera, we want all post-processing effects done with a low-res RT,
|
|
// and only upscale the low-res RT to fullscreen when blitting it to camera target. Also, final post processing pass is not run in this case,
|
|
// so FXAA is not supported (you don't want to apply FXAA when everything is intentionally pixelated).
|
|
// FSR1 also requires the final pass (unlike upscalers using IUpscaler, it does not self-schedule).
|
|
bool applyFinalPostProcessing = cameraData.resolveFinalTarget && !ppcUpscaleRT && anyPostProcessing &&
|
|
((cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing) ||
|
|
(cameraData.imageScalingMode == ImageScalingMode.Upscaling && fsr1Enabled));
|
|
|
|
bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing || (x as ScriptableRenderPass2D)?.renderPassEvent2D == RenderPassEvent2D.AfterRenderingPostProcessing) != null;
|
|
bool needsColorEncoding = !resolveToDebugScreen;
|
|
|
|
// Don't resolve during post processing if there are passes after or pixel perfect camera is used
|
|
bool pixelPerfectCameraEnabled = ppc != null && ppc.enabled;
|
|
bool hasCaptureActions = cameraData.captureActions != null && cameraData.resolveFinalTarget;
|
|
bool resolvePostProcessingToCameraTarget = cameraData.resolveFinalTarget && !hasCaptureActions && !hasPassesAfterPostProcessing && !applyFinalPostProcessing && !pixelPerfectCameraEnabled && !m_DrawOverlayUIPass.RequiresComposition();
|
|
bool doSRGBEncoding = resolvePostProcessingToCameraTarget && needsColorEncoding;
|
|
|
|
if (applyPostProcessing)
|
|
{
|
|
bool isTargetBackbuffer = resolvePostProcessingToCameraTarget;
|
|
|
|
if(isTargetBackbuffer)
|
|
{
|
|
commonResourceData.SwitchActiveTexturesToBackbuffer();
|
|
}
|
|
else
|
|
{
|
|
// if the postprocessing pass is trying to read and write to the same CameraColor target, we need to swap so it writes to a different target,
|
|
// since reading a pass attachment is not possible. Normally this would be possible using temporary RenderGraph managed textures.
|
|
// The reason why in this case we need to use "external" RTHandles is to preserve the results for camera stacking.
|
|
// TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we can just use temporary RenderGraph textures as intermediate buffer.
|
|
ImportResourceParams importColorParams = new ImportResourceParams();
|
|
importColorParams.clearOnFirstUse = true;
|
|
importColorParams.clearColor = Color.black;
|
|
importColorParams.discardOnLastUse = cameraData.resolveFinalTarget; // check if last camera in the stack
|
|
|
|
commonResourceData.destinationCameraColor = renderGraph.ImportTexture(nextRenderGraphCameraColorHandle, importColorParams);
|
|
}
|
|
|
|
m_PostProcess.RenderPostProcessing(
|
|
renderGraph,
|
|
frameData,
|
|
applyFinalPostProcessing,
|
|
doSRGBEncoding);
|
|
|
|
}
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingPostProcessing);
|
|
|
|
// Do PixelPerfect upscaling when using the Stretch Fill option
|
|
if (requirePixelPerfectUpscale)
|
|
{
|
|
m_UpscalePass.Render(renderGraph, cameraData.camera, commonResourceData.cameraColor, universal2DResourceData.upscaleTexture);
|
|
commonResourceData.cameraColor = universal2DResourceData.upscaleTexture;
|
|
}
|
|
|
|
// Capture pass for Unity Recorder
|
|
if (hasCaptureActions)
|
|
{
|
|
m_CapturePass.RecordRenderGraph(renderGraph, frameData);
|
|
}
|
|
|
|
// Composite needs cameraColor, so blit it into the overlay buffer before final post / the final blit
|
|
// swap it to the backbuffer. Skipped once the active target is already the backbuffer.
|
|
bool renderOverlayComposite = m_DrawOverlayUIPass.RequiresComposition() && !commonResourceData.isActiveTargetBackBuffer;
|
|
if (renderOverlayComposite)
|
|
m_DrawOverlayUIPass.BlitCameraColorToOverlayCompositeBuffer(renderGraph, commonResourceData, cameraData.pixelRect, CoreUtils.GetDefaultDepthStencilFormat());
|
|
|
|
if (applyFinalPostProcessing)
|
|
{
|
|
//Will swap the active camera targets to backbuffer (resourceData.SwitchActiveTexturesToBackbuffer)
|
|
m_PostProcess.RenderFinalPostProcessing(renderGraph, frameData, needsColorEncoding);
|
|
}
|
|
|
|
if (!commonResourceData.isActiveTargetBackBuffer && cameraData.resolveFinalTarget)
|
|
{
|
|
//Will swap the active camera targets to backbuffer (resourceData.SwitchActiveTexturesToBackbuffer)
|
|
m_FinalBlitPass.RecordRenderGraph(renderGraph, frameData);
|
|
}
|
|
|
|
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRendering);
|
|
|
|
// We can explicitly render the overlay UI from URP when HDR output is not enabled.
|
|
// SupportedRenderingFeatures.active.rendersUIOverlay should also be set to true.
|
|
bool shouldRenderUI = cameraData.rendersOverlayUI && cameraData.isLastBaseCamera;
|
|
bool outputToHDR = cameraData.isHDROutputActive;
|
|
if (shouldRenderUI && !outputToHDR)
|
|
{
|
|
var color = commonResourceData.backBufferColor;
|
|
var depth = commonResourceData.backBufferDepth;
|
|
|
|
if (renderOverlayComposite)
|
|
m_DrawOverlayUIPass.RenderOverlayUIToolkitAndUGUIComposite(renderGraph, frameData, in color);
|
|
else
|
|
m_DrawOverlayUIPass.RenderOverlayUIToolkitAndUGUI(renderGraph, frameData, in color, in depth);
|
|
|
|
m_DrawOverlayUIPass.RenderOverlayIMGUI(renderGraph, frameData, in color, in depth);
|
|
}
|
|
|
|
// If HDR debug views are enabled, debugHandler will perform the blit from debugScreenColor (== finalColorHandle) to backBufferColor.
|
|
if (resolveToDebugScreen)
|
|
{
|
|
debugHandler.Render(renderGraph, cameraData, commonResourceData.backBufferColor, commonResourceData.overlayUITexture, debugRealBackBufferColor);
|
|
|
|
//Swapping the backbuffer textures back
|
|
commonResourceData.backBufferColor = debugRealBackBufferColor;
|
|
commonResourceData.backBufferDepth = debugRealBackBufferDepth;
|
|
}
|
|
|
|
if (cameraData.resolveFinalTarget)
|
|
{
|
|
if (cameraData.isSceneViewCamera)
|
|
DrawRenderGraphWireOverlay(renderGraph, frameData, commonResourceData.activeColorTexture);
|
|
|
|
if (drawGizmos)
|
|
DrawRenderGraphGizmos(renderGraph, frameData, commonResourceData.activeColorTexture, commonResourceData.activeDepthTexture, GizmoSubset.PostImageEffects);
|
|
}
|
|
}
|
|
|
|
public Renderer2DData GetRenderer2DData()
|
|
{
|
|
return m_Renderer2DData;
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
CleanupRenderGraphResources();
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
private void CleanupRenderGraphResources()
|
|
{
|
|
m_Renderer2DData.Dispose();
|
|
m_CopyDepthPass?.Dispose();
|
|
m_FinalBlitPass?.Dispose();
|
|
m_OffscreenUICoverPrepass?.Dispose();
|
|
m_DrawOffscreenUIPass?.Dispose();
|
|
m_DrawOverlayUIPass?.Dispose();
|
|
m_PostProcess?.Dispose();
|
|
m_RenderingLayerMaskPass.Dispose();
|
|
m_ColorGradingLutPassRenderGraph?.Cleanup();
|
|
|
|
s_RenderGraphCameraColorHandles[0]?.Release();
|
|
s_RenderGraphCameraColorHandles[1]?.Release();
|
|
s_RenderGraphCameraDepthHandle?.Release();
|
|
m_RenderGraphBackbufferColorHandle?.Release();
|
|
m_RenderGraphBackbufferDepthHandle?.Release();
|
|
m_CameraSortingLayerHandle?.Release();
|
|
s_OffscreenUIColorHandle?.Release();
|
|
|
|
Light2DManager.Dispose();
|
|
Light2DLookupTexture.Release();
|
|
LensFlareCommonSRP.Dispose();
|
|
|
|
CoreUtils.Destroy(m_BlitMaterial);
|
|
CoreUtils.Destroy(m_BlitHDRMaterial);
|
|
CoreUtils.Destroy(m_BlitOffscreenUICoverMaterial);
|
|
CoreUtils.Destroy(m_SamplingMaterial);
|
|
CoreUtils.Destroy(m_BackdropFilterCompositeMaterial);
|
|
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
XRSystem.Dispose();
|
|
#endif
|
|
}
|
|
|
|
internal static bool IsGLESDevice()
|
|
{
|
|
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3;
|
|
}
|
|
|
|
internal static bool supportsMRT
|
|
{
|
|
get => !IsGLESDevice();
|
|
}
|
|
|
|
internal static bool IsSceneViewOrPreviewLightingActive(UniversalCameraData cameraData)
|
|
{
|
|
DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData);
|
|
var isLightingActive = debugHandler?.IsLightingActive ?? true;
|
|
|
|
#if UNITY_EDITOR
|
|
if (cameraData.isSceneViewCamera && UnityEditor.SceneView.currentDrawingSceneView != null)
|
|
isLightingActive &= UnityEditor.SceneView.currentDrawingSceneView.sceneLighting;
|
|
#endif
|
|
|
|
return isLightingActive;
|
|
}
|
|
}
|
|
}
|