NativeRenderPass.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Unity.Collections;
  5. using UnityEngine.Experimental.Rendering;
  6. using UnityEngine.Rendering;
  7. namespace UnityEngine.Rendering.Universal
  8. {
  9. public partial class ScriptableRenderer
  10. {
  11. private const int kRenderPassMapSize = 10;
  12. private const int kRenderPassMaxCount = 20;
  13. // used to keep track of the index of the last pass when we called BeginSubpass
  14. private int m_LastBeginSubpassPassIndex = 0;
  15. private Dictionary<Hash128, int[]> m_MergeableRenderPassesMap = new Dictionary<Hash128, int[]>(kRenderPassMapSize);
  16. // static array storing all the mergeableRenderPassesMap arrays. This is used to remove any GC allocs during the frame which would have been introduced by using a dynamic array to store the mergeablePasses per RenderPass
  17. private int[][] m_MergeableRenderPassesMapArrays;
  18. private Hash128[] m_PassIndexToPassHash = new Hash128[kRenderPassMaxCount];
  19. private Dictionary<Hash128, int> m_RenderPassesAttachmentCount = new Dictionary<Hash128, int>(kRenderPassMapSize);
  20. AttachmentDescriptor[] m_ActiveColorAttachmentDescriptors = new AttachmentDescriptor[]
  21. {
  22. RenderingUtils.emptyAttachment, RenderingUtils.emptyAttachment, RenderingUtils.emptyAttachment,
  23. RenderingUtils.emptyAttachment, RenderingUtils.emptyAttachment, RenderingUtils.emptyAttachment,
  24. RenderingUtils.emptyAttachment, RenderingUtils.emptyAttachment
  25. };
  26. AttachmentDescriptor m_ActiveDepthAttachmentDescriptor;
  27. bool[] m_IsActiveColorAttachmentTransient = new bool[]
  28. {
  29. false, false, false, false, false, false, false, false
  30. };
  31. internal RenderBufferStoreAction[] m_FinalColorStoreAction = new RenderBufferStoreAction[]
  32. {
  33. RenderBufferStoreAction.Store, RenderBufferStoreAction.Store, RenderBufferStoreAction.Store, RenderBufferStoreAction.Store,
  34. RenderBufferStoreAction.Store, RenderBufferStoreAction.Store, RenderBufferStoreAction.Store, RenderBufferStoreAction.Store
  35. };
  36. internal RenderBufferStoreAction m_FinalDepthStoreAction = RenderBufferStoreAction.Store;
  37. private static partial class Profiling
  38. {
  39. public static readonly ProfilingSampler setMRTAttachmentsList = new ProfilingSampler($"NativeRenderPass {nameof(SetNativeRenderPassMRTAttachmentList)}");
  40. public static readonly ProfilingSampler setAttachmentList = new ProfilingSampler($"NativeRenderPass {nameof(SetNativeRenderPassAttachmentList)}");
  41. public static readonly ProfilingSampler configure = new ProfilingSampler($"NativeRenderPass {nameof(ConfigureNativeRenderPass)}");
  42. public static readonly ProfilingSampler execute = new ProfilingSampler($"NativeRenderPass {nameof(ExecuteNativeRenderPass)}");
  43. public static readonly ProfilingSampler setupFrameData = new ProfilingSampler($"NativeRenderPass {nameof(SetupNativeRenderPassFrameData)}");
  44. }
  45. internal struct RenderPassDescriptor
  46. {
  47. internal int w, h, samples, depthID;
  48. internal RenderPassDescriptor(int width, int height, int sampleCount, int rtID)
  49. {
  50. w = width;
  51. h = height;
  52. samples = sampleCount;
  53. depthID = rtID;
  54. }
  55. }
  56. internal void ResetNativeRenderPassFrameData()
  57. {
  58. if (m_MergeableRenderPassesMapArrays == null)
  59. m_MergeableRenderPassesMapArrays = new int[kRenderPassMapSize][];
  60. for (int i = 0; i < kRenderPassMapSize; ++i)
  61. {
  62. if (m_MergeableRenderPassesMapArrays[i] == null)
  63. m_MergeableRenderPassesMapArrays[i] = new int[kRenderPassMaxCount];
  64. for (int j = 0; j < kRenderPassMaxCount; ++j)
  65. {
  66. m_MergeableRenderPassesMapArrays[i][j] = -1;
  67. }
  68. }
  69. }
  70. internal void SetupNativeRenderPassFrameData(CameraData cameraData, bool isRenderPassEnabled)
  71. {
  72. //TODO: edge cases to detect that should affect possible passes to merge
  73. // - total number of color attachment > 8
  74. // Go through all the passes and mark the final one as last pass
  75. using (new ProfilingScope(null, Profiling.setupFrameData))
  76. {
  77. int lastPassIndex = m_ActiveRenderPassQueue.Count - 1;
  78. // Make sure the list is already sorted!
  79. m_MergeableRenderPassesMap.Clear();
  80. m_RenderPassesAttachmentCount.Clear();
  81. uint currentHashIndex = 0;
  82. // reset all the passes last pass flag
  83. for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
  84. {
  85. var renderPass = m_ActiveRenderPassQueue[i];
  86. // Empty configure to setup dimensions/targets and whatever data is needed for merging
  87. // We do not execute this at this time, so render targets are still invalid
  88. var rpDesc = InitializeRenderPassDescriptor(cameraData, renderPass);
  89. renderPass.isLastPass = false;
  90. renderPass.renderPassQueueIndex = i;
  91. bool RPEnabled = renderPass.useNativeRenderPass && isRenderPassEnabled;
  92. if (!RPEnabled)
  93. continue;
  94. Hash128 hash = CreateRenderPassHash(rpDesc, currentHashIndex);
  95. m_PassIndexToPassHash[i] = hash;
  96. if (!m_MergeableRenderPassesMap.ContainsKey(hash))
  97. {
  98. m_MergeableRenderPassesMap.Add(hash, m_MergeableRenderPassesMapArrays[m_MergeableRenderPassesMap.Count]);
  99. m_RenderPassesAttachmentCount.Add(hash, 0);
  100. }
  101. else if (m_MergeableRenderPassesMap[hash][GetValidPassIndexCount(m_MergeableRenderPassesMap[hash]) - 1] != (i - 1))
  102. {
  103. // if the passes are not sequential we want to split the current mergeable passes list. So we increment the hashIndex and update the hash
  104. currentHashIndex++;
  105. hash = CreateRenderPassHash(rpDesc, currentHashIndex);
  106. m_PassIndexToPassHash[i] = hash;
  107. m_MergeableRenderPassesMap.Add(hash, m_MergeableRenderPassesMapArrays[m_MergeableRenderPassesMap.Count]);
  108. m_RenderPassesAttachmentCount.Add(hash, 0);
  109. }
  110. m_MergeableRenderPassesMap[hash][GetValidPassIndexCount(m_MergeableRenderPassesMap[hash])] = i;
  111. }
  112. m_ActiveRenderPassQueue[lastPassIndex].isLastPass = true;
  113. for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
  114. {
  115. m_ActiveRenderPassQueue[i].m_ColorAttachmentIndices = new NativeArray<int>(8, Allocator.Temp);
  116. m_ActiveRenderPassQueue[i].m_InputAttachmentIndices = new NativeArray<int>(8, Allocator.Temp);
  117. }
  118. }
  119. }
  120. internal void UpdateFinalStoreActions(int[] currentMergeablePasses, CameraData cameraData)
  121. {
  122. for (int i = 0; i < m_FinalColorStoreAction.Length; ++i)
  123. m_FinalColorStoreAction[i] = RenderBufferStoreAction.Store;
  124. m_FinalDepthStoreAction = RenderBufferStoreAction.Store;
  125. foreach (var passIdx in currentMergeablePasses)
  126. {
  127. if (!m_UseOptimizedStoreActions)
  128. break;
  129. if (passIdx == -1)
  130. break;
  131. ScriptableRenderPass pass = m_ActiveRenderPassQueue[passIdx];
  132. var samples = pass.renderTargetSampleCount != -1
  133. ? pass.renderTargetSampleCount
  134. : cameraData.cameraTargetDescriptor.msaaSamples;
  135. // only override existing non destructive actions
  136. for (int i = 0; i < m_FinalColorStoreAction.Length; ++i)
  137. {
  138. if (m_FinalColorStoreAction[i] == RenderBufferStoreAction.Store || m_FinalColorStoreAction[i] == RenderBufferStoreAction.StoreAndResolve || pass.overriddenColorStoreActions[i])
  139. m_FinalColorStoreAction[i] = pass.colorStoreActions[i];
  140. if (samples > 1)
  141. {
  142. if (m_FinalColorStoreAction[i] == RenderBufferStoreAction.Store)
  143. m_FinalColorStoreAction[i] = RenderBufferStoreAction.StoreAndResolve;
  144. else if (m_FinalColorStoreAction[i] == RenderBufferStoreAction.DontCare)
  145. m_FinalColorStoreAction[i] = RenderBufferStoreAction.Resolve;
  146. }
  147. }
  148. // only override existing store
  149. if (m_FinalDepthStoreAction == RenderBufferStoreAction.Store || (m_FinalDepthStoreAction == RenderBufferStoreAction.StoreAndResolve && pass.depthStoreAction == RenderBufferStoreAction.Resolve) || pass.overriddenDepthStoreAction)
  150. m_FinalDepthStoreAction = pass.depthStoreAction;
  151. }
  152. }
  153. internal void SetNativeRenderPassMRTAttachmentList(ScriptableRenderPass renderPass, ref CameraData cameraData, bool needCustomCameraColorClear, ClearFlag clearFlag)
  154. {
  155. using (new ProfilingScope(null, Profiling.setMRTAttachmentsList))
  156. {
  157. int currentPassIndex = renderPass.renderPassQueueIndex;
  158. Hash128 currentPassHash = m_PassIndexToPassHash[currentPassIndex];
  159. int[] currentMergeablePasses = m_MergeableRenderPassesMap[currentPassHash];
  160. // Not the first pass
  161. if (currentMergeablePasses.First() != currentPassIndex)
  162. return;
  163. m_RenderPassesAttachmentCount[currentPassHash] = 0;
  164. UpdateFinalStoreActions(currentMergeablePasses, cameraData);
  165. int currentAttachmentIdx = 0;
  166. bool hasInput = false;
  167. foreach (var passIdx in currentMergeablePasses)
  168. {
  169. if (passIdx == -1)
  170. break;
  171. ScriptableRenderPass pass = m_ActiveRenderPassQueue[passIdx];
  172. for (int i = 0; i < pass.m_ColorAttachmentIndices.Length; ++i)
  173. pass.m_ColorAttachmentIndices[i] = -1;
  174. for (int i = 0; i < pass.m_InputAttachmentIndices.Length; ++i)
  175. pass.m_InputAttachmentIndices[i] = -1;
  176. uint validColorBuffersCount = RenderingUtils.GetValidColorBufferCount(pass.colorAttachments);
  177. for (int i = 0; i < validColorBuffersCount; ++i)
  178. {
  179. AttachmentDescriptor currentAttachmentDescriptor =
  180. new AttachmentDescriptor(pass.renderTargetFormat[i] != GraphicsFormat.None ? pass.renderTargetFormat[i] : GetDefaultGraphicsFormat(cameraData));
  181. var colorTarget = pass.overrideCameraTarget ? pass.colorAttachments[i] : m_CameraColorTarget;
  182. int existingAttachmentIndex = FindAttachmentDescriptorIndexInList(colorTarget, m_ActiveColorAttachmentDescriptors);
  183. if (m_UseOptimizedStoreActions)
  184. currentAttachmentDescriptor.storeAction = m_FinalColorStoreAction[i];
  185. if (existingAttachmentIndex == -1)
  186. {
  187. // add a new attachment
  188. m_ActiveColorAttachmentDescriptors[currentAttachmentIdx] = currentAttachmentDescriptor;
  189. m_ActiveColorAttachmentDescriptors[currentAttachmentIdx].ConfigureTarget(colorTarget, (pass.clearFlag & ClearFlag.Color) == 0, true);
  190. if (pass.colorAttachments[i] == m_CameraColorTarget && needCustomCameraColorClear && (clearFlag & ClearFlag.Color) != 0)
  191. m_ActiveColorAttachmentDescriptors[currentAttachmentIdx].ConfigureClear(CoreUtils.ConvertSRGBToActiveColorSpace(cameraData.camera.backgroundColor), 1.0f, 0);
  192. else if ((pass.clearFlag & ClearFlag.Color) != 0)
  193. m_ActiveColorAttachmentDescriptors[currentAttachmentIdx].ConfigureClear(CoreUtils.ConvertSRGBToActiveColorSpace(pass.clearColor), 1.0f, 0);
  194. pass.m_ColorAttachmentIndices[i] = currentAttachmentIdx;
  195. currentAttachmentIdx++;
  196. m_RenderPassesAttachmentCount[currentPassHash]++;
  197. }
  198. else
  199. {
  200. // attachment was already present
  201. pass.m_ColorAttachmentIndices[i] = existingAttachmentIndex;
  202. }
  203. }
  204. if (PassHasInputAttachments(pass))
  205. {
  206. hasInput = true;
  207. SetupInputAttachmentIndices(pass);
  208. }
  209. // TODO: this is redundant and is being setup for each attachment. Needs to be done only once per mergeable pass list (we need to make sure mergeable passes use the same depth!)
  210. m_ActiveDepthAttachmentDescriptor = new AttachmentDescriptor(SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil));
  211. m_ActiveDepthAttachmentDescriptor.ConfigureTarget(pass.overrideCameraTarget ? pass.depthAttachment : m_CameraDepthTarget, (clearFlag & ClearFlag.DepthStencil) == 0, true);
  212. if ((clearFlag & ClearFlag.DepthStencil) != 0)
  213. m_ActiveDepthAttachmentDescriptor.ConfigureClear(Color.black, 1.0f, 0);
  214. if (m_UseOptimizedStoreActions)
  215. m_ActiveDepthAttachmentDescriptor.storeAction = m_FinalDepthStoreAction;
  216. }
  217. if (hasInput)
  218. SetupTransientInputAttachments(m_RenderPassesAttachmentCount[currentPassHash]);
  219. }
  220. }
  221. bool IsDepthOnlyRenderTexture(RenderTexture t)
  222. {
  223. if (t.graphicsFormat == GraphicsFormat.None ||
  224. #pragma warning disable 0618 // Disable deprecation warnings. If you get here once these formats are really gone, the code in this #pragma can simply be removed
  225. t.graphicsFormat == GraphicsFormat.DepthAuto ||
  226. t.graphicsFormat == GraphicsFormat.ShadowAuto
  227. #pragma warning restore 0618
  228. )
  229. {
  230. return true;
  231. }
  232. return false;
  233. }
  234. internal void SetNativeRenderPassAttachmentList(ScriptableRenderPass renderPass, ref CameraData cameraData, RenderTargetIdentifier passColorAttachment, RenderTargetIdentifier passDepthAttachment, ClearFlag finalClearFlag, Color finalClearColor)
  235. {
  236. using (new ProfilingScope(null, Profiling.setAttachmentList))
  237. {
  238. int currentPassIndex = renderPass.renderPassQueueIndex;
  239. Hash128 currentPassHash = m_PassIndexToPassHash[currentPassIndex];
  240. int[] currentMergeablePasses = m_MergeableRenderPassesMap[currentPassHash];
  241. // Skip if not the first pass
  242. if (currentMergeablePasses.First() != currentPassIndex)
  243. return;
  244. m_RenderPassesAttachmentCount[currentPassHash] = 0;
  245. UpdateFinalStoreActions(currentMergeablePasses, cameraData);
  246. int currentAttachmentIdx = 0;
  247. foreach (var passIdx in currentMergeablePasses)
  248. {
  249. if (passIdx == -1)
  250. break;
  251. ScriptableRenderPass pass = m_ActiveRenderPassQueue[passIdx];
  252. for (int i = 0; i < pass.m_ColorAttachmentIndices.Length; ++i)
  253. pass.m_ColorAttachmentIndices[i] = -1;
  254. AttachmentDescriptor currentAttachmentDescriptor;
  255. var usesTargetTexture = cameraData.targetTexture != null;
  256. var depthOnly = renderPass.depthOnly || (usesTargetTexture && IsDepthOnlyRenderTexture(cameraData.targetTexture));
  257. // Offscreen depth-only cameras need this set explicitly
  258. if (depthOnly && usesTargetTexture)
  259. {
  260. if (IsDepthOnlyRenderTexture(cameraData.targetTexture) && !pass.overrideCameraTarget)
  261. passColorAttachment = new RenderTargetIdentifier(cameraData.targetTexture);
  262. else
  263. passColorAttachment = renderPass.colorAttachment;
  264. currentAttachmentDescriptor = new AttachmentDescriptor(SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil));
  265. }
  266. else
  267. currentAttachmentDescriptor =
  268. new AttachmentDescriptor(cameraData.cameraTargetDescriptor.graphicsFormat);
  269. if (pass.overrideCameraTarget)
  270. currentAttachmentDescriptor = new AttachmentDescriptor(pass.renderTargetFormat[0] != GraphicsFormat.None ? pass.renderTargetFormat[0] : GetDefaultGraphicsFormat(cameraData));
  271. var samples = pass.renderTargetSampleCount != -1
  272. ? pass.renderTargetSampleCount
  273. : cameraData.cameraTargetDescriptor.msaaSamples;
  274. var colorAttachmentTarget =
  275. (depthOnly || passColorAttachment != BuiltinRenderTextureType.CameraTarget)
  276. ? passColorAttachment : (usesTargetTexture
  277. ? new RenderTargetIdentifier(cameraData.targetTexture.colorBuffer)
  278. : BuiltinRenderTextureType.CameraTarget);
  279. var depthAttachmentTarget = (passDepthAttachment != BuiltinRenderTextureType.CameraTarget) ?
  280. passDepthAttachment : (usesTargetTexture
  281. ? new RenderTargetIdentifier(cameraData.targetTexture.depthBuffer)
  282. : BuiltinRenderTextureType.Depth);
  283. currentAttachmentDescriptor.ConfigureTarget(colorAttachmentTarget, ((uint)finalClearFlag & (uint)ClearFlag.Color) == 0, true);
  284. if (PassHasInputAttachments(pass))
  285. SetupInputAttachmentIndices(pass);
  286. // TODO: this is redundant and is being setup for each attachment. Needs to be done only once per mergeable pass list (we need to make sure mergeable passes use the same depth!)
  287. m_ActiveDepthAttachmentDescriptor = new AttachmentDescriptor(SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil));
  288. m_ActiveDepthAttachmentDescriptor.ConfigureTarget(depthAttachmentTarget,
  289. ((uint)finalClearFlag & (uint)ClearFlag.Depth) == 0, true);
  290. if (finalClearFlag != ClearFlag.None)
  291. {
  292. // We don't clear color for Overlay render targets, however pipeline set's up depth only render passes as color attachments which we do need to clear
  293. if ((cameraData.renderType != CameraRenderType.Overlay || depthOnly && ((uint)finalClearFlag & (uint)ClearFlag.Color) != 0))
  294. currentAttachmentDescriptor.ConfigureClear(finalClearColor, 1.0f, 0);
  295. if (((uint)finalClearFlag & (uint)ClearFlag.Depth) != 0)
  296. m_ActiveDepthAttachmentDescriptor.ConfigureClear(Color.black, 1.0f, 0);
  297. }
  298. // resolving to the implicit color target's resolve surface TODO: handle m_CameraResolveTarget if present?
  299. if (samples > 1)
  300. currentAttachmentDescriptor.ConfigureResolveTarget(colorAttachmentTarget);
  301. if (m_UseOptimizedStoreActions)
  302. {
  303. currentAttachmentDescriptor.storeAction = m_FinalColorStoreAction[0];
  304. m_ActiveDepthAttachmentDescriptor.storeAction = m_FinalDepthStoreAction;
  305. }
  306. int existingAttachmentIndex = FindAttachmentDescriptorIndexInList(currentAttachmentIdx,
  307. currentAttachmentDescriptor, m_ActiveColorAttachmentDescriptors);
  308. if (existingAttachmentIndex == -1)
  309. {
  310. // add a new attachment
  311. pass.m_ColorAttachmentIndices[0] = currentAttachmentIdx;
  312. m_ActiveColorAttachmentDescriptors[currentAttachmentIdx] = currentAttachmentDescriptor;
  313. currentAttachmentIdx++;
  314. m_RenderPassesAttachmentCount[currentPassHash]++;
  315. }
  316. else
  317. {
  318. // attachment was already present
  319. pass.m_ColorAttachmentIndices[0] = existingAttachmentIndex;
  320. }
  321. }
  322. }
  323. }
  324. internal void ConfigureNativeRenderPass(CommandBuffer cmd, ScriptableRenderPass renderPass, CameraData cameraData)
  325. {
  326. using (new ProfilingScope(null, Profiling.configure))
  327. {
  328. int currentPassIndex = renderPass.renderPassQueueIndex;
  329. Hash128 currentPassHash = m_PassIndexToPassHash[currentPassIndex];
  330. int[] currentMergeablePasses = m_MergeableRenderPassesMap[currentPassHash];
  331. // If it's the first pass, configure the whole merge block
  332. if (currentMergeablePasses.First() == currentPassIndex)
  333. {
  334. foreach (var passIdx in currentMergeablePasses)
  335. {
  336. if (passIdx == -1)
  337. break;
  338. ScriptableRenderPass pass = m_ActiveRenderPassQueue[passIdx];
  339. pass.Configure(cmd, cameraData.cameraTargetDescriptor);
  340. }
  341. }
  342. }
  343. }
  344. internal void ExecuteNativeRenderPass(ScriptableRenderContext context, ScriptableRenderPass renderPass, CameraData cameraData, ref RenderingData renderingData)
  345. {
  346. using (new ProfilingScope(null, Profiling.execute))
  347. {
  348. int currentPassIndex = renderPass.renderPassQueueIndex;
  349. Hash128 currentPassHash = m_PassIndexToPassHash[currentPassIndex];
  350. int[] currentMergeablePasses = m_MergeableRenderPassesMap[currentPassHash];
  351. int validColorBuffersCount = m_RenderPassesAttachmentCount[currentPassHash];
  352. bool isLastPass = renderPass.isLastPass;
  353. // TODO: review the lastPassToBB logic to mak it work with merged passes
  354. // keep track if this is the current camera's last pass and the RT is the backbuffer (BuiltinRenderTextureType.CameraTarget)
  355. bool isLastPassToBB = isLastPass && (m_ActiveColorAttachmentDescriptors[0].loadStoreTarget ==
  356. BuiltinRenderTextureType.CameraTarget);
  357. var depthOnly = renderPass.depthOnly || (cameraData.targetTexture != null && IsDepthOnlyRenderTexture(cameraData.targetTexture));
  358. bool useDepth = depthOnly || (!renderPass.overrideCameraTarget || (renderPass.overrideCameraTarget && renderPass.depthAttachment != BuiltinRenderTextureType.CameraTarget)) &&
  359. (!(isLastPassToBB || (isLastPass && cameraData.camera.targetTexture != null)));
  360. var attachments =
  361. new NativeArray<AttachmentDescriptor>(useDepth && !depthOnly ? validColorBuffersCount + 1 : 1,
  362. Allocator.Temp);
  363. for (int i = 0; i < validColorBuffersCount; ++i)
  364. attachments[i] = m_ActiveColorAttachmentDescriptors[i];
  365. if (useDepth && !depthOnly)
  366. attachments[validColorBuffersCount] = m_ActiveDepthAttachmentDescriptor;
  367. var rpDesc = InitializeRenderPassDescriptor(cameraData, renderPass);
  368. int validPassCount = GetValidPassIndexCount(currentMergeablePasses);
  369. var attachmentIndicesCount = GetSubPassAttachmentIndicesCount(renderPass);
  370. var attachmentIndices = new NativeArray<int>(!depthOnly ? (int)attachmentIndicesCount : 0, Allocator.Temp);
  371. if (!depthOnly)
  372. {
  373. for (int i = 0; i < attachmentIndicesCount; ++i)
  374. {
  375. attachmentIndices[i] = renderPass.m_ColorAttachmentIndices[i];
  376. }
  377. }
  378. if (validPassCount == 1 || currentMergeablePasses[0] == currentPassIndex) // Check if it's the first pass
  379. {
  380. if (PassHasInputAttachments(renderPass))
  381. Debug.LogWarning("First pass in a RenderPass should not have input attachments.");
  382. context.BeginRenderPass(rpDesc.w, rpDesc.h, Math.Max(rpDesc.samples, 1), attachments,
  383. useDepth ? (!depthOnly ? validColorBuffersCount : 0) : -1);
  384. attachments.Dispose();
  385. context.BeginSubPass(attachmentIndices);
  386. m_LastBeginSubpassPassIndex = currentPassIndex;
  387. }
  388. else
  389. {
  390. // Regarding input attachments, currently we always recreate a new subpass if it contains input attachments
  391. // This might not the most optimal way though and it should be investigated in the future
  392. // Whether merging subpasses with matching input attachments is a more viable option
  393. if (!AreAttachmentIndicesCompatible(m_ActiveRenderPassQueue[m_LastBeginSubpassPassIndex], m_ActiveRenderPassQueue[currentPassIndex]))
  394. {
  395. context.EndSubPass();
  396. if (PassHasInputAttachments(m_ActiveRenderPassQueue[currentPassIndex]))
  397. context.BeginSubPass(attachmentIndices, m_ActiveRenderPassQueue[currentPassIndex].m_InputAttachmentIndices);
  398. else
  399. context.BeginSubPass(attachmentIndices);
  400. m_LastBeginSubpassPassIndex = currentPassIndex;
  401. }
  402. else if (PassHasInputAttachments(m_ActiveRenderPassQueue[currentPassIndex]))
  403. {
  404. context.EndSubPass();
  405. context.BeginSubPass(attachmentIndices, m_ActiveRenderPassQueue[currentPassIndex].m_InputAttachmentIndices);
  406. m_LastBeginSubpassPassIndex = currentPassIndex;
  407. }
  408. }
  409. attachmentIndices.Dispose();
  410. renderPass.Execute(context, ref renderingData);
  411. if (validPassCount == 1 || currentMergeablePasses[validPassCount - 1] == currentPassIndex) // Check if it's the last pass
  412. {
  413. context.EndSubPass();
  414. context.EndRenderPass();
  415. m_LastBeginSubpassPassIndex = 0;
  416. }
  417. for (int i = 0; i < m_ActiveColorAttachmentDescriptors.Length; ++i)
  418. {
  419. m_ActiveColorAttachmentDescriptors[i] = RenderingUtils.emptyAttachment;
  420. m_IsActiveColorAttachmentTransient[i] = false;
  421. }
  422. m_ActiveDepthAttachmentDescriptor = RenderingUtils.emptyAttachment;
  423. }
  424. }
  425. internal void SetupInputAttachmentIndices(ScriptableRenderPass pass)
  426. {
  427. var validInputBufferCount = GetValidInputAttachmentCount(pass);
  428. pass.m_InputAttachmentIndices = new NativeArray<int>(validInputBufferCount, Allocator.Temp);
  429. for (int i = 0; i < validInputBufferCount; i++)
  430. {
  431. pass.m_InputAttachmentIndices[i] = FindAttachmentDescriptorIndexInList(pass.m_InputAttachments[i], m_ActiveColorAttachmentDescriptors);
  432. if (pass.m_InputAttachmentIndices[i] == -1)
  433. {
  434. Debug.LogWarning("RenderPass Input attachment not found in the current RenderPass");
  435. continue;
  436. }
  437. // Only update it as long as it has default value - if it was changed once, we assume it'll be memoryless in the whole RenderPass
  438. if (!m_IsActiveColorAttachmentTransient[pass.m_InputAttachmentIndices[i]])
  439. m_IsActiveColorAttachmentTransient[pass.m_InputAttachmentIndices[i]] = pass.IsInputAttachmentTransient(i);
  440. }
  441. }
  442. internal void SetupTransientInputAttachments(int attachmentCount)
  443. {
  444. for (int i = 0; i < attachmentCount; ++i)
  445. {
  446. if (!m_IsActiveColorAttachmentTransient[i])
  447. continue;
  448. m_ActiveColorAttachmentDescriptors[i].loadAction = RenderBufferLoadAction.DontCare;
  449. m_ActiveColorAttachmentDescriptors[i].storeAction = RenderBufferStoreAction.DontCare;
  450. // We change the target of the descriptor for it to be initialized engine-side as a transient resource.
  451. m_ActiveColorAttachmentDescriptors[i].loadStoreTarget = BuiltinRenderTextureType.None;
  452. }
  453. }
  454. internal static uint GetSubPassAttachmentIndicesCount(ScriptableRenderPass pass)
  455. {
  456. uint numValidAttachments = 0;
  457. foreach (var attIdx in pass.m_ColorAttachmentIndices)
  458. {
  459. if (attIdx >= 0)
  460. ++numValidAttachments;
  461. }
  462. return numValidAttachments;
  463. }
  464. internal static bool AreAttachmentIndicesCompatible(ScriptableRenderPass lastSubPass, ScriptableRenderPass currentSubPass)
  465. {
  466. uint lastSubPassAttCount = GetSubPassAttachmentIndicesCount(lastSubPass);
  467. uint currentSubPassAttCount = GetSubPassAttachmentIndicesCount(currentSubPass);
  468. if (currentSubPassAttCount > lastSubPassAttCount)
  469. return false;
  470. uint numEqualAttachments = 0;
  471. for (int currPassIdx = 0; currPassIdx < currentSubPassAttCount; ++currPassIdx)
  472. {
  473. for (int lastPassIdx = 0; lastPassIdx < lastSubPassAttCount; ++lastPassIdx)
  474. {
  475. if (currentSubPass.m_ColorAttachmentIndices[currPassIdx] == lastSubPass.m_ColorAttachmentIndices[lastPassIdx])
  476. numEqualAttachments++;
  477. }
  478. }
  479. return (numEqualAttachments == currentSubPassAttCount);
  480. }
  481. internal static uint GetValidColorAttachmentCount(AttachmentDescriptor[] colorAttachments)
  482. {
  483. uint nonNullColorBuffers = 0;
  484. if (colorAttachments != null)
  485. {
  486. foreach (var attachment in colorAttachments)
  487. {
  488. if (attachment != RenderingUtils.emptyAttachment)
  489. ++nonNullColorBuffers;
  490. }
  491. }
  492. return nonNullColorBuffers;
  493. }
  494. internal static int GetValidInputAttachmentCount(ScriptableRenderPass renderPass)
  495. {
  496. var length = renderPass.m_InputAttachments.Length;
  497. if (length != 8) // overriden, there are attachments
  498. return length;
  499. else
  500. {
  501. for (int i = 0; i < length; ++i)
  502. {
  503. if (renderPass.m_InputAttachments[i] == -1)
  504. return i;
  505. }
  506. return length;
  507. }
  508. }
  509. internal static int FindAttachmentDescriptorIndexInList(int attachmentIdx, AttachmentDescriptor attachmentDescriptor, AttachmentDescriptor[] attachmentDescriptors)
  510. {
  511. int existingAttachmentIndex = -1;
  512. for (int i = 0; i <= attachmentIdx; ++i)
  513. {
  514. AttachmentDescriptor att = attachmentDescriptors[i];
  515. if (att.loadStoreTarget == attachmentDescriptor.loadStoreTarget && att.graphicsFormat == attachmentDescriptor.graphicsFormat)
  516. {
  517. existingAttachmentIndex = i;
  518. break;
  519. }
  520. }
  521. return existingAttachmentIndex;
  522. }
  523. internal static int FindAttachmentDescriptorIndexInList(RenderTargetIdentifier target, AttachmentDescriptor[] attachmentDescriptors)
  524. {
  525. for (int i = 0; i < attachmentDescriptors.Length; i++)
  526. {
  527. AttachmentDescriptor att = attachmentDescriptors[i];
  528. if (att.loadStoreTarget == target)
  529. return i;
  530. }
  531. return -1;
  532. }
  533. internal static int GetValidPassIndexCount(int[] array)
  534. {
  535. if (array == null)
  536. return 0;
  537. for (int i = 0; i < array.Length; ++i)
  538. {
  539. if (array[i] == -1)
  540. return i;
  541. }
  542. return array.Length - 1;
  543. }
  544. internal static bool PassHasInputAttachments(ScriptableRenderPass renderPass)
  545. {
  546. return renderPass.m_InputAttachments.Length != 8 || renderPass.m_InputAttachments[0] != -1;
  547. }
  548. internal static Hash128 CreateRenderPassHash(int width, int height, int depthID, int sample, uint hashIndex)
  549. {
  550. return new Hash128((uint)(width << 4) + (uint)height, (uint)depthID, (uint)sample, hashIndex);
  551. }
  552. internal static Hash128 CreateRenderPassHash(RenderPassDescriptor desc, uint hashIndex)
  553. {
  554. return CreateRenderPassHash(desc.w, desc.h, desc.depthID, desc.samples, hashIndex);
  555. }
  556. private RenderPassDescriptor InitializeRenderPassDescriptor(CameraData cameraData, ScriptableRenderPass renderPass)
  557. {
  558. var w = (renderPass.renderTargetWidth != -1) ? renderPass.renderTargetWidth : cameraData.cameraTargetDescriptor.width;
  559. var h = (renderPass.renderTargetHeight != -1) ? renderPass.renderTargetHeight : cameraData.cameraTargetDescriptor.height;
  560. var samples = (renderPass.renderTargetSampleCount != -1) ? renderPass.renderTargetSampleCount : cameraData.cameraTargetDescriptor.msaaSamples;
  561. var depthTarget = renderPass.overrideCameraTarget ? renderPass.depthAttachment : m_CameraDepthTarget;
  562. var depthID = renderPass.depthOnly ? renderPass.colorAttachment.GetHashCode() : depthTarget.GetHashCode();
  563. return new RenderPassDescriptor(w, h, samples, depthID);
  564. }
  565. private static GraphicsFormat GetDefaultGraphicsFormat(CameraData cameraData)
  566. {
  567. if (cameraData.isHdrEnabled)
  568. {
  569. GraphicsFormat hdrFormat = GraphicsFormat.None;
  570. if (!Graphics.preserveFramebufferAlpha &&
  571. RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.B10G11R11_UFloatPack32,
  572. FormatUsage.Linear | FormatUsage.Render))
  573. hdrFormat = GraphicsFormat.B10G11R11_UFloatPack32;
  574. else if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R16G16B16A16_SFloat,
  575. FormatUsage.Linear | FormatUsage.Render))
  576. hdrFormat = GraphicsFormat.R16G16B16A16_SFloat;
  577. else
  578. hdrFormat = SystemInfo.GetGraphicsFormat(DefaultFormat.HDR);
  579. return hdrFormat;
  580. }
  581. return SystemInfo.GetGraphicsFormat(DefaultFormat.LDR);
  582. }
  583. }
  584. }