using System; using System.Diagnostics; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering { /// /// Render graph command buffer types inherit from this base class. /// It provides some shared functionality for all command buffer types. /// public class BaseCommandBuffer { /// /// The instance of Unity's CommandBuffer that this class encapsulates, providing access to lower-level rendering commands. /// protected internal CommandBuffer m_WrappedCommandBuffer; internal RenderGraphPass m_ExecutingPass; // Users cannot directly create command buffers. The rendergraph creates them and passes them to callbacks. internal BaseCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPass, bool isAsync) { m_WrappedCommandBuffer = wrapped; m_ExecutingPass = executingPass; if (isAsync) m_WrappedCommandBuffer.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute); } ///See (https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer-name.html) public string name => m_WrappedCommandBuffer.name; ///See (https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer-sizeInBytes.html) public int sizeInBytes => m_WrappedCommandBuffer.sizeInBytes; /// /// Checks if modifying the global state is permitted by the currently executing render graph pass. /// If such modifications are not allowed, an InvalidOperationException is thrown. /// /// /// Thrown if the current render graph pass does not permit modifications to global state. /// [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] protected internal void ThrowIfGlobalStateNotAllowed() { if (m_ExecutingPass != null && !m_ExecutingPass.allowGlobalState) throw new InvalidOperationException($"{m_ExecutingPass.name}: Modifying global state from this command buffer is not allowed. Please ensure your render graph pass allows modifying global state."); } /// /// Checks if the Raster Command Buffer has set a valid render target. /// /// Thrown if the there are no active render targets. [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] protected internal void ThrowIfRasterNotAllowed() { if (m_ExecutingPass != null && !m_ExecutingPass.HasRenderAttachments()) throw new InvalidOperationException($"{m_ExecutingPass.name}: Using raster commands from a pass with no active render targets is not allowed as it will use an undefined render target state. Please set-up the pass's render targets using SetRenderAttachments."); } /// /// Ensures that the texture handle being used is valid for the currently executing render graph pass. /// This includes checks to ensure that the texture handle is registered for read or write access /// and is not being used incorrectly as a render target attachment. /// /// The TextureHandle to validate for the current pass. /// /// Throws an exception if the texture handle is not properly registered for the pass or being used incorrectly. /// [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] protected internal void ValidateTextureHandle(TextureHandle h) { if(RenderGraph.enableValidityChecks) { if (m_ExecutingPass == null) return; if (h.IsBuiltin()) return; if (!m_ExecutingPass.IsRead(h.handle) && !m_ExecutingPass.IsWritten(h.handle)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to use a texture on the command buffer that was never registered with the pass builder. Please indicate the texture use to the pass builder."); } if (m_ExecutingPass.IsAttachment(h)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. "); } } } /// /// Validates that the specified texture handle is registered for read access within the context of the current executing render graph pass. /// Throws an exception if the texture is not registered for reading or is used incorrectly as a render target attachment. /// /// The TextureHandle to validate for read access. /// /// Throws an exception if the texture handle is either not registered as a readable resource or misused as both an attachment and a regular texture. /// [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] protected internal void ValidateTextureHandleRead(TextureHandle h) { if(RenderGraph.enableValidityChecks) { if (m_ExecutingPass == null) return; if (!m_ExecutingPass.IsRead(h.handle)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to read a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as read to the pass builder."); } if (m_ExecutingPass.IsAttachment(h)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. "); } } } /// /// Validates that the specified texture handle is registered for write access within the context of the current executing render graph pass. /// Additionally, it checks that built-in textures are not being written to, and that the texture is not incorrectly used as a render target attachment. /// An exception is thrown if any of these checks fail. /// /// The TextureHandle to validate for write access. /// /// Throws an exception if the texture handle is not registered for writing, attempts to write to a built-in texture, or is misused as both a writeable resource and a render target attachment. /// [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] protected internal void ValidateTextureHandleWrite(TextureHandle h) { if(RenderGraph.enableValidityChecks) { if (m_ExecutingPass == null) return; if (h.IsBuiltin()) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write to a built-in texture. This is not allowed built-in textures are small default resources like `white` or `black` that cannot be written to."); } if (!m_ExecutingPass.IsWritten(h.handle)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as written to the pass builder."); } if (m_ExecutingPass.IsAttachment(h)) { throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. "); } } } } }