// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#if GT_USE_URP
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace Microsoft.MixedReality.GraphicsTools
{
///
/// Draws full screen mesh using given material and pass and reading from source target.
/// Forked from: https://github.com/Unity-Technologies/UniversalRenderingExamples/tree/master/Assets/Scripts/Runtime/RenderPasses
///
class DrawFullscreenPass : ScriptableRenderPass
{
///
/// Pass configuration settings.
///
public DrawFullscreenFeature.Settings Settings;
#if UNITY_2022_1_OR_NEWER
private RTHandle source;
private RTHandle destination;
private bool isSourceAndDestinationSameTarget;
private string profilerTag;
///
/// Constructor.
///
public DrawFullscreenPass(string tag)
{
profilerTag = tag;
}
///
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
RenderTextureDescriptor blitTargetDescriptor = renderingData.cameraData.cameraTargetDescriptor;
blitTargetDescriptor.depthBufferBits = 0;
isSourceAndDestinationSameTarget = Settings.SourceType == Settings.DestinationType &&
(Settings.SourceType == BufferType.CameraColor || Settings.SourceTextureId == Settings.DestinationTextureId);
if (Settings.SourceType == BufferType.CameraColor)
{
source = renderingData.cameraData.renderer.cameraColorTargetHandle;
}
else
{
RenderingUtils.ReAllocateIfNeeded(ref source, blitTargetDescriptor, Settings.FilterMode,
TextureWrapMode.Clamp, name: Settings.SourceTextureId);
}
if (isSourceAndDestinationSameTarget)
{
RenderingUtils.ReAllocateIfNeeded(ref destination, blitTargetDescriptor, Settings.FilterMode,
TextureWrapMode.Clamp, name: "_TempRT");
}
else if (Settings.DestinationType == BufferType.CameraColor)
{
destination = renderingData.cameraData.renderer.cameraColorTargetHandle;
}
else
{
RenderingUtils.ReAllocateIfNeeded(ref destination, blitTargetDescriptor, Settings.FilterMode,
TextureWrapMode.Clamp, name: Settings.DestinationTextureId);
}
}
///
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(profilerTag);
// Can't read and write to same color target, create a temp render target to blit.
if (isSourceAndDestinationSameTarget)
{
Blitter.BlitCameraTexture(cmd, source, destination, Settings.BlitMaterial, Settings.BlitMaterialPassIndex);
Blitter.BlitCameraTexture(cmd, destination, source, Settings.BlitMaterial, 0);
}
else
{
Blitter.BlitCameraTexture(cmd, source, destination, Settings.BlitMaterial, Settings.BlitMaterialPassIndex);
}
cmd.SetGlobalTexture(Settings.DestinationTextureId, destination);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
///
/// Unsure when this is called? This is the only resource I could find to dispose of RTHandles.
/// https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/upgrade-guide-2022-1.html
///
private void Dispose()
{
source?.Release();
destination?.Release();
}
#else
private RenderTargetIdentifier source;
private RenderTargetIdentifier destination;
private RenderTargetIdentifier cameraColorTarget;
private int temporaryRTId = Shader.PropertyToID("_TempRT");
private int sourceId;
private int destinationId;
private bool isSourceAndDestinationSameTarget;
private string profilerTag;
///
/// Constructor.
///
public DrawFullscreenPass(string tag)
{
profilerTag = tag;
}
///
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
RenderTextureDescriptor blitTargetDescriptor = renderingData.cameraData.cameraTargetDescriptor;
blitTargetDescriptor.depthBufferBits = 0;
isSourceAndDestinationSameTarget = Settings.SourceType == Settings.DestinationType &&
(Settings.SourceType == BufferType.CameraColor || Settings.SourceTextureId == Settings.DestinationTextureId);
var renderer = renderingData.cameraData.renderer;
if (Settings.SourceType == BufferType.CameraColor)
{
sourceId = -1;
source = renderer.cameraColorTarget;
}
else
{
sourceId = Shader.PropertyToID(Settings.SourceTextureId);
cmd.GetTemporaryRT(sourceId, blitTargetDescriptor, Settings.FilterMode);
source = new RenderTargetIdentifier(sourceId);
}
if (isSourceAndDestinationSameTarget)
{
destinationId = temporaryRTId;
cmd.GetTemporaryRT(destinationId, blitTargetDescriptor, Settings.FilterMode);
destination = new RenderTargetIdentifier(destinationId);
}
else if (Settings.DestinationType == BufferType.CameraColor)
{
destinationId = -1;
destination = renderer.cameraColorTarget;
}
else
{
destinationId = Shader.PropertyToID(Settings.DestinationTextureId);
cmd.GetTemporaryRT(destinationId, blitTargetDescriptor, Settings.FilterMode);
destination = new RenderTargetIdentifier(destinationId);
}
cameraColorTarget = renderer.cameraColorTarget;
}
///
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(profilerTag);
bool useDrawProceduleBlit = renderingData.cameraData.xrRendering;
// Can't read and write to same color target, create a temp render target to blit.
if (isSourceAndDestinationSameTarget)
{
Blit(cmd, source, destination, Settings.BlitMaterial, Settings.BlitMaterialPassIndex, useDrawProceduleBlit);
Blit(cmd, destination, source, Settings.BlitMaterial, 0, useDrawProceduleBlit);
}
else
{
Blit(cmd, source, destination, Settings.BlitMaterial, Settings.BlitMaterialPassIndex, useDrawProceduleBlit);
}
if (Settings.RestoreCameraColorTarget)
{
cmd.SetRenderTarget(cameraColorTarget);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
///
public override void FrameCleanup(CommandBuffer cmd)
{
if (destinationId != -1)
cmd.ReleaseTemporaryRT(destinationId);
if (source == destination && sourceId != -1)
cmd.ReleaseTemporaryRT(sourceId);
}
private struct ShaderPropertyId
{
public static readonly int sourceTex = Shader.PropertyToID("_SourceTex");
public static readonly int scaleBias = Shader.PropertyToID("_ScaleBias");
public static readonly int scaleBiasRt = Shader.PropertyToID("_ScaleBiasRt");
}
///
/// Fork of the internal UnityEngine.Rendering.Universal.RenderingUtils.Blit method.
///
private static void Blit(CommandBuffer cmd,
RenderTargetIdentifier source,
RenderTargetIdentifier destination,
Material material,
int passIndex = 0,
bool useDrawProcedural = false,
RenderBufferLoadAction colorLoadAction = RenderBufferLoadAction.Load,
RenderBufferStoreAction colorStoreAction = RenderBufferStoreAction.Store,
RenderBufferLoadAction depthLoadAction = RenderBufferLoadAction.Load,
RenderBufferStoreAction depthStoreAction = RenderBufferStoreAction.Store)
{
cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, source);
if (useDrawProcedural)
{
Vector4 scaleBias = new Vector4(1, 1, 0, 0);
Vector4 scaleBiasRt = new Vector4(1, 1, 0, 0);
cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
cmd.SetGlobalVector(ShaderPropertyId.scaleBiasRt, scaleBiasRt);
cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
colorLoadAction, colorStoreAction, depthLoadAction, depthStoreAction);
cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Quads, 4, 1, null);
}
else
{
cmd.SetRenderTarget(destination, colorLoadAction, colorStoreAction, depthLoadAction, depthStoreAction);
cmd.Blit(source, BuiltinRenderTextureType.CurrentActive, material, passIndex);
}
}
#endif // UNITY_2022_1_OR_NEWER
}
}
#endif // GT_USE_URP