using System;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.Universal.Internal
{
///
/// Copy the given color target to the current camera target
///
/// You can use this pass to copy the result of rendering to
/// the camera target. The pass takes the screen viewport into
/// consideration.
///
public class FinalBlitPass : ScriptableRenderPass
{
RTHandle m_Source;
Material m_BlitMaterial;
Material m_BlitHDRMaterial;
RTHandle m_CameraTargetHandle;
///
/// Creates a new FinalBlitPass instance.
///
/// The RenderPassEvent to use.
/// The Material to use for copying the executing the final blit.
/// The Material to use for copying the executing the final blit when HDR output is active.
///
public FinalBlitPass(RenderPassEvent evt, Material blitMaterial, Material blitHDRMaterial)
{
base.profilingSampler = new ProfilingSampler(nameof(FinalBlitPass));
base.useNativeRenderPass = false;
m_BlitMaterial = blitMaterial;
m_BlitHDRMaterial = blitHDRMaterial;
renderPassEvent = evt;
}
///
/// Cleans up resources used by the pass.
///
public void Dispose()
{
m_CameraTargetHandle?.Release();
}
///
/// Configure the pass
///
///
///
[Obsolete("Use RTHandles for colorHandle")]
public void Setup(RenderTextureDescriptor baseDescriptor, RenderTargetHandle colorHandle)
{
if (m_Source?.nameID != colorHandle.Identifier())
m_Source = RTHandles.Alloc(colorHandle.Identifier());
}
///
/// Configure the pass
///
///
///
public void Setup(RenderTextureDescriptor baseDescriptor, RTHandle colorHandle)
{
m_Source = colorHandle;
}
static void SetupHDROutput(Material material, HDROutputUtils.Operation hdrOperation, Vector4 hdrOutputParameters)
{
material.SetVector(ShaderPropertyId.hdrOutputLuminanceParams, hdrOutputParameters);
HDROutputUtils.ConfigureHDROutput(material, HDROutputSettings.main.displayColorGamut, hdrOperation);
}
///
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
bool outputsToHDR = renderingData.cameraData.isHDROutputActive;
Material blitMaterial = outputsToHDR ? m_BlitHDRMaterial : m_BlitMaterial;
if (blitMaterial == null)
{
Debug.LogErrorFormat("Missing {0}. {1} render pass will not execute. Check for missing reference in the renderer resources.", blitMaterial, GetType().Name);
return;
}
ref CameraData cameraData = ref renderingData.cameraData;
var cameraTarget = RenderingUtils.GetCameraTargetIdentifier(ref renderingData);
DebugHandler debugHandler = GetActiveDebugHandler(ref renderingData);
bool resolveToDebugScreen = debugHandler != null && debugHandler.WriteToDebugScreenTexture(ref cameraData);
if (!resolveToDebugScreen)
{
// Create RTHandle alias to use RTHandle apis
if (m_CameraTargetHandle != cameraTarget)
{
m_CameraTargetHandle?.Release();
m_CameraTargetHandle = RTHandles.Alloc(cameraTarget);
}
}
var cmd = renderingData.commandBuffer;
if (m_Source == cameraData.renderer.GetCameraColorFrontBuffer(cmd))
{
m_Source = renderingData.cameraData.renderer.cameraColorTargetHandle;
}
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.FinalBlit)))
{
blitMaterial.enabledKeywords = null;
debugHandler?.UpdateShaderGlobalPropertiesForFinalValidationPass(cmd, ref cameraData, !resolveToDebugScreen);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.LinearToSRGBConversion,
cameraData.requireSrgbConversion);
if (outputsToHDR)
{
VolumeStack stack = VolumeManager.instance.stack;
Tonemapping tonemapping = stack.GetComponent();
Vector4 hdrOutputLuminanceParams;
UniversalRenderPipeline.GetHDROutputLuminanceParameters(tonemapping, out hdrOutputLuminanceParams);
HDROutputUtils.Operation hdrOperation = HDROutputUtils.Operation.None;
// If the HDRDebugView is on, we don't want the encoding
if (debugHandler == null || !debugHandler.HDRDebugViewIsActive(ref cameraData))
hdrOperation |= HDROutputUtils.Operation.ColorEncoding;
// Color conversion may have happened in the Uber post process through color grading, so we don't want to reapply it
if (!cameraData.postProcessEnabled)
hdrOperation |= HDROutputUtils.Operation.ColorConversion;
SetupHDROutput(blitMaterial, hdrOperation, hdrOutputLuminanceParams);
}
if (resolveToDebugScreen)
{
debugHandler.BlitTextureToDebugScreenTexture(cmd, m_Source, blitMaterial, m_Source.rt?.filterMode == FilterMode.Bilinear ? 1 : 0);
}
else
{
FinalBlitPass.ExecutePass(ref renderingData, blitMaterial, m_CameraTargetHandle, m_Source);
cameraData.renderer.ConfigureCameraTarget(m_CameraTargetHandle, m_CameraTargetHandle);
}
}
}
private static void ExecutePass(ref RenderingData renderingData, Material blitMaterial, RTHandle cameraTarget, RTHandle source)
{
var cameraData = renderingData.cameraData;
var cmd = renderingData.commandBuffer;
// TODO: Final blit pass should always blit to backbuffer. The first time we do we don't need to Load contents to tile.
// We need to keep in the pipeline of first render pass to each render target to properly set load/store actions.
// meanwhile we set to load so split screen case works.
var loadAction = RenderBufferLoadAction.DontCare;
if (!cameraData.isSceneViewCamera && !cameraData.isDefaultViewport)
loadAction = RenderBufferLoadAction.Load;
#if ENABLE_VR && ENABLE_XR_MODULE
if (cameraData.xr.enabled)
loadAction = RenderBufferLoadAction.Load;
#endif
RenderingUtils.FinalBlit(cmd, ref cameraData, source, cameraTarget, loadAction, RenderBufferStoreAction.Store, blitMaterial, source.rt?.filterMode == FilterMode.Bilinear ? 1 : 0);
}
private class PassData
{
internal Material blitMaterial;
internal TextureHandle source;
internal TextureHandle destination;
internal int sourceID;
internal Vector4 hdrOutputLuminanceParams;
internal RenderingData renderingData;
}
internal void Render(RenderGraph renderGraph, ref RenderingData renderingData, TextureHandle src, TextureHandle dest, TextureHandle overlayUITexture)
{
using (var builder = renderGraph.AddRenderPass("Final Blit", out var passData, base.profilingSampler))
{
bool outputsToHDR = renderingData.cameraData.isHDROutputActive;
passData.blitMaterial = outputsToHDR ? m_BlitHDRMaterial : m_BlitMaterial;
passData.source = src;
passData.destination = dest;
passData.renderingData = renderingData;
passData.sourceID = ShaderPropertyId.sourceTex;
builder.UseColorBuffer(passData.destination, 0);
builder.ReadTexture(passData.source);
if (outputsToHDR && overlayUITexture.IsValid())
{
VolumeStack stack = VolumeManager.instance.stack;
Tonemapping tonemapping = stack.GetComponent();
UniversalRenderPipeline.GetHDROutputLuminanceParameters(tonemapping, out passData.hdrOutputLuminanceParams);
builder.ReadTexture(overlayUITexture);
}
else
{
passData.hdrOutputLuminanceParams = new Vector4(-1.0f, -1.0f, -1.0f, -1.0f);
}
CoreUtils.SetKeyword(renderingData.commandBuffer, ShaderKeywordStrings.LinearToSRGBConversion,
renderingData.cameraData.requireSrgbConversion);
builder.SetRenderFunc((PassData data, RenderGraphContext context) =>
{
data.blitMaterial.SetTexture(data.sourceID, data.source);
// TODO RENDERGRAPH: this should ideally be shared in ExecutePass to avoid code duplication
if (data.hdrOutputLuminanceParams.w >= 0)
{
// Color conversion may have happened in the Uber post process through color grading, so we don't want to reapply it
HDROutputUtils.Operation hdrOperation = HDROutputUtils.Operation.ColorEncoding;
if (!data.renderingData.cameraData.postProcessEnabled)
hdrOperation |= HDROutputUtils.Operation.ColorConversion;
SetupHDROutput(data.blitMaterial, hdrOperation, data.hdrOutputLuminanceParams);
}
ExecutePass(ref data.renderingData, data.blitMaterial, data.destination, data.source);
});
}
}
}
}