using System; using System.Collections.Generic; using XCEngine; namespace XCEngine.Rendering { internal enum RenderGraphRasterPassExecutionKind { None = 0, ColorScaleFullscreen = 1, ShaderVectorFullscreen = 2 } public sealed class RenderGraphRasterPassBuilder { private readonly ScriptableRenderContext m_context; private readonly string m_passName; private readonly List m_readTextures = new List(); private readonly List m_colorAttachments = new List(); private RenderGraphTextureHandle m_sourceColorTexture; private Vector4 m_vectorPayload; private string m_shaderPath = string.Empty; private string m_shaderPassName = string.Empty; private RenderGraphRasterPassExecutionKind m_executionKind; private bool m_finalized; internal RenderGraphRasterPassBuilder( ScriptableRenderContext context, string passName) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (string.IsNullOrEmpty(passName)) { throw new ArgumentException( "Render graph raster pass name cannot be null or empty.", nameof(passName)); } m_context = context; m_passName = passName; } public RenderGraphRasterPassBuilder UseColorSource( RenderGraphTextureHandle texture) { m_sourceColorTexture = texture; return this; } public RenderGraphRasterPassBuilder UseTexture( RenderGraphTextureHandle texture) { if (texture.isValid) { m_readTextures.Add(texture); } return this; } public RenderGraphRasterPassBuilder SetColorAttachment( RenderGraphTextureHandle texture, int index = 0) { if (index < 0) { throw new ArgumentOutOfRangeException( nameof(index), "Render graph color attachment index cannot be negative."); } while (m_colorAttachments.Count <= index) { m_colorAttachments.Add(default); } m_colorAttachments[index] = texture; return this; } public RenderGraphRasterPassBuilder SetColorScaleFullscreenExecution( Vector4 colorScale) { m_executionKind = RenderGraphRasterPassExecutionKind .ColorScaleFullscreen; m_vectorPayload = colorScale; m_shaderPath = string.Empty; m_shaderPassName = string.Empty; return this; } public RenderGraphRasterPassBuilder SetShaderVectorFullscreenExecution( string shaderPath, Vector4 vectorPayload, string shaderPassName = null) { if (string.IsNullOrEmpty(shaderPath)) { throw new ArgumentException( "Fullscreen shader path cannot be null or empty.", nameof(shaderPath)); } m_executionKind = RenderGraphRasterPassExecutionKind .ShaderVectorFullscreen; m_vectorPayload = vectorPayload; m_shaderPath = shaderPath; m_shaderPassName = shaderPassName ?? string.Empty; return this; } public bool Commit() { if (m_finalized || !HasExecutionConfigured() || !HasAnyColorAttachment()) { return false; } m_finalized = true; ulong nativePassHandle = InternalCalls .Rendering_ScriptableRenderContext_BeginRasterPass( m_context.nativeHandle, m_passName); if (nativePassHandle == 0ul) { return false; } if (m_sourceColorTexture.isValid && !InternalCalls .Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture( m_context.nativeHandle, nativePassHandle, m_sourceColorTexture.nativeIndex)) { return false; } for (int i = 0; i < m_readTextures.Count; ++i) { RenderGraphTextureHandle readTexture = m_readTextures[i]; if (!readTexture.isValid) { continue; } if (!InternalCalls .Rendering_ScriptableRenderContext_AddRasterPassReadTexture( m_context.nativeHandle, nativePassHandle, readTexture.nativeIndex)) { return false; } } for (int i = 0; i < m_colorAttachments.Count; ++i) { RenderGraphTextureHandle colorAttachment = m_colorAttachments[i]; if (!colorAttachment.isValid) { continue; } if (!InternalCalls .Rendering_ScriptableRenderContext_SetRasterPassColorAttachment( m_context.nativeHandle, nativePassHandle, i, colorAttachment.nativeIndex)) { return false; } } bool configuredExecution; switch (m_executionKind) { case RenderGraphRasterPassExecutionKind .ColorScaleFullscreen: configuredExecution = InternalCalls .Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution( m_context.nativeHandle, nativePassHandle, ref m_vectorPayload); break; case RenderGraphRasterPassExecutionKind .ShaderVectorFullscreen: configuredExecution = InternalCalls .Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution( m_context.nativeHandle, nativePassHandle, m_shaderPath, m_shaderPassName, ref m_vectorPayload); break; default: configuredExecution = false; break; } return configuredExecution && InternalCalls .Rendering_ScriptableRenderContext_CommitRasterPass( m_context.nativeHandle, nativePassHandle); } private bool HasExecutionConfigured() { return m_executionKind != RenderGraphRasterPassExecutionKind.None; } private bool HasAnyColorAttachment() { for (int i = 0; i < m_colorAttachments.Count; ++i) { if (m_colorAttachments[i].isValid) { return true; } } return false; } } }