暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

NativeRenderPass.cs 36KB

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