RTHandleSystem.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Assertions;
  4. using UnityEngine.Experimental.Rendering;
  5. namespace UnityEngine.Rendering
  6. {
  7. /// <summary>
  8. /// Scaled function used to compute the size of a RTHandle for the current frame.
  9. /// </summary>
  10. /// <param name="size">Reference size of the RTHandle system for the frame.</param>
  11. /// <returns>The size of the RTHandled computed from the reference size.</returns>
  12. public delegate Vector2Int ScaleFunc(Vector2Int size);
  13. /// <summary>
  14. /// List of properties of the RTHandle System for the current frame.
  15. /// </summary>
  16. public struct RTHandleProperties
  17. {
  18. /// <summary>
  19. /// Size set as reference at the previous frame
  20. /// </summary>
  21. public Vector2Int previousViewportSize;
  22. /// <summary>
  23. /// Size of the render targets at the previous frame
  24. /// </summary>
  25. public Vector2Int previousRenderTargetSize;
  26. /// <summary>
  27. /// Size set as reference at the current frame
  28. /// </summary>
  29. public Vector2Int currentViewportSize;
  30. /// <summary>
  31. /// Size of the render targets at the current frame
  32. /// </summary>
  33. public Vector2Int currentRenderTargetSize;
  34. /// <summary>
  35. /// Scale factor from RTHandleSystem max size to requested reference size (referenceSize/maxSize)
  36. /// (x,y) current frame (z,w) last frame (this is only used for buffered RTHandle Systems)
  37. /// </summary>
  38. public Vector4 rtHandleScale;
  39. }
  40. /// <summary>
  41. /// System managing a set of RTHandle textures
  42. /// </summary>
  43. public partial class RTHandleSystem : IDisposable
  44. {
  45. internal enum ResizeMode
  46. {
  47. Auto,
  48. OnDemand
  49. }
  50. // Parameters for auto-scaled Render Textures
  51. bool m_HardwareDynamicResRequested = false;
  52. bool m_ScaledRTSupportsMSAA = false;
  53. MSAASamples m_ScaledRTCurrentMSAASamples = MSAASamples.None;
  54. HashSet<RTHandle> m_AutoSizedRTs;
  55. RTHandle[] m_AutoSizedRTsArray; // For fast iteration
  56. HashSet<RTHandle> m_ResizeOnDemandRTs;
  57. RTHandleProperties m_RTHandleProperties;
  58. /// <summary>
  59. /// Current properties of the RTHandle System.
  60. /// </summary>
  61. public RTHandleProperties rtHandleProperties { get { return m_RTHandleProperties; } }
  62. int m_MaxWidths = 0;
  63. int m_MaxHeights = 0;
  64. #if UNITY_EDITOR
  65. // In editor every now and then we must reset the size of the rthandle system if it was set very high and then switched back to a much smaller scale.
  66. int m_FramesSinceLastReset = 0;
  67. #endif
  68. /// <summary>
  69. /// RTHandleSystem constructor.
  70. /// </summary>
  71. public RTHandleSystem()
  72. {
  73. m_AutoSizedRTs = new HashSet<RTHandle>();
  74. m_ResizeOnDemandRTs = new HashSet<RTHandle>();
  75. m_MaxWidths = 1;
  76. m_MaxHeights = 1;
  77. }
  78. /// <summary>
  79. /// Disposable pattern implementation
  80. /// </summary>
  81. public void Dispose()
  82. {
  83. Dispose(true);
  84. }
  85. /// <summary>
  86. /// Initialize the RTHandle system.
  87. /// </summary>
  88. /// <param name="width">Initial reference rendering width.</param>
  89. /// <param name="height">Initial reference rendering height.</param>
  90. /// <param name="scaledRTsupportsMSAA">Set to true if automatically scaled RTHandles should support MSAA</param>
  91. /// <param name="scaledRTMSAASamples">Number of MSAA samples for automatically scaled RTHandles.</param>
  92. public void Initialize(int width, int height, bool scaledRTsupportsMSAA, MSAASamples scaledRTMSAASamples)
  93. {
  94. if (m_AutoSizedRTs.Count != 0)
  95. {
  96. string leakingResources = "Unreleased RTHandles:";
  97. foreach (var rt in m_AutoSizedRTs)
  98. {
  99. leakingResources = string.Format("{0}\n {1}", leakingResources, rt.name);
  100. }
  101. Debug.LogError(string.Format("RTHandle.Initialize should only be called once before allocating any Render Texture. This may be caused by an unreleased RTHandle resource.\n{0}\n", leakingResources));
  102. }
  103. m_MaxWidths = width;
  104. m_MaxHeights = height;
  105. m_ScaledRTSupportsMSAA = scaledRTsupportsMSAA;
  106. m_ScaledRTCurrentMSAASamples = scaledRTMSAASamples;
  107. m_HardwareDynamicResRequested = DynamicResolutionHandler.instance.RequestsHardwareDynamicResolution();
  108. }
  109. /// <summary>
  110. /// Release memory of a RTHandle from the RTHandle System
  111. /// </summary>
  112. /// <param name="rth">RTHandle that should be released.</param>
  113. public void Release(RTHandle rth)
  114. {
  115. if (rth != null)
  116. {
  117. Assert.AreEqual(this, rth.m_Owner);
  118. rth.Release();
  119. }
  120. }
  121. internal void Remove(RTHandle rth)
  122. {
  123. m_AutoSizedRTs.Remove(rth);
  124. }
  125. /// <summary>
  126. /// Reset the reference size of the system and reallocate all textures.
  127. /// </summary>
  128. /// <param name="width">New width.</param>
  129. /// <param name="height">New height.</param>
  130. public void ResetReferenceSize(int width, int height)
  131. {
  132. m_MaxWidths = width;
  133. m_MaxHeights = height;
  134. SetReferenceSize(width, height, m_ScaledRTCurrentMSAASamples, reset: true);
  135. }
  136. /// <summary>
  137. /// Sets the reference rendering size for subsequent rendering for the RTHandle System
  138. /// </summary>
  139. /// <param name="width">Reference rendering width for subsequent rendering.</param>
  140. /// <param name="height">Reference rendering height for subsequent rendering.</param>
  141. /// <param name="msaaSamples">Number of MSAA samples for multisampled textures for subsequent rendering.</param>
  142. public void SetReferenceSize(int width, int height, MSAASamples msaaSamples)
  143. {
  144. SetReferenceSize(width, height, msaaSamples, false);
  145. }
  146. /// <summary>
  147. /// Sets the reference rendering size for subsequent rendering for the RTHandle System
  148. /// </summary>
  149. /// <param name="width">Reference rendering width for subsequent rendering.</param>
  150. /// <param name="height">Reference rendering height for subsequent rendering.</param>
  151. /// <param name="msaaSamples">Number of MSAA samples for multisampled textures for subsequent rendering.</param>
  152. /// <param name="reset">If set to true, the new width and height will override the old values even if they are not bigger.</param>
  153. public void SetReferenceSize(int width, int height, MSAASamples msaaSamples, bool reset)
  154. {
  155. m_RTHandleProperties.previousViewportSize = m_RTHandleProperties.currentViewportSize;
  156. m_RTHandleProperties.previousRenderTargetSize = m_RTHandleProperties.currentRenderTargetSize;
  157. Vector2 lastFrameMaxSize = new Vector2(GetMaxWidth(), GetMaxHeight());
  158. width = Mathf.Max(width, 1);
  159. height = Mathf.Max(height, 1);
  160. #if UNITY_EDITOR
  161. // If the reference size is significantly higher than the current actualWidth/Height and it is larger than 1440p dimensions, we reset the reference size every several frames
  162. // in editor to avoid issues if a large resolution was temporarily set.
  163. const int resetInterval = 100;
  164. if (((m_MaxWidths / (float)width) > 2.0f && m_MaxWidths > 2560) ||
  165. ((m_MaxHeights / (float)height) > 2.0f && m_MaxHeights > 1440))
  166. {
  167. if (m_FramesSinceLastReset > resetInterval)
  168. {
  169. m_FramesSinceLastReset = 0;
  170. ResetReferenceSize(width, height);
  171. }
  172. m_FramesSinceLastReset++;
  173. }
  174. // If some cameras is requesting the same res as the max res, we don't want to reset
  175. if (m_MaxWidths == width && m_MaxHeights == height)
  176. m_FramesSinceLastReset = 0;
  177. #endif
  178. bool sizeChanged = width > GetMaxWidth() || height > GetMaxHeight() || reset;
  179. bool msaaSamplesChanged = (msaaSamples != m_ScaledRTCurrentMSAASamples);
  180. if (sizeChanged || msaaSamplesChanged)
  181. {
  182. Resize(width, height, msaaSamples, sizeChanged, msaaSamplesChanged);
  183. }
  184. m_RTHandleProperties.currentViewportSize = new Vector2Int(width, height);
  185. m_RTHandleProperties.currentRenderTargetSize = new Vector2Int(GetMaxWidth(), GetMaxHeight());
  186. // If the currentViewportSize is 0, it mean we are the first frame of rendering (can happen when doing domain reload for example or for reflection probe)
  187. // in this case the scalePrevious below could be invalided. But some effect rely on having a correct value like TAA with the history buffer for the first frame.
  188. // to work around this, when we detect that size is 0, we setup previous size to current size.
  189. if (m_RTHandleProperties.previousViewportSize.x == 0)
  190. {
  191. m_RTHandleProperties.previousViewportSize = m_RTHandleProperties.currentViewportSize;
  192. m_RTHandleProperties.previousRenderTargetSize = m_RTHandleProperties.currentRenderTargetSize;
  193. lastFrameMaxSize = new Vector2(GetMaxWidth(), GetMaxHeight());
  194. }
  195. if (DynamicResolutionHandler.instance.HardwareDynamicResIsEnabled() && m_HardwareDynamicResRequested)
  196. {
  197. Vector2Int maxSize = new Vector2Int(GetMaxWidth(), GetMaxHeight());
  198. // Making the final scale in 'drs' space, since the final scale must account for rounding pixel values.
  199. var scaledFinalViewport = DynamicResolutionHandler.instance.ApplyScalesOnSize(DynamicResolutionHandler.instance.finalViewport);
  200. var scaledMaxSize = DynamicResolutionHandler.instance.ApplyScalesOnSize(maxSize);
  201. float xScale = (float)scaledFinalViewport.x / (float)scaledMaxSize.x;
  202. float yScale = (float)scaledFinalViewport.y / (float)scaledMaxSize.y;
  203. m_RTHandleProperties.rtHandleScale = new Vector4(xScale, yScale, m_RTHandleProperties.rtHandleScale.x, m_RTHandleProperties.rtHandleScale.y);
  204. }
  205. else
  206. {
  207. Vector2 maxSize = new Vector2(GetMaxWidth(), GetMaxHeight());
  208. Vector2 scaleCurrent = m_RTHandleProperties.currentViewportSize / maxSize;
  209. Vector2 scalePrevious = m_RTHandleProperties.previousViewportSize / lastFrameMaxSize;
  210. m_RTHandleProperties.rtHandleScale = new Vector4(scaleCurrent.x, scaleCurrent.y, scalePrevious.x, scalePrevious.y);
  211. }
  212. }
  213. /// <summary>
  214. /// Enable or disable hardware dynamic resolution for the RTHandle System
  215. /// </summary>
  216. /// <param name="enableHWDynamicRes">State of hardware dynamic resolution.</param>
  217. public void SetHardwareDynamicResolutionState(bool enableHWDynamicRes)
  218. {
  219. if(enableHWDynamicRes != m_HardwareDynamicResRequested)
  220. {
  221. m_HardwareDynamicResRequested = enableHWDynamicRes;
  222. Array.Resize(ref m_AutoSizedRTsArray, m_AutoSizedRTs.Count);
  223. m_AutoSizedRTs.CopyTo(m_AutoSizedRTsArray);
  224. for (int i = 0, c = m_AutoSizedRTsArray.Length; i < c; ++i)
  225. {
  226. var rth = m_AutoSizedRTsArray[i];
  227. // Grab the render texture
  228. var renderTexture = rth.m_RT;
  229. if(renderTexture)
  230. {
  231. // Free the previous version
  232. renderTexture.Release();
  233. renderTexture.useDynamicScale = m_HardwareDynamicResRequested && rth.m_EnableHWDynamicScale;
  234. // Create the render texture
  235. renderTexture.Create();
  236. }
  237. }
  238. }
  239. }
  240. internal void SwitchResizeMode(RTHandle rth, ResizeMode mode)
  241. {
  242. // Don't do anything is scaling isn't enabled on this RT
  243. // TODO: useScaling should probably be moved to ResizeMode.Fixed or something
  244. if (!rth.useScaling)
  245. return;
  246. switch (mode)
  247. {
  248. case ResizeMode.OnDemand:
  249. m_AutoSizedRTs.Remove(rth);
  250. m_ResizeOnDemandRTs.Add(rth);
  251. break;
  252. case ResizeMode.Auto:
  253. // Resize now so it is consistent with other auto resize RTHs
  254. if (m_ResizeOnDemandRTs.Contains(rth))
  255. DemandResize(rth);
  256. m_ResizeOnDemandRTs.Remove(rth);
  257. m_AutoSizedRTs.Add(rth);
  258. break;
  259. }
  260. }
  261. void DemandResize(RTHandle rth)
  262. {
  263. Assert.IsTrue(m_ResizeOnDemandRTs.Contains(rth), "The RTHandle is not an resize on demand handle in this RTHandleSystem. Please call SwitchToResizeOnDemand(rth, true) before resizing on demand.");
  264. // Grab the render texture
  265. var rt = rth.m_RT;
  266. rth.referenceSize = new Vector2Int(m_MaxWidths, m_MaxHeights);
  267. var scaledSize = rth.GetScaledSize(rth.referenceSize);
  268. scaledSize = Vector2Int.Max(Vector2Int.one, scaledSize);
  269. // Did the size change?
  270. var sizeChanged = rt.width != scaledSize.x || rt.height != scaledSize.y;
  271. // If this is an MSAA texture, did the sample count change?
  272. var msaaSampleChanged = rth.m_EnableMSAA && rt.antiAliasing != (int)m_ScaledRTCurrentMSAASamples;
  273. if (sizeChanged || msaaSampleChanged)
  274. {
  275. // Free this render texture
  276. rt.Release();
  277. // Update the antialiasing count
  278. if (rth.m_EnableMSAA)
  279. rt.antiAliasing = (int)m_ScaledRTCurrentMSAASamples;
  280. // Update the size
  281. rt.width = scaledSize.x;
  282. rt.height = scaledSize.y;
  283. // Generate a new name
  284. rt.name = CoreUtils.GetRenderTargetAutoName(
  285. rt.width,
  286. rt.height,
  287. rt.volumeDepth,
  288. rt.graphicsFormat,
  289. rt.dimension,
  290. rth.m_Name,
  291. mips: rt.useMipMap,
  292. enableMSAA: rth.m_EnableMSAA,
  293. msaaSamples: m_ScaledRTCurrentMSAASamples,
  294. dynamicRes: rt.useDynamicScale
  295. );
  296. // Create the new texture
  297. rt.Create();
  298. }
  299. }
  300. /// <summary>
  301. /// Returns the maximum allocated width of the RTHandle System.
  302. /// </summary>
  303. /// <returns>Maximum allocated width of the RTHandle System.</returns>
  304. public int GetMaxWidth() { return m_MaxWidths; }
  305. /// <summary>
  306. /// Returns the maximum allocated height of the RTHandle System.
  307. /// </summary>
  308. /// <returns>Maximum allocated height of the RTHandle System.</returns>
  309. public int GetMaxHeight() { return m_MaxHeights; }
  310. void Dispose(bool disposing)
  311. {
  312. if (disposing)
  313. {
  314. Array.Resize(ref m_AutoSizedRTsArray, m_AutoSizedRTs.Count);
  315. m_AutoSizedRTs.CopyTo(m_AutoSizedRTsArray);
  316. for (int i = 0, c = m_AutoSizedRTsArray.Length; i < c; ++i)
  317. {
  318. var rt = m_AutoSizedRTsArray[i];
  319. Release(rt);
  320. }
  321. m_AutoSizedRTs.Clear();
  322. Array.Resize(ref m_AutoSizedRTsArray, m_ResizeOnDemandRTs.Count);
  323. m_ResizeOnDemandRTs.CopyTo(m_AutoSizedRTsArray);
  324. for (int i = 0, c = m_AutoSizedRTsArray.Length; i < c; ++i)
  325. {
  326. var rt = m_AutoSizedRTsArray[i];
  327. Release(rt);
  328. }
  329. m_ResizeOnDemandRTs.Clear();
  330. m_AutoSizedRTsArray = null;
  331. }
  332. }
  333. void Resize(int width, int height, MSAASamples msaaSamples, bool sizeChanged, bool msaaSampleChanged)
  334. {
  335. m_MaxWidths = Math.Max(width, m_MaxWidths);
  336. m_MaxHeights = Math.Max(height, m_MaxHeights);
  337. m_ScaledRTCurrentMSAASamples = msaaSamples;
  338. var maxSize = new Vector2Int(m_MaxWidths, m_MaxHeights);
  339. Array.Resize(ref m_AutoSizedRTsArray, m_AutoSizedRTs.Count);
  340. m_AutoSizedRTs.CopyTo(m_AutoSizedRTsArray);
  341. for (int i = 0, c = m_AutoSizedRTsArray.Length; i < c; ++i)
  342. {
  343. // Grab the RT Handle
  344. var rth = m_AutoSizedRTsArray[i];
  345. // If we are only processing MSAA sample count change, make sure this RT is an MSAA one
  346. if (!sizeChanged && msaaSampleChanged && !rth.m_EnableMSAA)
  347. {
  348. continue;
  349. }
  350. // Force its new reference size
  351. rth.referenceSize = maxSize;
  352. // Grab the render texture
  353. var renderTexture = rth.m_RT;
  354. // Free the previous version
  355. renderTexture.Release();
  356. // Get the scaled size
  357. var scaledSize = rth.GetScaledSize(maxSize);
  358. renderTexture.width = Mathf.Max(scaledSize.x, 1);
  359. renderTexture.height = Mathf.Max(scaledSize.y, 1);
  360. // If this is a msaa texture, make sure to update its msaa count
  361. if (rth.m_EnableMSAA)
  362. {
  363. renderTexture.antiAliasing = (int)m_ScaledRTCurrentMSAASamples;
  364. }
  365. // Regenerate the name
  366. renderTexture.name = CoreUtils.GetRenderTargetAutoName(renderTexture.width, renderTexture.height, renderTexture.volumeDepth, renderTexture.graphicsFormat, renderTexture.dimension, rth.m_Name, mips: renderTexture.useMipMap, enableMSAA: rth.m_EnableMSAA, msaaSamples: m_ScaledRTCurrentMSAASamples, dynamicRes: renderTexture.useDynamicScale);
  367. // Create the render texture
  368. renderTexture.Create();
  369. }
  370. }
  371. /// <summary>
  372. /// Allocate a new fixed sized RTHandle.
  373. /// </summary>
  374. /// <param name="width">With of the RTHandle.</param>
  375. /// <param name="height">Heigh of the RTHandle.</param>
  376. /// <param name="slices">Number of slices of the RTHandle.</param>
  377. /// <param name="depthBufferBits">Bit depths of a depth buffer.</param>
  378. /// <param name="colorFormat">GraphicsFormat of a color buffer.</param>
  379. /// <param name="filterMode">Filtering mode of the RTHandle.</param>
  380. /// <param name="wrapMode">Addressing mode of the RTHandle.</param>
  381. /// <param name="dimension">Texture dimension of the RTHandle.</param>
  382. /// <param name="enableRandomWrite">Set to true to enable UAV random read writes on the texture.</param>
  383. /// <param name="useMipMap">Set to true if the texture should have mipmaps.</param>
  384. /// <param name="autoGenerateMips">Set to true to automatically generate mipmaps.</param>
  385. /// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
  386. /// <param name="anisoLevel">Anisotropic filtering level.</param>
  387. /// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
  388. /// <param name="msaaSamples">Number of MSAA samples for the RTHandle.</param>
  389. /// <param name="bindTextureMS">Set to true if the texture needs to be bound as a multisampled texture in the shader.</param>
  390. /// <param name="useDynamicScale">Set to true to use hardware dynamic scaling.</param>
  391. /// <param name="memoryless">Use this property to set the render texture memoryless modes.</param>
  392. /// <param name="name">Name of the RTHandle.</param>
  393. /// <returns></returns>
  394. public RTHandle Alloc(
  395. int width,
  396. int height,
  397. int slices = 1,
  398. DepthBits depthBufferBits = DepthBits.None,
  399. GraphicsFormat colorFormat = GraphicsFormat.R8G8B8A8_SRGB,
  400. FilterMode filterMode = FilterMode.Point,
  401. TextureWrapMode wrapMode = TextureWrapMode.Repeat,
  402. TextureDimension dimension = TextureDimension.Tex2D,
  403. bool enableRandomWrite = false,
  404. bool useMipMap = false,
  405. bool autoGenerateMips = true,
  406. bool isShadowMap = false,
  407. int anisoLevel = 1,
  408. float mipMapBias = 0f,
  409. MSAASamples msaaSamples = MSAASamples.None,
  410. bool bindTextureMS = false,
  411. bool useDynamicScale = false,
  412. RenderTextureMemoryless memoryless = RenderTextureMemoryless.None,
  413. string name = ""
  414. )
  415. {
  416. bool enableMSAA = msaaSamples != MSAASamples.None;
  417. if (!enableMSAA && bindTextureMS == true)
  418. {
  419. Debug.LogWarning("RTHandle allocated without MSAA but with bindMS set to true, forcing bindMS to false.");
  420. bindTextureMS = false;
  421. }
  422. // We need to handle this in an explicit way since GraphicsFormat does not expose depth formats. TODO: Get rid of this branch once GraphicsFormat'll expose depth related formats
  423. RenderTexture rt;
  424. if (isShadowMap || depthBufferBits != DepthBits.None)
  425. {
  426. RenderTextureFormat format = isShadowMap ? RenderTextureFormat.Shadowmap : RenderTextureFormat.Depth;
  427. rt = new RenderTexture(width, height, (int)depthBufferBits, format, RenderTextureReadWrite.Linear)
  428. {
  429. hideFlags = HideFlags.HideAndDontSave,
  430. volumeDepth = slices,
  431. filterMode = filterMode,
  432. wrapMode = wrapMode,
  433. dimension = dimension,
  434. enableRandomWrite = enableRandomWrite,
  435. useMipMap = useMipMap,
  436. autoGenerateMips = autoGenerateMips,
  437. anisoLevel = anisoLevel,
  438. mipMapBias = mipMapBias,
  439. antiAliasing = (int)msaaSamples,
  440. bindTextureMS = bindTextureMS,
  441. useDynamicScale = m_HardwareDynamicResRequested && useDynamicScale,
  442. memorylessMode = memoryless,
  443. name = CoreUtils.GetRenderTargetAutoName(width, height, slices, format, name, mips: useMipMap, enableMSAA: enableMSAA, msaaSamples: msaaSamples)
  444. };
  445. }
  446. else
  447. {
  448. rt = new RenderTexture(width, height, (int)depthBufferBits, colorFormat)
  449. {
  450. hideFlags = HideFlags.HideAndDontSave,
  451. volumeDepth = slices,
  452. filterMode = filterMode,
  453. wrapMode = wrapMode,
  454. dimension = dimension,
  455. enableRandomWrite = enableRandomWrite,
  456. useMipMap = useMipMap,
  457. autoGenerateMips = autoGenerateMips,
  458. anisoLevel = anisoLevel,
  459. mipMapBias = mipMapBias,
  460. antiAliasing = (int)msaaSamples,
  461. bindTextureMS = bindTextureMS,
  462. useDynamicScale = m_HardwareDynamicResRequested && useDynamicScale,
  463. memorylessMode = memoryless,
  464. name = CoreUtils.GetRenderTargetAutoName(width, height, slices, colorFormat, dimension, name, mips: useMipMap, enableMSAA: enableMSAA, msaaSamples: msaaSamples, dynamicRes: useDynamicScale)
  465. };
  466. }
  467. rt.Create();
  468. var newRT = new RTHandle(this);
  469. newRT.SetRenderTexture(rt);
  470. newRT.useScaling = false;
  471. newRT.m_EnableRandomWrite = enableRandomWrite;
  472. newRT.m_EnableMSAA = enableMSAA;
  473. newRT.m_EnableHWDynamicScale = useDynamicScale;
  474. newRT.m_Name = name;
  475. newRT.referenceSize = new Vector2Int(width, height);
  476. return newRT;
  477. }
  478. // Next two methods are used to allocate RenderTexture that depend on the frame settings (resolution and msaa for now)
  479. // RenderTextures allocated this way are meant to be defined by a scale of camera resolution (full/half/quarter resolution for example).
  480. // The idea is that internally the system will scale up the size of all render texture so that it amortizes with time and not reallocate when a smaller size is required (which is what happens with TemporaryRTs).
  481. // Since MSAA cannot be changed on the fly for a given RenderTexture, a separate instance will be created if the user requires it. This instance will be the one used after the next call of SetReferenceSize if MSAA is required.
  482. /// <summary>
  483. /// Allocate a new automatically sized RTHandle.
  484. /// </summary>
  485. /// <param name="scaleFactor">Constant scale for the RTHandle size computation.</param>
  486. /// <param name="slices">Number of slices of the RTHandle.</param>
  487. /// <param name="depthBufferBits">Bit depths of a depth buffer.</param>
  488. /// <param name="colorFormat">GraphicsFormat of a color buffer.</param>
  489. /// <param name="filterMode">Filtering mode of the RTHandle.</param>
  490. /// <param name="wrapMode">Addressing mode of the RTHandle.</param>
  491. /// <param name="dimension">Texture dimension of the RTHandle.</param>
  492. /// <param name="enableRandomWrite">Set to true to enable UAV random read writes on the texture.</param>
  493. /// <param name="useMipMap">Set to true if the texture should have mipmaps.</param>
  494. /// <param name="autoGenerateMips">Set to true to automatically generate mipmaps.</param>
  495. /// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
  496. /// <param name="anisoLevel">Anisotropic filtering level.</param>
  497. /// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
  498. /// <param name="enableMSAA">Enable MSAA for this RTHandle.</param>
  499. /// <param name="bindTextureMS">Set to true if the texture needs to be bound as a multisampled texture in the shader.</param>
  500. /// <param name="useDynamicScale">Set to true to use hardware dynamic scaling.</param>
  501. /// <param name="memoryless">Use this property to set the render texture memoryless modes.</param>
  502. /// <param name="name">Name of the RTHandle.</param>
  503. /// <returns></returns>
  504. public RTHandle Alloc(
  505. Vector2 scaleFactor,
  506. int slices = 1,
  507. DepthBits depthBufferBits = DepthBits.None,
  508. GraphicsFormat colorFormat = GraphicsFormat.R8G8B8A8_SRGB,
  509. FilterMode filterMode = FilterMode.Point,
  510. TextureWrapMode wrapMode = TextureWrapMode.Repeat,
  511. TextureDimension dimension = TextureDimension.Tex2D,
  512. bool enableRandomWrite = false,
  513. bool useMipMap = false,
  514. bool autoGenerateMips = true,
  515. bool isShadowMap = false,
  516. int anisoLevel = 1,
  517. float mipMapBias = 0f,
  518. bool enableMSAA = false,
  519. bool bindTextureMS = false,
  520. bool useDynamicScale = false,
  521. RenderTextureMemoryless memoryless = RenderTextureMemoryless.None,
  522. string name = ""
  523. )
  524. {
  525. // If an MSAA target is requested, make sure the support was on
  526. if (enableMSAA)
  527. Debug.Assert(m_ScaledRTSupportsMSAA);
  528. int width = Mathf.Max(Mathf.RoundToInt(scaleFactor.x * GetMaxWidth()), 1);
  529. int height = Mathf.Max(Mathf.RoundToInt(scaleFactor.y * GetMaxHeight()), 1);
  530. var rth = AllocAutoSizedRenderTexture(width,
  531. height,
  532. slices,
  533. depthBufferBits,
  534. colorFormat,
  535. filterMode,
  536. wrapMode,
  537. dimension,
  538. enableRandomWrite,
  539. useMipMap,
  540. autoGenerateMips,
  541. isShadowMap,
  542. anisoLevel,
  543. mipMapBias,
  544. enableMSAA,
  545. bindTextureMS,
  546. useDynamicScale,
  547. memoryless,
  548. name
  549. );
  550. rth.referenceSize = new Vector2Int(width, height);
  551. rth.scaleFactor = scaleFactor;
  552. return rth;
  553. }
  554. //
  555. // You can provide your own scaling function for advanced scaling schemes (e.g. scaling to
  556. // the next POT). The function takes a Vec2 as parameter that holds max width & height
  557. // values for the current manager context and returns a Vec2 of the final size in pixels.
  558. //
  559. // var rth = Alloc(
  560. // size => new Vector2Int(size.x / 2, size.y),
  561. // [...]
  562. // );
  563. //
  564. /// <summary>
  565. /// Allocate a new automatically sized RTHandle.
  566. /// </summary>
  567. /// <param name="scaleFunc">Function used for the RTHandle size computation.</param>
  568. /// <param name="slices">Number of slices of the RTHandle.</param>
  569. /// <param name="depthBufferBits">Bit depths of a depth buffer.</param>
  570. /// <param name="colorFormat">GraphicsFormat of a color buffer.</param>
  571. /// <param name="filterMode">Filtering mode of the RTHandle.</param>
  572. /// <param name="wrapMode">Addressing mode of the RTHandle.</param>
  573. /// <param name="dimension">Texture dimension of the RTHandle.</param>
  574. /// <param name="enableRandomWrite">Set to true to enable UAV random read writes on the texture.</param>
  575. /// <param name="useMipMap">Set to true if the texture should have mipmaps.</param>
  576. /// <param name="autoGenerateMips">Set to true to automatically generate mipmaps.</param>
  577. /// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
  578. /// <param name="anisoLevel">Anisotropic filtering level.</param>
  579. /// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
  580. /// <param name="enableMSAA">Enable MSAA for this RTHandle.</param>
  581. /// <param name="bindTextureMS">Set to true if the texture needs to be bound as a multisampled texture in the shader.</param>
  582. /// <param name="useDynamicScale">Set to true to use hardware dynamic scaling.</param>
  583. /// <param name="memoryless">Use this property to set the render texture memoryless modes.</param>
  584. /// <param name="name">Name of the RTHandle.</param>
  585. /// <returns></returns>
  586. public RTHandle Alloc(
  587. ScaleFunc scaleFunc,
  588. int slices = 1,
  589. DepthBits depthBufferBits = DepthBits.None,
  590. GraphicsFormat colorFormat = GraphicsFormat.R8G8B8A8_SRGB,
  591. FilterMode filterMode = FilterMode.Point,
  592. TextureWrapMode wrapMode = TextureWrapMode.Repeat,
  593. TextureDimension dimension = TextureDimension.Tex2D,
  594. bool enableRandomWrite = false,
  595. bool useMipMap = false,
  596. bool autoGenerateMips = true,
  597. bool isShadowMap = false,
  598. int anisoLevel = 1,
  599. float mipMapBias = 0f,
  600. bool enableMSAA = false,
  601. bool bindTextureMS = false,
  602. bool useDynamicScale = false,
  603. RenderTextureMemoryless memoryless = RenderTextureMemoryless.None,
  604. string name = ""
  605. )
  606. {
  607. var scaleFactor = scaleFunc(new Vector2Int(GetMaxWidth(), GetMaxHeight()));
  608. int width = Mathf.Max(scaleFactor.x, 1);
  609. int height = Mathf.Max(scaleFactor.y, 1);
  610. var rth = AllocAutoSizedRenderTexture(width,
  611. height,
  612. slices,
  613. depthBufferBits,
  614. colorFormat,
  615. filterMode,
  616. wrapMode,
  617. dimension,
  618. enableRandomWrite,
  619. useMipMap,
  620. autoGenerateMips,
  621. isShadowMap,
  622. anisoLevel,
  623. mipMapBias,
  624. enableMSAA,
  625. bindTextureMS,
  626. useDynamicScale,
  627. memoryless,
  628. name
  629. );
  630. rth.referenceSize = new Vector2Int(width, height);
  631. rth.scaleFunc = scaleFunc;
  632. return rth;
  633. }
  634. // Internal function
  635. RTHandle AllocAutoSizedRenderTexture(
  636. int width,
  637. int height,
  638. int slices,
  639. DepthBits depthBufferBits,
  640. GraphicsFormat colorFormat,
  641. FilterMode filterMode,
  642. TextureWrapMode wrapMode,
  643. TextureDimension dimension,
  644. bool enableRandomWrite,
  645. bool useMipMap,
  646. bool autoGenerateMips,
  647. bool isShadowMap,
  648. int anisoLevel,
  649. float mipMapBias,
  650. bool enableMSAA,
  651. bool bindTextureMS,
  652. bool useDynamicScale,
  653. RenderTextureMemoryless memoryless,
  654. string name
  655. )
  656. {
  657. // Here user made a mistake in setting up msaa/bindMS, hence the warning
  658. if (!enableMSAA && bindTextureMS == true)
  659. {
  660. Debug.LogWarning("RTHandle allocated without MSAA but with bindMS set to true, forcing bindMS to false.");
  661. bindTextureMS = false;
  662. }
  663. bool allocForMSAA = m_ScaledRTSupportsMSAA ? enableMSAA : false;
  664. // Here we purposefully disable MSAA so we just force the bindMS param to false.
  665. if (!allocForMSAA)
  666. {
  667. bindTextureMS = false;
  668. }
  669. // MSAA Does not support random read/write.
  670. bool UAV = enableRandomWrite;
  671. if (allocForMSAA && (UAV == true))
  672. {
  673. Debug.LogWarning("RTHandle that is MSAA-enabled cannot allocate MSAA RT with 'enableRandomWrite = true'.");
  674. UAV = false;
  675. }
  676. int msaaSamples = allocForMSAA ? (int)m_ScaledRTCurrentMSAASamples : 1;
  677. // We need to handle this in an explicit way since GraphicsFormat does not expose depth formats. TODO: Get rid of this branch once GraphicsFormat'll expose depth related formats
  678. RenderTexture rt;
  679. if (isShadowMap || depthBufferBits != DepthBits.None)
  680. {
  681. RenderTextureFormat format = isShadowMap ? RenderTextureFormat.Shadowmap : RenderTextureFormat.Depth;
  682. GraphicsFormat stencilFormat = isShadowMap ? GraphicsFormat.None : GraphicsFormat.R8_UInt;
  683. rt = new RenderTexture(width, height, (int)depthBufferBits, format, RenderTextureReadWrite.Linear)
  684. {
  685. hideFlags = HideFlags.HideAndDontSave,
  686. volumeDepth = slices,
  687. filterMode = filterMode,
  688. wrapMode = wrapMode,
  689. dimension = dimension,
  690. enableRandomWrite = UAV,
  691. useMipMap = useMipMap,
  692. autoGenerateMips = autoGenerateMips,
  693. anisoLevel = anisoLevel,
  694. mipMapBias = mipMapBias,
  695. antiAliasing = msaaSamples,
  696. bindTextureMS = bindTextureMS,
  697. useDynamicScale = m_HardwareDynamicResRequested && useDynamicScale,
  698. memorylessMode = memoryless,
  699. stencilFormat = stencilFormat,
  700. name = CoreUtils.GetRenderTargetAutoName(width, height, slices, colorFormat, dimension, name, mips: useMipMap, enableMSAA: allocForMSAA, msaaSamples: m_ScaledRTCurrentMSAASamples, dynamicRes: useDynamicScale)
  701. };
  702. }
  703. else
  704. {
  705. rt = new RenderTexture(width, height, (int)depthBufferBits, colorFormat)
  706. {
  707. hideFlags = HideFlags.HideAndDontSave,
  708. volumeDepth = slices,
  709. filterMode = filterMode,
  710. wrapMode = wrapMode,
  711. dimension = dimension,
  712. enableRandomWrite = UAV,
  713. useMipMap = useMipMap,
  714. autoGenerateMips = autoGenerateMips,
  715. anisoLevel = anisoLevel,
  716. mipMapBias = mipMapBias,
  717. antiAliasing = msaaSamples,
  718. bindTextureMS = bindTextureMS,
  719. useDynamicScale = m_HardwareDynamicResRequested && useDynamicScale,
  720. memorylessMode = memoryless,
  721. name = CoreUtils.GetRenderTargetAutoName(width, height, slices, colorFormat, dimension, name, mips: useMipMap, enableMSAA: allocForMSAA, msaaSamples: m_ScaledRTCurrentMSAASamples, dynamicRes: useDynamicScale)
  722. };
  723. }
  724. rt.Create();
  725. var rth = new RTHandle(this);
  726. rth.SetRenderTexture(rt);
  727. rth.m_EnableMSAA = enableMSAA;
  728. rth.m_EnableRandomWrite = enableRandomWrite;
  729. rth.useScaling = true;
  730. rth.m_EnableHWDynamicScale = useDynamicScale;
  731. rth.m_Name = name;
  732. m_AutoSizedRTs.Add(rth);
  733. return rth;
  734. }
  735. /// <summary>
  736. /// Allocate a RTHandle from a regular RenderTexture.
  737. /// </summary>
  738. /// <param name="texture">Input texture</param>
  739. /// <returns>A new RTHandle referencing the input texture.</returns>
  740. public RTHandle Alloc(RenderTexture texture)
  741. {
  742. var rth = new RTHandle(this);
  743. rth.SetRenderTexture(texture);
  744. rth.m_EnableMSAA = false;
  745. rth.m_EnableRandomWrite = false;
  746. rth.useScaling = false;
  747. rth.m_EnableHWDynamicScale = false;
  748. rth.m_Name = texture.name;
  749. return rth;
  750. }
  751. /// <summary>
  752. /// Allocate a RTHandle from a regular Texture.
  753. /// </summary>
  754. /// <param name="texture">Input texture</param>
  755. /// <returns>A new RTHandle referencing the input texture.</returns>
  756. public RTHandle Alloc(Texture texture)
  757. {
  758. var rth = new RTHandle(this);
  759. rth.SetTexture(texture);
  760. rth.m_EnableMSAA = false;
  761. rth.m_EnableRandomWrite = false;
  762. rth.useScaling = false;
  763. rth.m_EnableHWDynamicScale = false;
  764. rth.m_Name = texture.name;
  765. return rth;
  766. }
  767. /// <summary>
  768. /// Allocate a RTHandle from a regular render target identifier.
  769. /// </summary>
  770. /// <param name="texture">Input render target identifier.</param>
  771. /// <returns>A new RTHandle referencing the input render target identifier.</returns>
  772. public RTHandle Alloc(RenderTargetIdentifier texture)
  773. {
  774. return Alloc(texture, "");
  775. }
  776. /// <summary>
  777. /// Allocate a RTHandle from a regular render target identifier.
  778. /// </summary>
  779. /// <param name="texture">Input render target identifier.</param>
  780. /// <param name="name">Name of the texture.</param>
  781. /// <returns>A new RTHandle referencing the input render target identifier.</returns>
  782. public RTHandle Alloc(RenderTargetIdentifier texture, string name)
  783. {
  784. var rth = new RTHandle(this);
  785. rth.SetTexture(texture);
  786. rth.m_EnableMSAA = false;
  787. rth.m_EnableRandomWrite = false;
  788. rth.useScaling = false;
  789. rth.m_EnableHWDynamicScale = false;
  790. rth.m_Name = name;
  791. return rth;
  792. }
  793. private static RTHandle Alloc(RTHandle tex)
  794. {
  795. Debug.LogError("Allocation a RTHandle from another one is forbidden.");
  796. return null;
  797. }
  798. internal string DumpRTInfo()
  799. {
  800. string result = "";
  801. Array.Resize(ref m_AutoSizedRTsArray, m_AutoSizedRTs.Count);
  802. m_AutoSizedRTs.CopyTo(m_AutoSizedRTsArray);
  803. for (int i = 0, c = m_AutoSizedRTsArray.Length; i < c; ++i)
  804. {
  805. var rt = m_AutoSizedRTsArray[i].rt;
  806. result = string.Format("{0}\nRT ({1})\t Format: {2} W: {3} H {4}\n", result, i, rt.format, rt.width, rt.height);
  807. }
  808. return result;
  809. }
  810. }
  811. }