123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- using System;
- using Unity.Mathematics;
-
- namespace UnityEngine.Rendering.Universal
- {
- // NOTE: This might become SRPCameraHistory for unified history access in the future.
-
- /// <summary>
- /// URP camera history texture manager.
- /// </summary>
- public class UniversalCameraHistory : ICameraHistoryReadAccess, ICameraHistoryWriteAccess, IPerFrameHistoryAccessTracker, IDisposable
- {
- /// <summary>
- /// Number of frames to consider history valid.
- /// </summary>
- const int k_ValidVersionCount = 2; // current frame + previous frame
-
- private static uint s_TypeCount = 0;
- private static class TypeId<T>
- {
- public static uint value = s_TypeCount++;
- }
-
- private struct Item
- {
- public ContextItem storage;
-
- // The last tick the type was requested.
- public int requestVersion;
-
- // The last tick the type was written to.
- public int writeVersion;
-
- public void Reset()
- {
- storage?.Reset();
- requestVersion = -k_ValidVersionCount; // NOTE: must be invalid on frame 0
- writeVersion = -k_ValidVersionCount;
- }
- }
- private Item[] m_Items = new Item[32];
- private int m_Version = 0;
-
- // A central storage for camera history textures.
- private BufferedRTHandleSystem m_HistoryTextures = new BufferedRTHandleSystem();
-
- #region SrpApi
-
- /// <summary>
- /// Request access to a history item.
- /// </summary>
- /// <typeparam name="Type">Type of the history item.</typeparam>
- public void RequestAccess<Type>() where Type : ContextItem
- {
- uint index = TypeId<Type>.value;
-
- // Resize
- if(index >= m_Items.Length)
- {
- var items = new Item[math.max(math.ceilpow2(s_TypeCount), m_Items.Length * 2)];
- for (var i = 0; i < m_Items.Length; i++)
- {
- items[i] = m_Items[i];
- }
- m_Items = items;
- }
-
- m_Items[index].requestVersion = m_Version;
- }
-
- /// <summary>
- /// Obtain read access to a history item.
- /// Valid only if the item was requested and written this or the previous frame.
- /// </summary>
- /// <typeparam name="Type">Type of the history item.</typeparam>
- /// <returns>Instance of the history item if valid. Null otherwise.</returns>
- public Type GetHistoryForRead<Type>() where Type : ContextItem
- {
- uint index = TypeId<Type>.value;
-
- if (index >= m_Items.Length)
- return null;
-
- // If the Type wasn't written in previous or this frame, return null.
- // The Type design is expected to handle, current/previous/Nth frame history access via BufferedRTHandleSystem.
- if (!IsValid((int)index))
- return null;
-
- return (Type)m_Items[index].storage;
- }
-
- /// <summary>
- /// Check if a type was requested this frame.
- /// </summary>
- /// <typeparam name="Type">Type of the history item.</typeparam>
- /// <returns>True if an active request exists. False otherwise.</returns>
- public bool IsAccessRequested<Type>() where Type : ContextItem
- {
- uint index = TypeId<Type>.value;
-
- if (index >= m_Items.Length)
- return false;
-
- return IsValidRequest((int)index);
- }
-
- /// <summary>
- /// Obtain write access to a history item.
- /// Valid only if the item was requested this or the previous frame.
- /// Write access implies that the contents of the history item must be written.
- /// </summary>
- /// <typeparam name="Type">Type of the history item.</typeparam>
- /// <returns>Instance of the history item if valid. Null otherwise.</returns>
- public Type GetHistoryForWrite<Type>() where Type : ContextItem, new()
- {
- uint index = TypeId<Type>.value;
-
- if (index >= m_Items.Length)
- return null;
-
- if (!IsValidRequest((int)index)) // If the request is too old, return null.
- return null;
-
- // Create Type instance on the first use
- if (m_Items[index].storage == null)
- {
- ref var i = ref m_Items[index];
- i.storage = new Type();
-
- // If the convenience base class for BufferedRTHandleSystem is used, set the owner.
- if (i.storage is CameraHistoryItem hi)
- hi.OnCreate(m_HistoryTextures, index);
- }
-
- // Assume the write for GetForWrite is done correctly by the caller.
- m_Items[index].writeVersion = m_Version;
-
- ContextItem item = m_Items[index].storage;
- return (Type)item;
- }
-
- /// <summary>
- /// Check if a type was written this frame.
- /// </summary>
- /// <typeparam name="Type">Type of the history item.</typeparam>
- /// <returns>True if write access was obtained this frame. False otherwise.</returns>
- public bool IsWritten<Type>() where Type : ContextItem
- {
- uint index = TypeId<Type>.value;
-
- if (index >= m_Items.Length)
- return false;
-
- return m_Items[index].writeVersion == m_Version;
- }
-
- /// <summary>
- /// Register external type request callbacks to this event.
- /// </summary>
- public event ICameraHistoryReadAccess.HistoryRequestDelegate OnGatherHistoryRequests;
-
- #endregion
- #region UrpApi
-
- internal UniversalCameraHistory()
- {
- // Init items with invalid versions.
- for(int i = 0; i < m_Items.Length; i++)
- m_Items[i].Reset();
- }
-
- /// <summary>
- /// Release all camera history textures on the GPU.
- /// </summary>
- public void Dispose()
- {
- for (int i = 0; i < m_Items.Length; i++)
- m_Items[i].Reset();
-
- m_HistoryTextures.ReleaseAll();
- }
-
- // Query which types are needed for the registered system.
- internal void GatherHistoryRequests()
- {
- OnGatherHistoryRequests?.Invoke(this);
- }
-
- // A type is valid if it was requested this or the last frame.
- // Requesting access in the leaf classes, means we might be 1 frame late.
- private bool IsValidRequest(int i)
- {
- return ((m_Version - m_Items[i].requestVersion) < k_ValidVersionCount);
- }
-
- // A type is valid if it was requested and written to this or the last frame.
- // Requesting access in the leaf classes, means we might be 1 frame late.
- // NOTE: BufferedRTHandleSystem technically supports history of N length.
- // We might need to keep the history for N frames.
- // For now we expect that active history has the previous frame written.
- private bool IsValid(int i)
- {
- return ((m_Version - m_Items[i].writeVersion) < k_ValidVersionCount);
- }
-
- // Garbage collect old unused type instances and Reset them. The user is expected to free any GPU resources.
- internal void ReleaseUnusedHistory()
- {
- for (int i = 0; i < m_Items.Length; i++)
- {
- if (!IsValidRequest(i) && !IsValid(i))
- m_Items[i].Reset();
- }
-
- // After collecting stale Types, start a new generation.
- m_Version++;
- }
-
- // Set the camera reference size for all history textures.
- internal void SwapAndSetReferenceSize(int cameraWidth, int cameraHeight)
- {
- m_HistoryTextures.SwapAndSetReferenceSize(cameraWidth, cameraHeight);
- }
-
- #endregion
- }
- }
|