Geen omschrijving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UniversalCameraHistory.cs 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using Unity.Mathematics;
  3. namespace UnityEngine.Rendering.Universal
  4. {
  5. // NOTE: This might become SRPCameraHistory for unified history access in the future.
  6. /// <summary>
  7. /// URP camera history texture manager.
  8. /// </summary>
  9. public class UniversalCameraHistory : ICameraHistoryReadAccess, ICameraHistoryWriteAccess, IPerFrameHistoryAccessTracker, IDisposable
  10. {
  11. /// <summary>
  12. /// Number of frames to consider history valid.
  13. /// </summary>
  14. const int k_ValidVersionCount = 2; // current frame + previous frame
  15. private static uint s_TypeCount = 0;
  16. private static class TypeId<T>
  17. {
  18. public static uint value = s_TypeCount++;
  19. }
  20. private struct Item
  21. {
  22. public ContextItem storage;
  23. // The last tick the type was requested.
  24. public int requestVersion;
  25. // The last tick the type was written to.
  26. public int writeVersion;
  27. public void Reset()
  28. {
  29. storage?.Reset();
  30. requestVersion = -k_ValidVersionCount; // NOTE: must be invalid on frame 0
  31. writeVersion = -k_ValidVersionCount;
  32. }
  33. }
  34. private Item[] m_Items = new Item[32];
  35. private int m_Version = 0;
  36. // A central storage for camera history textures.
  37. private BufferedRTHandleSystem m_HistoryTextures = new BufferedRTHandleSystem();
  38. #region SrpApi
  39. /// <summary>
  40. /// Request access to a history item.
  41. /// </summary>
  42. /// <typeparam name="Type">Type of the history item.</typeparam>
  43. public void RequestAccess<Type>() where Type : ContextItem
  44. {
  45. uint index = TypeId<Type>.value;
  46. // Resize
  47. if(index >= m_Items.Length)
  48. {
  49. var items = new Item[math.max(math.ceilpow2(s_TypeCount), m_Items.Length * 2)];
  50. for (var i = 0; i < m_Items.Length; i++)
  51. {
  52. items[i] = m_Items[i];
  53. }
  54. m_Items = items;
  55. }
  56. m_Items[index].requestVersion = m_Version;
  57. }
  58. /// <summary>
  59. /// Obtain read access to a history item.
  60. /// Valid only if the item was requested and written this or the previous frame.
  61. /// </summary>
  62. /// <typeparam name="Type">Type of the history item.</typeparam>
  63. /// <returns>Instance of the history item if valid. Null otherwise.</returns>
  64. public Type GetHistoryForRead<Type>() where Type : ContextItem
  65. {
  66. uint index = TypeId<Type>.value;
  67. if (index >= m_Items.Length)
  68. return null;
  69. // If the Type wasn't written in previous or this frame, return null.
  70. // The Type design is expected to handle, current/previous/Nth frame history access via BufferedRTHandleSystem.
  71. if (!IsValid((int)index))
  72. return null;
  73. return (Type)m_Items[index].storage;
  74. }
  75. /// <summary>
  76. /// Check if a type was requested this frame.
  77. /// </summary>
  78. /// <typeparam name="Type">Type of the history item.</typeparam>
  79. /// <returns>True if an active request exists. False otherwise.</returns>
  80. public bool IsAccessRequested<Type>() where Type : ContextItem
  81. {
  82. uint index = TypeId<Type>.value;
  83. if (index >= m_Items.Length)
  84. return false;
  85. return IsValidRequest((int)index);
  86. }
  87. /// <summary>
  88. /// Obtain write access to a history item.
  89. /// Valid only if the item was requested this or the previous frame.
  90. /// Write access implies that the contents of the history item must be written.
  91. /// </summary>
  92. /// <typeparam name="Type">Type of the history item.</typeparam>
  93. /// <returns>Instance of the history item if valid. Null otherwise.</returns>
  94. public Type GetHistoryForWrite<Type>() where Type : ContextItem, new()
  95. {
  96. uint index = TypeId<Type>.value;
  97. if (index >= m_Items.Length)
  98. return null;
  99. if (!IsValidRequest((int)index)) // If the request is too old, return null.
  100. return null;
  101. // Create Type instance on the first use
  102. if (m_Items[index].storage == null)
  103. {
  104. ref var i = ref m_Items[index];
  105. i.storage = new Type();
  106. // If the convenience base class for BufferedRTHandleSystem is used, set the owner.
  107. if (i.storage is CameraHistoryItem hi)
  108. hi.OnCreate(m_HistoryTextures, index);
  109. }
  110. // Assume the write for GetForWrite is done correctly by the caller.
  111. m_Items[index].writeVersion = m_Version;
  112. ContextItem item = m_Items[index].storage;
  113. return (Type)item;
  114. }
  115. /// <summary>
  116. /// Check if a type was written this frame.
  117. /// </summary>
  118. /// <typeparam name="Type">Type of the history item.</typeparam>
  119. /// <returns>True if write access was obtained this frame. False otherwise.</returns>
  120. public bool IsWritten<Type>() where Type : ContextItem
  121. {
  122. uint index = TypeId<Type>.value;
  123. if (index >= m_Items.Length)
  124. return false;
  125. return m_Items[index].writeVersion == m_Version;
  126. }
  127. /// <summary>
  128. /// Register external type request callbacks to this event.
  129. /// </summary>
  130. public event ICameraHistoryReadAccess.HistoryRequestDelegate OnGatherHistoryRequests;
  131. #endregion
  132. #region UrpApi
  133. internal UniversalCameraHistory()
  134. {
  135. // Init items with invalid versions.
  136. for(int i = 0; i < m_Items.Length; i++)
  137. m_Items[i].Reset();
  138. }
  139. /// <summary>
  140. /// Release all camera history textures on the GPU.
  141. /// </summary>
  142. public void Dispose()
  143. {
  144. for (int i = 0; i < m_Items.Length; i++)
  145. m_Items[i].Reset();
  146. m_HistoryTextures.ReleaseAll();
  147. }
  148. // Query which types are needed for the registered system.
  149. internal void GatherHistoryRequests()
  150. {
  151. OnGatherHistoryRequests?.Invoke(this);
  152. }
  153. // A type is valid if it was requested this or the last frame.
  154. // Requesting access in the leaf classes, means we might be 1 frame late.
  155. private bool IsValidRequest(int i)
  156. {
  157. return ((m_Version - m_Items[i].requestVersion) < k_ValidVersionCount);
  158. }
  159. // A type is valid if it was requested and written to this or the last frame.
  160. // Requesting access in the leaf classes, means we might be 1 frame late.
  161. // NOTE: BufferedRTHandleSystem technically supports history of N length.
  162. // We might need to keep the history for N frames.
  163. // For now we expect that active history has the previous frame written.
  164. private bool IsValid(int i)
  165. {
  166. return ((m_Version - m_Items[i].writeVersion) < k_ValidVersionCount);
  167. }
  168. // Garbage collect old unused type instances and Reset them. The user is expected to free any GPU resources.
  169. internal void ReleaseUnusedHistory()
  170. {
  171. for (int i = 0; i < m_Items.Length; i++)
  172. {
  173. if (!IsValidRequest(i) && !IsValid(i))
  174. m_Items[i].Reset();
  175. }
  176. // After collecting stale Types, start a new generation.
  177. m_Version++;
  178. }
  179. // Set the camera reference size for all history textures.
  180. internal void SwapAndSetReferenceSize(int cameraWidth, int cameraHeight)
  181. {
  182. m_HistoryTextures.SwapAndSetReferenceSize(cameraWidth, cameraHeight);
  183. }
  184. #endregion
  185. }
  186. }