using System;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.Universal
{
///
/// Base class for depth history.
/// Format is the camera depth format or R32Float on platforms with limitations.
/// If TemporalAA is enabled the depth is jittered.
/// No mips. No depth pyramid.
/// MSAA is not supported and is resolved for the history.
/// XR is supported.
///
public abstract class DepthHistory : CameraHistoryItem
{
// Currently we are storing up to 2, one for each eye in the case of XR stereo rendering
private int[] m_Ids = new int[2];
///
/// The names to use for history items.
///
protected readonly string[] m_Names = new[]
{
"DepthHistory0",
"DepthHistory1"
};
private RenderTextureDescriptor m_Descriptor;
private Hash128 m_DescKey;
// Store one jitter offset per eye per history RT. Currently the jitter offset
// is the same for both eyes, but first of all this could change, but mostly
// it's because eye jitters could be updated at different times.
private Vector2[] m_JitterOffsets = new Vector2[2*2];
///
public override void OnCreate(BufferedRTHandleSystem owner, uint typeId)
{
base.OnCreate(owner, typeId);
m_Ids[0] = MakeId(0);
m_Ids[1] = MakeId(1);
Array.Fill(m_JitterOffsets, Vector2.zero);
}
///
/// Get the current history texture.
/// Current history might not be valid yet. It is valid only after executing the producing render pass.
///
/// Eye index, typically XRPass.multipassId.
/// The texture.
public RTHandle GetCurrentTexture(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_Ids.Length)
return null;
return GetCurrentFrameRT(m_Ids[eyeIndex]);
}
///
/// Get the previous history texture.
///
/// Eye index, typically XRPass.multipassId.
/// The texture.
public RTHandle GetPreviousTexture(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_Ids.Length)
return null;
return GetPreviousFrameRT(m_Ids[eyeIndex]);
}
///
/// Get the current history jitter value.
/// Current history might not be valid yet. It is valid only after executing the producing render pass.
///
/// Eye index, typically XRPass.multipassId.
/// The jitter value in NDC space [-1,1].
public Vector2 GetCurrentJitter(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_Ids.Length)
return Vector2.zero;
int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]);
if (stableIndex < 0)
return Vector2.zero;
return m_JitterOffsets[stableIndex + 2 * eyeIndex];
}
///
/// Get the previous history jitter value.
///
/// Eye index, typically XRPass.multipassId.
/// The jitter value in NDC space [-1,1].
public Vector2 GetPreviousJitter(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_Ids.Length)
return Vector2.zero;
int stableIndex = GetPreviousFrameRTStableIndex(m_Ids[eyeIndex]);
if (stableIndex < 0)
return Vector2.zero;
return m_JitterOffsets[stableIndex + 2 * eyeIndex];
}
private bool IsAllocated()
{
return GetCurrentTexture() != null;
}
// True if the desc changed, graphicsFormat etc.
private bool IsDirty(ref RenderTextureDescriptor desc)
{
return m_DescKey != Hash128.Compute(ref desc);
}
private void Alloc(ref RenderTextureDescriptor desc, bool xrMultipassEnabled)
{
// Generic type, we need double buffering.
AllocHistoryFrameRT(m_Ids[0], 2, ref desc, m_Names[0]);
if(xrMultipassEnabled)
AllocHistoryFrameRT(m_Ids[1], 2, ref desc, m_Names[1]);
m_Descriptor = desc;
m_DescKey = Hash128.Compute(ref desc);
}
///
/// Release the history texture(s).
///
public override void Reset()
{
for(int i = 0; i < m_Ids.Length; i++)
ReleaseHistoryFrameRT(m_Ids[i]);
}
internal RenderTextureDescriptor GetHistoryDescriptor(ref RenderTextureDescriptor cameraDesc)
{
var depthDesc = cameraDesc;
depthDesc.mipCount = 0;
depthDesc.msaaSamples = 1; // History copy should not have MSAA.
return depthDesc;
}
// Return true if the RTHandles were reallocated.
internal bool Update(UniversalCameraData cameraData, bool xrMultipassEnabled, in RenderTextureDescriptor? cameraDescOverride = null)
{
#if ENABLE_VR && ENABLE_XR_MODULE
int eyeIndex = (cameraData.xr.enabled && !cameraData.xr.singlePassEnabled) ? cameraData.xr.multipassId : 0;
#else
const int eyeIndex = 0;
#endif
Debug.Assert(eyeIndex < m_JitterOffsets.Length);
int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]);
if (stableIndex >= 0)
{
// Update the current jitter value for the current eye. Note that we could handle the case where
// this is the first time or if we reallocate the buffers except there's no clear definition of
// what we should use for a sensible previous jitter value in that case. So might just leave it as is.
m_JitterOffsets[stableIndex + 2 * eyeIndex] = cameraData.jitter;
}
RenderTextureDescriptor cameraDesc;
if (cameraDescOverride.HasValue)
{
cameraDesc = cameraDescOverride.Value;
}
else
{
cameraDesc = cameraData.cameraTargetDescriptor;
// On GLES we don't support sampling the MSAA targets, so if auto depth resolve is not available, the only thing that works is rendering to a color target.
// This has been the behavior from at least 6.0. However, it results in the format mostly being color on the different graphics APIs, even when
// it could be a depth format if MSAA sampling for depth is allowed.
if (RenderingUtils.MultisampleDepthResolveSupported())
{
cameraDesc.graphicsFormat = GraphicsFormat.None;
}
else
{
cameraDesc.graphicsFormat = GraphicsFormat.R32_SFloat;
cameraDesc.depthStencilFormat = GraphicsFormat.None;
}
}
if (cameraDesc.width > 0 && cameraDesc.height > 0 && (cameraDesc.depthStencilFormat != GraphicsFormat.None || cameraDesc.graphicsFormat != GraphicsFormat.None) )
{
var historyDesc = GetHistoryDescriptor(ref cameraDesc);
if (IsDirty(ref historyDesc))
Reset();
if (!IsAllocated())
{
Alloc(ref historyDesc, xrMultipassEnabled);
return true;
}
}
return false;
}
}
}