ScriptableRenderer.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. using System;
  2. using System.Diagnostics;
  3. using System.Collections.Generic;
  4. using Unity.Collections;
  5. using UnityEngine.Scripting.APIUpdating;
  6. namespace UnityEngine.Rendering.Universal
  7. {
  8. /// <summary>
  9. /// Class <c>ScriptableRenderer</c> implements a rendering strategy. It describes how culling and lighting works and
  10. /// the effects supported.
  11. ///
  12. /// A renderer can be used for all cameras or be overridden on a per-camera basis. It will implement light culling and setup
  13. /// and describe a list of <c>ScriptableRenderPass</c> to execute in a frame. The renderer can be extended to support more effect with additional
  14. /// <c>ScriptableRendererFeature</c>. Resources for the renderer are serialized in <c>ScriptableRendererData</c>.
  15. ///
  16. /// he renderer resources are serialized in <c>ScriptableRendererData</c>.
  17. /// <seealso cref="ScriptableRendererData"/>
  18. /// <seealso cref="ScriptableRendererFeature"/>
  19. /// <seealso cref="ScriptableRenderPass"/>
  20. /// </summary>
  21. [MovedFrom("UnityEngine.Rendering.LWRP")] public abstract class ScriptableRenderer : IDisposable
  22. {
  23. /// <summary>
  24. /// Configures the supported features for this renderer. When creating custom renderers
  25. /// for Universal Render Pipeline you can choose to opt-in or out for specific features.
  26. /// </summary>
  27. public class RenderingFeatures
  28. {
  29. /// <summary>
  30. /// This setting controls if the camera editor should display the camera stack category.
  31. /// Renderers that don't support camera stacking will only render camera of type CameraRenderType.Base
  32. /// <see cref="CameraRenderType"/>
  33. /// <seealso cref="UniversalAdditionalCameraData.cameraStack"/>
  34. /// </summary>
  35. public bool cameraStacking { get; set; } = false;
  36. }
  37. void SetShaderTimeValues(float time, float deltaTime, float smoothDeltaTime, CommandBuffer cmd = null)
  38. {
  39. // We make these parameters to mirror those described in `https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
  40. float timeEights = time / 8f;
  41. float timeFourth = time / 4f;
  42. float timeHalf = time / 2f;
  43. // Time values
  44. Vector4 timeVector = time * new Vector4(1f / 20f, 1f, 2f, 3f);
  45. Vector4 sinTimeVector = new Vector4(Mathf.Sin(timeEights), Mathf.Sin(timeFourth), Mathf.Sin(timeHalf), Mathf.Sin(time));
  46. Vector4 cosTimeVector = new Vector4(Mathf.Cos(timeEights), Mathf.Cos(timeFourth), Mathf.Cos(timeHalf), Mathf.Cos(time));
  47. Vector4 deltaTimeVector = new Vector4(deltaTime, 1f / deltaTime, smoothDeltaTime, 1f / smoothDeltaTime);
  48. Vector4 timeParametersVector = new Vector4(time, Mathf.Sin(time), Mathf.Cos(time), 0.0f);
  49. if (cmd == null)
  50. {
  51. Shader.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._Time, timeVector);
  52. Shader.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._SinTime, sinTimeVector);
  53. Shader.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._CosTime, cosTimeVector);
  54. Shader.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer.unity_DeltaTime, deltaTimeVector);
  55. Shader.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._TimeParameters, timeParametersVector);
  56. }
  57. else
  58. {
  59. cmd.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._Time, timeVector);
  60. cmd.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._SinTime, sinTimeVector);
  61. cmd.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._CosTime, cosTimeVector);
  62. cmd.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer.unity_DeltaTime, deltaTimeVector);
  63. cmd.SetGlobalVector(UniversalRenderPipeline.PerFrameBuffer._TimeParameters, timeParametersVector);
  64. }
  65. }
  66. public RenderTargetIdentifier cameraColorTarget
  67. {
  68. get => m_CameraColorTarget;
  69. }
  70. public RenderTargetIdentifier cameraDepth
  71. {
  72. get => m_CameraDepthTarget;
  73. }
  74. protected List<ScriptableRendererFeature> rendererFeatures
  75. {
  76. get => m_RendererFeatures;
  77. }
  78. protected List<ScriptableRenderPass> activeRenderPassQueue
  79. {
  80. get => m_ActiveRenderPassQueue;
  81. }
  82. /// <summary>
  83. /// Supported rendering features by this renderer.
  84. /// <see cref="SupportedRenderingFeatures"/>
  85. /// </summary>
  86. public RenderingFeatures supportedRenderingFeatures { get; set; } = new RenderingFeatures();
  87. static class RenderPassBlock
  88. {
  89. // Executes render passes that are inputs to the main rendering
  90. // but don't depend on camera state. They all render in monoscopic mode. f.ex, shadow maps.
  91. public static readonly int BeforeRendering = 0;
  92. // Main bulk of render pass execution. They required camera state to be properly set
  93. // and when enabled they will render in stereo.
  94. public static readonly int MainRenderingOpaque = 1;
  95. public static readonly int MainRenderingTransparent = 2;
  96. // Execute after Post-processing.
  97. public static readonly int AfterRendering = 3;
  98. }
  99. const int k_RenderPassBlockCount = 4;
  100. List<ScriptableRenderPass> m_ActiveRenderPassQueue = new List<ScriptableRenderPass>(32);
  101. List<ScriptableRendererFeature> m_RendererFeatures = new List<ScriptableRendererFeature>(10);
  102. RenderTargetIdentifier m_CameraColorTarget;
  103. RenderTargetIdentifier m_CameraDepthTarget;
  104. bool m_FirstTimeCameraColorTargetIsBound = true; // flag used to track when m_CameraColorTarget should be cleared (if necessary), as well as other special actions only performed the first time m_CameraColorTarget is bound as a render target
  105. bool m_FirstTimeCameraDepthTargetIsBound = true; // flag used to track when m_CameraDepthTarget should be cleared (if necessary), the first time m_CameraDepthTarget is bound as a render target
  106. bool m_XRRenderTargetNeedsClear = false;
  107. const string k_SetCameraRenderStateTag = "Clear Render State";
  108. const string k_SetRenderTarget = "Set RenderTarget";
  109. const string k_ReleaseResourcesTag = "Release Resources";
  110. static RenderTargetIdentifier[] m_ActiveColorAttachments = new RenderTargetIdentifier[]{0, 0, 0, 0, 0, 0, 0, 0 };
  111. static RenderTargetIdentifier m_ActiveDepthAttachment;
  112. static bool m_InsideStereoRenderBlock;
  113. // CommandBuffer.SetRenderTarget(RenderTargetIdentifier[] colors, RenderTargetIdentifier depth, int mipLevel, CubemapFace cubemapFace, int depthSlice);
  114. // called from CoreUtils.SetRenderTarget will issue a warning assert from native c++ side if "colors" array contains some invalid RTIDs.
  115. // To avoid that warning assert we trim the RenderTargetIdentifier[] arrays we pass to CoreUtils.SetRenderTarget.
  116. // To avoid re-allocating a new array every time we do that, we re-use one of these arrays:
  117. static RenderTargetIdentifier[][] m_TrimmedColorAttachmentCopies = new RenderTargetIdentifier[][]
  118. {
  119. new RenderTargetIdentifier[0], // m_TrimmedColorAttachmentCopies[0] is an array of 0 RenderTargetIdentifier - only used to make indexing code easier to read
  120. new RenderTargetIdentifier[]{0}, // m_TrimmedColorAttachmentCopies[1] is an array of 1 RenderTargetIdentifier
  121. new RenderTargetIdentifier[]{0, 0}, // m_TrimmedColorAttachmentCopies[2] is an array of 2 RenderTargetIdentifiers
  122. new RenderTargetIdentifier[]{0, 0, 0}, // m_TrimmedColorAttachmentCopies[3] is an array of 3 RenderTargetIdentifiers
  123. new RenderTargetIdentifier[]{0, 0, 0, 0}, // m_TrimmedColorAttachmentCopies[4] is an array of 4 RenderTargetIdentifiers
  124. new RenderTargetIdentifier[]{0, 0, 0, 0, 0}, // m_TrimmedColorAttachmentCopies[5] is an array of 5 RenderTargetIdentifiers
  125. new RenderTargetIdentifier[]{0, 0, 0, 0, 0, 0}, // m_TrimmedColorAttachmentCopies[6] is an array of 6 RenderTargetIdentifiers
  126. new RenderTargetIdentifier[]{0, 0, 0, 0, 0, 0, 0}, // m_TrimmedColorAttachmentCopies[7] is an array of 7 RenderTargetIdentifiers
  127. new RenderTargetIdentifier[]{0, 0, 0, 0, 0, 0, 0, 0 }, // m_TrimmedColorAttachmentCopies[8] is an array of 8 RenderTargetIdentifiers
  128. };
  129. internal static void ConfigureActiveTarget(RenderTargetIdentifier colorAttachment,
  130. RenderTargetIdentifier depthAttachment)
  131. {
  132. m_ActiveColorAttachments[0] = colorAttachment;
  133. for (int i = 1; i < m_ActiveColorAttachments.Length; ++i)
  134. m_ActiveColorAttachments[i] = 0;
  135. m_ActiveDepthAttachment = depthAttachment;
  136. }
  137. public ScriptableRenderer(ScriptableRendererData data)
  138. {
  139. foreach (var feature in data.rendererFeatures)
  140. {
  141. if (feature == null)
  142. continue;
  143. feature.Create();
  144. m_RendererFeatures.Add(feature);
  145. }
  146. Clear(CameraRenderType.Base);
  147. }
  148. public void Dispose()
  149. {
  150. Dispose(true);
  151. GC.SuppressFinalize(this);
  152. }
  153. protected virtual void Dispose(bool disposing)
  154. {
  155. }
  156. /// <summary>
  157. /// Configures the camera target.
  158. /// </summary>
  159. /// <param name="colorTarget">Camera color target. Pass BuiltinRenderTextureType.CameraTarget if rendering to backbuffer.</param>
  160. /// <param name="depthTarget">Camera depth target. Pass BuiltinRenderTextureType.CameraTarget if color has depth or rendering to backbuffer.</param>
  161. public void ConfigureCameraTarget(RenderTargetIdentifier colorTarget, RenderTargetIdentifier depthTarget)
  162. {
  163. m_CameraColorTarget = colorTarget;
  164. m_CameraDepthTarget = depthTarget;
  165. }
  166. /// <summary>
  167. /// Configures the render passes that will execute for this renderer.
  168. /// This method is called per-camera every frame.
  169. /// </summary>
  170. /// <param name="context">Use this render context to issue any draw commands during execution.</param>
  171. /// <param name="renderingData">Current render state information.</param>
  172. /// <seealso cref="ScriptableRenderPass"/>
  173. /// <seealso cref="ScriptableRendererFeature"/>
  174. public abstract void Setup(ScriptableRenderContext context, ref RenderingData renderingData);
  175. /// <summary>
  176. /// Override this method to implement the lighting setup for the renderer. You can use this to
  177. /// compute and upload light CBUFFER for example.
  178. /// </summary>
  179. /// <param name="context">Use this render context to issue any draw commands during execution.</param>
  180. /// <param name="renderingData">Current render state information.</param>
  181. public virtual void SetupLights(ScriptableRenderContext context, ref RenderingData renderingData)
  182. {
  183. }
  184. /// <summary>
  185. /// Override this method to configure the culling parameters for the renderer. You can use this to configure if
  186. /// lights should be culled per-object or the maximum shadow distance for example.
  187. /// </summary>
  188. /// <param name="cullingParameters">Use this to change culling parameters used by the render pipeline.</param>
  189. /// <param name="cameraData">Current render state information.</param>
  190. public virtual void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters,
  191. ref CameraData cameraData)
  192. {
  193. }
  194. /// <summary>
  195. /// Called upon finishing rendering the camera stack. You can release any resources created by the renderer here.
  196. /// </summary>
  197. /// <param name="cmd"></param>
  198. public virtual void FinishRendering(CommandBuffer cmd)
  199. {
  200. }
  201. /// <summary>
  202. /// Execute the enqueued render passes. This automatically handles editor and stereo rendering.
  203. /// </summary>
  204. /// <param name="context">Use this render context to issue any draw commands during execution.</param>
  205. /// <param name="renderingData">Current render state information.</param>
  206. public void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  207. {
  208. ref CameraData cameraData = ref renderingData.cameraData;
  209. Camera camera = cameraData.camera;
  210. CommandBuffer cmd = CommandBufferPool.Get(k_SetCameraRenderStateTag);
  211. // Initialize Camera Render State
  212. SetCameraRenderState(cmd, ref cameraData);
  213. context.ExecuteCommandBuffer(cmd);
  214. cmd.Clear();
  215. // Sort the render pass queue
  216. SortStable(m_ActiveRenderPassQueue);
  217. // Cache the time for after the call to `SetupCameraProperties` and set the time variables in shader
  218. // For now we set the time variables per camera, as we plan to remove `SetupCamearProperties`.
  219. // Setting the time per frame would take API changes to pass the variable to each camera render.
  220. // Once `SetupCameraProperties` is gone, the variable should be set higher in the call-stack.
  221. #if UNITY_EDITOR
  222. float time = Application.isPlaying ? Time.time : Time.realtimeSinceStartup;
  223. #else
  224. float time = Time.time;
  225. #endif
  226. float deltaTime = Time.deltaTime;
  227. float smoothDeltaTime = Time.smoothDeltaTime;
  228. SetShaderTimeValues(time, deltaTime, smoothDeltaTime);
  229. // Upper limits for each block. Each block will contains render passes with events below the limit.
  230. NativeArray<RenderPassEvent> blockEventLimits = new NativeArray<RenderPassEvent>(k_RenderPassBlockCount, Allocator.Temp);
  231. blockEventLimits[RenderPassBlock.BeforeRendering] = RenderPassEvent.BeforeRenderingPrepasses;
  232. blockEventLimits[RenderPassBlock.MainRenderingOpaque] = RenderPassEvent.AfterRenderingOpaques;
  233. blockEventLimits[RenderPassBlock.MainRenderingTransparent] = RenderPassEvent.AfterRenderingPostProcessing;
  234. blockEventLimits[RenderPassBlock.AfterRendering] = (RenderPassEvent)Int32.MaxValue;
  235. NativeArray<int> blockRanges = new NativeArray<int>(blockEventLimits.Length + 1, Allocator.Temp);
  236. // blockRanges[0] is always 0
  237. // blockRanges[i] is the index of the first RenderPass found in m_ActiveRenderPassQueue that has a ScriptableRenderPass.renderPassEvent higher than blockEventLimits[i] (i.e, should be executed after blockEventLimits[i])
  238. // blockRanges[blockEventLimits.Length] is m_ActiveRenderPassQueue.Count
  239. FillBlockRanges(blockEventLimits, blockRanges);
  240. blockEventLimits.Dispose();
  241. SetupLights(context, ref renderingData);
  242. // Before Render Block. This render blocks always execute in mono rendering.
  243. // Camera is not setup. Lights are not setup.
  244. // Used to render input textures like shadowmaps.
  245. ExecuteBlock(RenderPassBlock.BeforeRendering, blockRanges, context, ref renderingData);
  246. for (int eyeIndex = 0; eyeIndex < renderingData.cameraData.numberOfXRPasses; ++eyeIndex)
  247. {
  248. /// Configure shader variables and other unity properties that are required for rendering.
  249. /// * Setup Camera RenderTarget and Viewport
  250. /// * VR Camera Setup and SINGLE_PASS_STEREO props
  251. /// * Setup camera view, projection and their inverse matrices.
  252. /// * Setup properties: _WorldSpaceCameraPos, _ProjectionParams, _ScreenParams, _ZBufferParams, unity_OrthoParams
  253. /// * Setup camera world clip planes properties
  254. /// * Setup HDR keyword
  255. /// * Setup global time properties (_Time, _SinTime, _CosTime)
  256. bool stereoEnabled = renderingData.cameraData.isStereoEnabled;
  257. context.SetupCameraProperties(camera, stereoEnabled, eyeIndex);
  258. // If overlay camera, we have to reset projection related matrices due to inheriting viewport from base
  259. // camera. This changes the aspect ratio, which requires to recompute projection.
  260. // TODO: We need to expose all work done in SetupCameraProperties above to c# land. This not only
  261. // avoids resetting values but also guarantee values are correct for all systems.
  262. // Known Issue: billboard will not work with camera stacking when using viewport with aspect ratio different from default aspect.
  263. if (cameraData.renderType == CameraRenderType.Overlay)
  264. {
  265. cmd.SetViewProjectionMatrices(cameraData.viewMatrix, cameraData.projectionMatrix);
  266. }
  267. // Override time values from when `SetupCameraProperties` were called.
  268. // They might be a frame behind.
  269. // We can remove this after removing `SetupCameraProperties` as the values should be per frame, and not per camera.
  270. SetShaderTimeValues(time, deltaTime, smoothDeltaTime, cmd);
  271. context.ExecuteCommandBuffer(cmd);
  272. cmd.Clear();
  273. if (stereoEnabled)
  274. BeginXRRendering(context, camera, eyeIndex);
  275. #if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER
  276. var localCmd = CommandBufferPool.Get(string.Empty);
  277. //Triggers dispatch per camera, all global parameters should have been setup at this stage.
  278. VFX.VFXManager.ProcessCameraCommand(camera, localCmd);
  279. context.ExecuteCommandBuffer(localCmd);
  280. CommandBufferPool.Release(localCmd);
  281. #endif
  282. // In the opaque and transparent blocks the main rendering executes.
  283. // Opaque blocks...
  284. ExecuteBlock(RenderPassBlock.MainRenderingOpaque, blockRanges, context, ref renderingData, eyeIndex);
  285. // Transparent blocks...
  286. ExecuteBlock(RenderPassBlock.MainRenderingTransparent, blockRanges, context, ref renderingData, eyeIndex);
  287. // Draw Gizmos...
  288. DrawGizmos(context, camera, GizmoSubset.PreImageEffects);
  289. // In this block after rendering drawing happens, e.g, post processing, video player capture.
  290. ExecuteBlock(RenderPassBlock.AfterRendering, blockRanges, context, ref renderingData, eyeIndex);
  291. if (stereoEnabled)
  292. EndXRRendering(context, renderingData, eyeIndex);
  293. }
  294. DrawGizmos(context, camera, GizmoSubset.PostImageEffects);
  295. InternalFinishRendering(context, renderingData.resolveFinalTarget);
  296. blockRanges.Dispose();
  297. CommandBufferPool.Release(cmd);
  298. }
  299. /// <summary>
  300. /// Enqueues a render pass for execution.
  301. /// </summary>
  302. /// <param name="pass">Render pass to be enqueued.</param>
  303. public void EnqueuePass(ScriptableRenderPass pass)
  304. {
  305. m_ActiveRenderPassQueue.Add(pass);
  306. }
  307. #region deprecated
  308. [Obsolete("Use GetCameraClearFlag(ref CameraData cameraData) instead")]
  309. protected static ClearFlag GetCameraClearFlag(CameraClearFlags cameraClearFlags)
  310. {
  311. #if UNITY_EDITOR
  312. // We need public API to tell if FrameDebugger is active and enabled. In that case
  313. // we want to force a clear to see properly the drawcall stepping.
  314. // For now, to fix FrameDebugger in Editor, we force a clear.
  315. cameraClearFlags = CameraClearFlags.SolidColor;
  316. #endif
  317. // Always clear on first render pass in mobile as it's same perf of DontCare and avoid tile clearing issues.
  318. if (Application.isMobilePlatform)
  319. return ClearFlag.All;
  320. if ((cameraClearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null) ||
  321. cameraClearFlags == CameraClearFlags.Nothing)
  322. return ClearFlag.Depth;
  323. return ClearFlag.All;
  324. }
  325. #endregion
  326. /// <summary>
  327. /// Returns a clear flag based on CameraClearFlags.
  328. /// </summary>
  329. /// <param name="cameraClearFlags">Camera clear flags.</param>
  330. /// <returns>A clear flag that tells if color and/or depth should be cleared.</returns>
  331. protected static ClearFlag GetCameraClearFlag(ref CameraData cameraData)
  332. {
  333. var cameraClearFlags = cameraData.camera.clearFlags;
  334. #if UNITY_EDITOR
  335. // We need public API to tell if FrameDebugger is active and enabled. In that case
  336. // we want to force a clear to see properly the drawcall stepping.
  337. // For now, to fix FrameDebugger in Editor, we force a clear.
  338. cameraClearFlags = CameraClearFlags.SolidColor;
  339. #endif
  340. // Universal RP doesn't support CameraClearFlags.DepthOnly and CameraClearFlags.Nothing.
  341. // CameraClearFlags.DepthOnly has the same effect of CameraClearFlags.SolidColor
  342. // CameraClearFlags.Nothing clears Depth on PC/Desktop and in mobile it clears both
  343. // depth and color.
  344. // CameraClearFlags.Skybox clears depth only.
  345. // Implementation details:
  346. // Camera clear flags are used to initialize the attachments on the first render pass.
  347. // ClearFlag is used together with Tile Load action to figure out how to clear the camera render target.
  348. // In Tile Based GPUs ClearFlag.Depth + RenderBufferLoadAction.DontCare becomes DontCare load action.
  349. // While ClearFlag.All + RenderBufferLoadAction.DontCare become Clear load action.
  350. // In mobile we force ClearFlag.All as DontCare doesn't have noticeable perf. difference from Clear
  351. // and this avoid tile clearing issue when not rendering all pixels in some GPUs.
  352. // In desktop/consoles there's actually performance difference between DontCare and Clear.
  353. // RenderBufferLoadAction.DontCare in PC/Desktop behaves as not clearing screen
  354. // RenderBufferLoadAction.DontCare in Vulkan/Metal behaves as DontCare load action
  355. // RenderBufferLoadAction.DontCare in GLES behaves as glInvalidateBuffer
  356. // Overlay cameras composite on top of previous ones. They don't clear color.
  357. // For overlay cameras we check if depth should be cleared on not.
  358. if (cameraData.renderType == CameraRenderType.Overlay)
  359. return (cameraData.clearDepth) ? ClearFlag.Depth : ClearFlag.None;
  360. // Always clear on first render pass in mobile as it's same perf of DontCare and avoid tile clearing issues.
  361. if (Application.isMobilePlatform)
  362. return ClearFlag.All;
  363. if ((cameraClearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null) ||
  364. cameraClearFlags == CameraClearFlags.Nothing)
  365. return ClearFlag.Depth;
  366. return ClearFlag.All;
  367. }
  368. // Initialize Camera Render State
  369. // Place all per-camera rendering logic that is generic for all types of renderers here.
  370. void SetCameraRenderState(CommandBuffer cmd, ref CameraData cameraData)
  371. {
  372. // Reset per-camera shader keywords. They are enabled depending on which render passes are executed.
  373. cmd.DisableShaderKeyword(ShaderKeywordStrings.MainLightShadows);
  374. cmd.DisableShaderKeyword(ShaderKeywordStrings.MainLightShadowCascades);
  375. cmd.DisableShaderKeyword(ShaderKeywordStrings.AdditionalLightsVertex);
  376. cmd.DisableShaderKeyword(ShaderKeywordStrings.AdditionalLightsPixel);
  377. cmd.DisableShaderKeyword(ShaderKeywordStrings.AdditionalLightShadows);
  378. cmd.DisableShaderKeyword(ShaderKeywordStrings.SoftShadows);
  379. cmd.DisableShaderKeyword(ShaderKeywordStrings.MixedLightingSubtractive);
  380. cmd.DisableShaderKeyword(ShaderKeywordStrings.LinearToSRGBConversion);
  381. }
  382. internal void Clear(CameraRenderType cameraType)
  383. {
  384. m_ActiveColorAttachments[0] = BuiltinRenderTextureType.CameraTarget;
  385. for (int i = 1; i < m_ActiveColorAttachments.Length; ++i)
  386. m_ActiveColorAttachments[i] = 0;
  387. m_ActiveDepthAttachment = BuiltinRenderTextureType.CameraTarget;
  388. m_InsideStereoRenderBlock = false;
  389. m_FirstTimeCameraColorTargetIsBound = cameraType == CameraRenderType.Base;
  390. m_FirstTimeCameraDepthTargetIsBound = true;
  391. m_ActiveRenderPassQueue.Clear();
  392. m_CameraColorTarget = BuiltinRenderTextureType.CameraTarget;
  393. m_CameraDepthTarget = BuiltinRenderTextureType.CameraTarget;
  394. }
  395. void ExecuteBlock(int blockIndex, NativeArray<int> blockRanges,
  396. ScriptableRenderContext context, ref RenderingData renderingData, int eyeIndex = 0, bool submit = false)
  397. {
  398. int endIndex = blockRanges[blockIndex + 1];
  399. for (int currIndex = blockRanges[blockIndex]; currIndex < endIndex; ++currIndex)
  400. {
  401. var renderPass = m_ActiveRenderPassQueue[currIndex];
  402. ExecuteRenderPass(context, renderPass, ref renderingData, eyeIndex);
  403. }
  404. if (submit)
  405. context.Submit();
  406. }
  407. void ExecuteRenderPass(ScriptableRenderContext context, ScriptableRenderPass renderPass, ref RenderingData renderingData, int eyeIndex)
  408. {
  409. ref CameraData cameraData = ref renderingData.cameraData;
  410. Camera camera = cameraData.camera;
  411. bool firstTimeStereo = false;
  412. CommandBuffer cmd = CommandBufferPool.Get(k_SetRenderTarget);
  413. renderPass.Configure(cmd, cameraData.cameraTargetDescriptor);
  414. renderPass.eyeIndex = eyeIndex;
  415. ClearFlag cameraClearFlag = GetCameraClearFlag(ref cameraData);
  416. // We use a different code path for MRT since it calls a different version of API SetRenderTarget
  417. if (RenderingUtils.IsMRT(renderPass.colorAttachments))
  418. {
  419. // In the MRT path we assume that all color attachments are REAL color attachments,
  420. // and that the depth attachment is a REAL depth attachment too.
  421. // Determine what attachments need to be cleared. ----------------
  422. bool needCustomCameraColorClear = false;
  423. bool needCustomCameraDepthClear = false;
  424. int cameraColorTargetIndex = RenderingUtils.IndexOf(renderPass.colorAttachments, m_CameraColorTarget);
  425. if (cameraColorTargetIndex != -1 && (m_FirstTimeCameraColorTargetIsBound || (cameraData.isXRMultipass && m_XRRenderTargetNeedsClear) ))
  426. {
  427. m_FirstTimeCameraColorTargetIsBound = false; // register that we did clear the camera target the first time it was bound
  428. firstTimeStereo = true;
  429. // Overlay cameras composite on top of previous ones. They don't clear.
  430. // MTT: Commented due to not implemented yet
  431. // if (renderingData.cameraData.renderType == CameraRenderType.Overlay)
  432. // clearFlag = ClearFlag.None;
  433. // We need to specifically clear the camera color target.
  434. // But there is still a chance we don't need to issue individual clear() on each render-targets if they all have the same clear parameters.
  435. needCustomCameraColorClear = (cameraClearFlag & ClearFlag.Color) != (renderPass.clearFlag & ClearFlag.Color)
  436. || CoreUtils.ConvertSRGBToActiveColorSpace(camera.backgroundColor) != renderPass.clearColor;
  437. if(cameraData.isXRMultipass && m_XRRenderTargetNeedsClear)
  438. // For multipass mode, if m_XRRenderTargetNeedsClear == true, then both color and depth buffer need clearing (not just color)
  439. needCustomCameraDepthClear = (cameraClearFlag & ClearFlag.Depth) != (renderPass.clearFlag & ClearFlag.Depth);
  440. m_XRRenderTargetNeedsClear = false; // register that the XR camera multi-pass target does not need clear any more (until next call to BeginXRRendering)
  441. }
  442. // Note: if we have to give up the assumption that no depthTarget can be included in the MRT colorAttachments, we might need something like this:
  443. // int cameraTargetDepthIndex = IndexOf(renderPass.colorAttachments, m_CameraDepthTarget);
  444. // if( !renderTargetAlreadySet && cameraTargetDepthIndex != -1 && m_FirstTimeCameraDepthTargetIsBound)
  445. // { ...
  446. // }
  447. if (renderPass.depthAttachment == m_CameraDepthTarget && m_FirstTimeCameraDepthTargetIsBound)
  448. // note: should be split m_XRRenderTargetNeedsClear into m_XRColorTargetNeedsClear and m_XRDepthTargetNeedsClear and use m_XRDepthTargetNeedsClear here?
  449. {
  450. m_FirstTimeCameraDepthTargetIsBound = false;
  451. //firstTimeStereo = true; // <- we do not call this here as the first render pass might be a shadow pass (non-stereo)
  452. needCustomCameraDepthClear = (cameraClearFlag & ClearFlag.Depth) != (renderPass.clearFlag & ClearFlag.Depth);
  453. //m_XRRenderTargetNeedsClear = false; // note: is it possible that XR camera multi-pass target gets clear first when bound as depth target?
  454. // in this case we might need need to register that it does not need clear any more (until next call to BeginXRRendering)
  455. }
  456. // Perform all clear operations needed. ----------------
  457. // We try to minimize calls to SetRenderTarget().
  458. // We get here only if cameraColorTarget needs to be handled separately from the rest of the color attachments.
  459. if (needCustomCameraColorClear)
  460. {
  461. // Clear camera color render-target separately from the rest of the render-targets.
  462. if ((cameraClearFlag & ClearFlag.Color) != 0)
  463. SetRenderTarget(cmd, renderPass.colorAttachments[cameraColorTargetIndex], renderPass.depthAttachment, ClearFlag.Color, CoreUtils.ConvertSRGBToActiveColorSpace(camera.backgroundColor));
  464. if ((renderPass.clearFlag & ClearFlag.Color) != 0)
  465. {
  466. uint otherTargetsCount = RenderingUtils.CountDistinct(renderPass.colorAttachments, m_CameraColorTarget);
  467. var nonCameraAttachments = m_TrimmedColorAttachmentCopies[otherTargetsCount];
  468. int writeIndex = 0;
  469. for (int readIndex = 0; readIndex < renderPass.colorAttachments.Length; ++readIndex)
  470. {
  471. if (renderPass.colorAttachments[readIndex] != m_CameraColorTarget && renderPass.colorAttachments[readIndex] != 0)
  472. {
  473. nonCameraAttachments[writeIndex] = renderPass.colorAttachments[readIndex];
  474. ++writeIndex;
  475. }
  476. }
  477. if (writeIndex != otherTargetsCount)
  478. Debug.LogError("writeIndex and otherTargetsCount values differed. writeIndex:" + writeIndex + " otherTargetsCount:" + otherTargetsCount);
  479. SetRenderTarget(cmd, nonCameraAttachments, m_CameraDepthTarget, ClearFlag.Color, renderPass.clearColor);
  480. }
  481. }
  482. // Bind all attachments, clear color only if there was no custom behaviour for cameraColorTarget, clear depth as needed.
  483. ClearFlag finalClearFlag = ClearFlag.None;
  484. finalClearFlag |= needCustomCameraDepthClear ? (cameraClearFlag & ClearFlag.Depth) : (renderPass.clearFlag & ClearFlag.Depth);
  485. finalClearFlag |= needCustomCameraColorClear ? 0 : (renderPass.clearFlag & ClearFlag.Color);
  486. // Only setup render target if current render pass attachments are different from the active ones.
  487. if (!RenderingUtils.SequenceEqual(renderPass.colorAttachments, m_ActiveColorAttachments) || renderPass.depthAttachment != m_ActiveDepthAttachment || finalClearFlag != ClearFlag.None)
  488. {
  489. int lastValidRTindex = RenderingUtils.LastValid(renderPass.colorAttachments);
  490. if (lastValidRTindex >= 0)
  491. {
  492. int rtCount = lastValidRTindex + 1;
  493. var trimmedAttachments = m_TrimmedColorAttachmentCopies[rtCount];
  494. for (int i = 0; i < rtCount; ++i)
  495. trimmedAttachments[i] = renderPass.colorAttachments[i];
  496. SetRenderTarget(cmd, trimmedAttachments, renderPass.depthAttachment, finalClearFlag, renderPass.clearColor);
  497. }
  498. }
  499. }
  500. else
  501. {
  502. // Currently in non-MRT case, color attachment can actually be a depth attachment.
  503. RenderTargetIdentifier passColorAttachment = renderPass.colorAttachment;
  504. RenderTargetIdentifier passDepthAttachment = renderPass.depthAttachment;
  505. // When render pass doesn't call ConfigureTarget we assume it's expected to render to camera target
  506. // which might be backbuffer or the framebuffer render textures.
  507. if (!renderPass.overrideCameraTarget)
  508. {
  509. passColorAttachment = m_CameraColorTarget;
  510. passDepthAttachment = m_CameraDepthTarget;
  511. }
  512. ClearFlag finalClearFlag = ClearFlag.None;
  513. Color finalClearColor;
  514. if (passColorAttachment == m_CameraColorTarget && (m_FirstTimeCameraColorTargetIsBound || (cameraData.isXRMultipass && m_XRRenderTargetNeedsClear)))
  515. {
  516. m_FirstTimeCameraColorTargetIsBound = false; // register that we did clear the camera target the first time it was bound
  517. finalClearFlag |= (cameraClearFlag & ClearFlag.Color);
  518. finalClearColor = CoreUtils.ConvertSRGBToActiveColorSpace(camera.backgroundColor);
  519. firstTimeStereo = true;
  520. if (m_FirstTimeCameraDepthTargetIsBound || (cameraData.isXRMultipass && m_XRRenderTargetNeedsClear))
  521. {
  522. // m_CameraColorTarget can be an opaque pointer to a RenderTexture with depth-surface.
  523. // We cannot infer this information here, so we must assume both camera color and depth are first-time bound here (this is the legacy behaviour).
  524. m_FirstTimeCameraDepthTargetIsBound = false;
  525. finalClearFlag |= (cameraClearFlag & ClearFlag.Depth);
  526. }
  527. m_XRRenderTargetNeedsClear = false; // register that the XR camera multi-pass target does not need clear any more (until next call to BeginXRRendering)
  528. }
  529. else
  530. {
  531. finalClearFlag |= (renderPass.clearFlag & ClearFlag.Color);
  532. finalClearColor = renderPass.clearColor;
  533. }
  534. // Condition (m_CameraDepthTarget!=BuiltinRenderTextureType.CameraTarget) below prevents m_FirstTimeCameraDepthTargetIsBound flag from being reset during non-camera passes (such as Color Grading LUT). This ensures that in those cases, cameraDepth will actually be cleared during the later camera pass.
  535. if ( (m_CameraDepthTarget!=BuiltinRenderTextureType.CameraTarget ) && (passDepthAttachment == m_CameraDepthTarget || passColorAttachment == m_CameraDepthTarget) && m_FirstTimeCameraDepthTargetIsBound )
  536. // note: should be split m_XRRenderTargetNeedsClear into m_XRColorTargetNeedsClear and m_XRDepthTargetNeedsClear and use m_XRDepthTargetNeedsClear here?
  537. {
  538. m_FirstTimeCameraDepthTargetIsBound = false;
  539. finalClearFlag |= (cameraClearFlag & ClearFlag.Depth);
  540. //firstTimeStereo = true; // <- we do not call this here as the first render pass might be a shadow pass (non-stereo)
  541. // finalClearFlag |= (cameraClearFlag & ClearFlag.Color); // <- m_CameraDepthTarget is never a color-surface, so no need to add this here.
  542. //m_XRRenderTargetNeedsClear = false; // note: is it possible that XR camera multi-pass target gets clear first when bound as depth target?
  543. // in this case we might need need to register that it does not need clear any more (until next call to BeginXRRendering)
  544. }
  545. else
  546. finalClearFlag |= (renderPass.clearFlag & ClearFlag.Depth);
  547. // Only setup render target if current render pass attachments are different from the active ones
  548. if (passColorAttachment != m_ActiveColorAttachments[0] || passDepthAttachment != m_ActiveDepthAttachment || finalClearFlag != ClearFlag.None)
  549. SetRenderTarget(cmd, passColorAttachment, passDepthAttachment, finalClearFlag, finalClearColor);
  550. }
  551. // We must execute the commands recorded at this point because potential call to context.StartMultiEye(cameraData.camera) below will alter internal renderer states
  552. // Also, we execute the commands recorded at this point to ensure SetRenderTarget is called before RenderPass.Execute
  553. context.ExecuteCommandBuffer(cmd);
  554. CommandBufferPool.Release(cmd);
  555. if (firstTimeStereo && cameraData.isStereoEnabled )
  556. {
  557. // The following call alters internal renderer states (we can think of some of the states as global states).
  558. // So any cmd recorded before must be executed before calling into that built-in call.
  559. context.StartMultiEye(camera, eyeIndex);
  560. XRUtils.DrawOcclusionMesh(cmd, camera);
  561. }
  562. renderPass.Execute(context, ref renderingData);
  563. }
  564. void BeginXRRendering(ScriptableRenderContext context, Camera camera, int eyeIndex)
  565. {
  566. context.StartMultiEye(camera, eyeIndex);
  567. m_InsideStereoRenderBlock = true;
  568. m_XRRenderTargetNeedsClear = true;
  569. }
  570. void EndXRRendering(ScriptableRenderContext context, in RenderingData renderingData, int eyeIndex)
  571. {
  572. Camera camera = renderingData.cameraData.camera;
  573. context.StopMultiEye(camera);
  574. bool isLastPass = renderingData.resolveFinalTarget && (eyeIndex == renderingData.cameraData.numberOfXRPasses - 1);
  575. context.StereoEndRender(camera, eyeIndex, isLastPass);
  576. m_InsideStereoRenderBlock = false;
  577. }
  578. internal static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorAttachment, RenderTargetIdentifier depthAttachment, ClearFlag clearFlag, Color clearColor)
  579. {
  580. m_ActiveColorAttachments[0] = colorAttachment;
  581. for (int i = 1; i < m_ActiveColorAttachments.Length; ++i)
  582. m_ActiveColorAttachments[i] = 0;
  583. m_ActiveDepthAttachment = depthAttachment;
  584. RenderBufferLoadAction colorLoadAction = ((uint)clearFlag & (uint)ClearFlag.Color) != 0 ?
  585. RenderBufferLoadAction.DontCare : RenderBufferLoadAction.Load;
  586. RenderBufferLoadAction depthLoadAction = ((uint)clearFlag & (uint)ClearFlag.Depth) != 0 ?
  587. RenderBufferLoadAction.DontCare : RenderBufferLoadAction.Load;
  588. TextureDimension dimension = (m_InsideStereoRenderBlock) ? XRGraphics.eyeTextureDesc.dimension : TextureDimension.Tex2D;
  589. SetRenderTarget(cmd, colorAttachment, colorLoadAction, RenderBufferStoreAction.Store,
  590. depthAttachment, depthLoadAction, RenderBufferStoreAction.Store, clearFlag, clearColor, dimension);
  591. }
  592. static void SetRenderTarget(
  593. CommandBuffer cmd,
  594. RenderTargetIdentifier colorAttachment,
  595. RenderBufferLoadAction colorLoadAction,
  596. RenderBufferStoreAction colorStoreAction,
  597. ClearFlag clearFlags,
  598. Color clearColor,
  599. TextureDimension dimension)
  600. {
  601. if (dimension == TextureDimension.Tex2DArray)
  602. CoreUtils.SetRenderTarget(cmd, colorAttachment, clearFlags, clearColor, 0, CubemapFace.Unknown, -1);
  603. else
  604. CoreUtils.SetRenderTarget(cmd, colorAttachment, colorLoadAction, colorStoreAction, clearFlags, clearColor);
  605. }
  606. static void SetRenderTarget(
  607. CommandBuffer cmd,
  608. RenderTargetIdentifier colorAttachment,
  609. RenderBufferLoadAction colorLoadAction,
  610. RenderBufferStoreAction colorStoreAction,
  611. RenderTargetIdentifier depthAttachment,
  612. RenderBufferLoadAction depthLoadAction,
  613. RenderBufferStoreAction depthStoreAction,
  614. ClearFlag clearFlags,
  615. Color clearColor,
  616. TextureDimension dimension)
  617. {
  618. if (depthAttachment == BuiltinRenderTextureType.CameraTarget)
  619. {
  620. SetRenderTarget(cmd, colorAttachment, colorLoadAction, colorStoreAction, clearFlags, clearColor,
  621. dimension);
  622. }
  623. else
  624. {
  625. if (dimension == TextureDimension.Tex2DArray)
  626. CoreUtils.SetRenderTarget(cmd, colorAttachment, depthAttachment,
  627. clearFlags, clearColor, 0, CubemapFace.Unknown, -1);
  628. else
  629. CoreUtils.SetRenderTarget(cmd, colorAttachment, colorLoadAction, colorStoreAction,
  630. depthAttachment, depthLoadAction, depthStoreAction, clearFlags, clearColor);
  631. }
  632. }
  633. static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorAttachments, RenderTargetIdentifier depthAttachment, ClearFlag clearFlag, Color clearColor)
  634. {
  635. m_ActiveColorAttachments = colorAttachments;
  636. m_ActiveDepthAttachment = depthAttachment;
  637. CoreUtils.SetRenderTarget(cmd, colorAttachments, depthAttachment, clearFlag, clearColor);
  638. }
  639. [Conditional("UNITY_EDITOR")]
  640. void DrawGizmos(ScriptableRenderContext context, Camera camera, GizmoSubset gizmoSubset)
  641. {
  642. #if UNITY_EDITOR
  643. if (UnityEditor.Handles.ShouldRenderGizmos())
  644. context.DrawGizmos(camera, gizmoSubset);
  645. #endif
  646. }
  647. // Fill in render pass indices for each block. End index is startIndex + 1.
  648. void FillBlockRanges(NativeArray<RenderPassEvent> blockEventLimits, NativeArray<int> blockRanges)
  649. {
  650. int currRangeIndex = 0;
  651. int currRenderPass = 0;
  652. blockRanges[currRangeIndex++] = 0;
  653. // For each block, it finds the first render pass index that has an event
  654. // higher than the block limit.
  655. for (int i = 0; i < blockEventLimits.Length - 1; ++i)
  656. {
  657. while (currRenderPass < m_ActiveRenderPassQueue.Count &&
  658. m_ActiveRenderPassQueue[currRenderPass].renderPassEvent < blockEventLimits[i])
  659. currRenderPass++;
  660. blockRanges[currRangeIndex++] = currRenderPass;
  661. }
  662. blockRanges[currRangeIndex] = m_ActiveRenderPassQueue.Count;
  663. }
  664. void InternalFinishRendering(ScriptableRenderContext context, bool resolveFinalTarget)
  665. {
  666. CommandBuffer cmd = CommandBufferPool.Get(k_ReleaseResourcesTag);
  667. for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
  668. m_ActiveRenderPassQueue[i].FrameCleanup(cmd);
  669. // Happens when rendering the last camera in the camera stack.
  670. if (resolveFinalTarget)
  671. {
  672. for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
  673. m_ActiveRenderPassQueue[i].OnFinishCameraStackRendering(cmd);
  674. FinishRendering(cmd);
  675. }
  676. context.ExecuteCommandBuffer(cmd);
  677. CommandBufferPool.Release(cmd);
  678. }
  679. internal static void SortStable(List<ScriptableRenderPass> list)
  680. {
  681. int j;
  682. for (int i = 1; i < list.Count; ++i)
  683. {
  684. ScriptableRenderPass curr = list[i];
  685. j = i - 1;
  686. for (; j >= 0 && curr < list[j]; --j)
  687. list[j + 1] = list[j];
  688. list[j + 1] = curr;
  689. }
  690. }
  691. }
  692. }