/// <summary>
        /// Function to return the dispatch call.
        /// </summary>
        /// <param name="allocator">The allocator used to create an instance of the object</param>
        /// <returns>The dispatch call created or updated by this builder.</returns>
        /// <exception cref="GorgonException">Thrown if a <see cref="GorgonComputeShader"/> is not assigned to the <see cref="GorgonComputeShader"/> property with the <see cref="ComputeShader"/> command.</exception>
        /// <remarks>
        /// <para>
        /// Using an <paramref name="allocator"/> can provide different strategies when building dispatch calls.  If omitted, the dispatch call will be created using the standard <see langword="new"/> keyword.
        /// </para>
        /// <para>
        /// A custom allocator can be beneficial because it allows us to use a pool for allocating the objects, and thus allows for recycling of objects. This keeps the garbage collector happy by keeping objects
        /// around for as long as we need them, instead of creating objects that can potentially end up in the large object heap or in Gen 2.
        /// </para>
        /// <para>
        /// A dispatch call requires that at least a vertex shader be bound. If none is present, then the method will throw an exception.
        /// </para>
        /// </remarks>
        public GorgonDispatchCall Build(GorgonRingPool <GorgonDispatchCall> allocator)
        {
            var final = new GorgonDispatchCall();

            final.Setup();

            // Copy over the available constants.
            StateCopy.CopyConstantBuffers(final.D3DState.CsConstantBuffers, _worker.D3DState.CsConstantBuffers, 0);

            // Copy over samplers.
            StateCopy.CopySamplers(final.D3DState.CsSamplers, _worker.D3DState.CsSamplers, 0);

            // Copy over shader resource views.
            (int _, int _) = _worker.D3DState.CsSrvs.GetDirtyItems();

            StateCopy.CopySrvs(final.D3DState.CsSrvs, _worker.D3DState.CsSrvs);

            // Copy over unordered access views.
            StateCopy.CopyReadWriteViews(final.D3DState.CsReadWriteViews, _worker.D3DState.CsReadWriteViews, 0);

            if (_worker.D3DState.ComputeShader == null)
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_ERR_NO_COMPUTE_SHADER);
            }

            final.D3DState.ComputeShader = _worker.D3DState.ComputeShader;

            return(final);
        }
        /// <summary>
        /// Function to assign the list of shader resource views to the draw call.
        /// </summary>
        /// <param name="shaderType">The shader stage to use.</param>
        /// <param name="resourceViews">The shader resource views to copy.</param>
        /// <param name="startSlot">[Optional] The starting slot to use when copying the list.</param>
        /// <returns>The fluent builder interface .</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="startSlot"/> is less than 0, or greater than/equal to <see cref="GorgonShaderResourceViews.MaximumShaderResourceViewCount"/>.</exception>
        /// <exception cref="NotSupportedException">Thrown if the <paramref name="shaderType"/> is not valid.</exception>
        /// <remarks>
        /// <para>
        /// <see cref="ShaderType.Compute"/> shaders are not supported in this method will throw an exception.
        /// </para>
        /// </remarks>
        public TB ShaderResources(ShaderType shaderType, IReadOnlyList <GorgonShaderResourceView> resourceViews, int startSlot = 0)
        {
            if ((startSlot < 0) || (startSlot >= GorgonShaderResourceViews.MaximumShaderResourceViewCount))
            {
                throw new ArgumentOutOfRangeException(nameof(startSlot), string.Format(Resources.GORGFX_ERR_SRV_SLOT_INVALID, GorgonShaderResourceViews.MaximumShaderResourceViewCount));
            }

            switch (shaderType)
            {
            case ShaderType.Pixel:
                StateCopy.CopySrvs(DrawCall.D3DState.PsSrvs, resourceViews, startSlot);
                break;

            case ShaderType.Vertex:
                StateCopy.CopySrvs(DrawCall.D3DState.VsSrvs, resourceViews, startSlot);
                break;

            case ShaderType.Geometry:
                StateCopy.CopySrvs(DrawCall.D3DState.GsSrvs, resourceViews, startSlot);
                break;

            case ShaderType.Domain:
                StateCopy.CopySrvs(DrawCall.D3DState.DsSrvs, resourceViews, startSlot);
                break;

            case ShaderType.Hull:
                StateCopy.CopySrvs(DrawCall.D3DState.HsSrvs, resourceViews, startSlot);
                break;

            default:
                throw new NotSupportedException(string.Format(Resources.GORGFX_ERR_SHADER_UNKNOWN_TYPE, shaderType));
            }

            return((TB)this);
        }
        /// <summary>
        /// Function to assign a list of samplers to a shader on the pipeline.
        /// </summary>
        /// <param name="shaderType">The type of shader to update.</param>
        /// <param name="samplers">The samplers to assign.</param>
        /// <param name="index">[Optional] The index to use when copying the list.</param>
        /// <returns>The fluent interface for this builder.</returns>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="index"/> parameter is less than 0, or greater than/equal to <see cref="GorgonSamplerStates.MaximumSamplerStateCount"/>.</exception>
        /// <exception cref="NotSupportedException">Thrown if the <paramref name="shaderType"/> is not valid.</exception>
        /// <remarks>
        /// <para>
        /// <see cref="ShaderType.Compute"/> shaders are not supported in this method will throw an exception.
        /// </para>
        /// </remarks>
        public TB SamplerStates(ShaderType shaderType, IReadOnlyList <GorgonSamplerState> samplers, int index = 0)
        {
            if ((index < 0) || (index >= GorgonSamplerStates.MaximumSamplerStateCount))
            {
                throw new ArgumentOutOfRangeException(nameof(index), string.Format(Resources.GORGFX_ERR_INVALID_SAMPLER_INDEX, GorgonSamplerStates.MaximumSamplerStateCount));
            }

            switch (shaderType)
            {
            case ShaderType.Pixel:
                StateCopy.CopySamplers(DrawCall.D3DState.PsSamplers, samplers, index);
                break;

            case ShaderType.Vertex:
                StateCopy.CopySamplers(DrawCall.D3DState.VsSamplers, samplers, index);
                break;

            case ShaderType.Geometry:
                StateCopy.CopySamplers(DrawCall.D3DState.GsSamplers, samplers, index);
                break;

            case ShaderType.Domain:
                StateCopy.CopySamplers(DrawCall.D3DState.DsSamplers, samplers, index);
                break;

            case ShaderType.Hull:
                StateCopy.CopySamplers(DrawCall.D3DState.VsSamplers, samplers, index);
                break;

            default:
                throw new NotSupportedException(string.Format(Resources.GORGFX_ERR_SHADER_UNKNOWN_TYPE, shaderType));
            }

            return((TB)this);
        }
        /// <summary>
        /// Function to assign the list of read/write (unordered access) views to the draw call.
        /// </summary>
        /// <param name="resourceViews">The shader resource views to copy.</param>
        /// <param name="startSlot">[Optional] The starting slot to use when copying the list.</param>
        /// <returns>The fluent builder interface .</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="startSlot"/> is less than 0, or greater than/equal to <see cref="GorgonShaderResourceViews.MaximumShaderResourceViewCount"/>.</exception>
        public TB ReadWriteViews(IReadOnlyList <GorgonReadWriteViewBinding> resourceViews, int startSlot = 0)
        {
            if ((startSlot < 0) || (startSlot >= GorgonShaderResourceViews.MaximumShaderResourceViewCount))
            {
                throw new ArgumentOutOfRangeException(nameof(startSlot), string.Format(Resources.GORGFX_ERR_SRV_SLOT_INVALID, GorgonShaderResourceViews.MaximumShaderResourceViewCount));
            }

            StateCopy.CopyReadWriteViews(DrawCall.D3DState.ReadWriteViews, resourceViews, startSlot);
            return((TB)this);
        }
        /// <summary>
        /// Function to assign a list of samplers to a compute shader on the pipeline.
        /// </summary>
        /// <param name="samplers">The samplers to assign.</param>
        /// <param name="index">[Optional] The starting index to use when copying the list.</param>
        /// <returns>The fluent interface for this builder.</returns>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="index"/> parameter is less than 0, or greater than/equal to <see cref="GorgonSamplerStates.MaximumSamplerStateCount"/>.</exception>
        public GorgonDispatchCallBuilder SamplerStates(IReadOnlyList <GorgonSamplerState> samplers, int index = 0)
        {
            if ((index < 0) || (index >= GorgonSamplerStates.MaximumSamplerStateCount))
            {
                throw new ArgumentOutOfRangeException(nameof(index), string.Format(Resources.GORGFX_ERR_INVALID_SAMPLER_INDEX, GorgonSamplerStates.MaximumSamplerStateCount));
            }

            StateCopy.CopySamplers(_worker.D3DState.CsSamplers, samplers, index);
            return(this);
        }
        /// <summary>
        /// Function to assign the list of shader resource views to the dispatch call.
        /// </summary>
        /// <param name="resourceViews">The shader resource views to copy.</param>
        /// <param name="startSlot">[Optional] The starting slot to use when copying the list.</param>
        /// <returns>The fluent builder interface .</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="startSlot"/> is less than 0, or greater than/equal to <see cref="GorgonShaderResourceViews.MaximumShaderResourceViewCount"/>.</exception>
        public GorgonDispatchCallBuilder ShaderResources(IReadOnlyList <GorgonShaderResourceView> resourceViews, int startSlot = 0)
        {
            if ((startSlot < 0) || (startSlot >= GorgonShaderResourceViews.MaximumShaderResourceViewCount))
            {
                throw new ArgumentOutOfRangeException(nameof(startSlot), string.Format(Resources.GORGFX_ERR_SRV_SLOT_INVALID, GorgonShaderResourceViews.MaximumShaderResourceViewCount));
            }

            StateCopy.CopySrvs(_worker.D3DState.CsSrvs, resourceViews, startSlot);
            return(this);
        }
        /// <summary>
        /// Function to set the constant buffers for a compute shader stage.
        /// </summary>
        /// <param name="constantBuffers">The constant buffers to copy.</param>
        /// <param name="startSlot">[Optional] The starting slot to use when copying the list.</param>
        /// <returns>The fluent builder interface.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="startSlot"/> is less than 0, or greater than/equal to <see cref="GorgonConstantBuffers.MaximumConstantBufferCount"/>.</exception>
        public GorgonDispatchCallBuilder ConstantBuffers(IReadOnlyList <GorgonConstantBufferView> constantBuffers, int startSlot = 0)
        {
            if ((startSlot < 0) || (startSlot >= GorgonConstantBuffers.MaximumConstantBufferCount))
            {
                throw new ArgumentOutOfRangeException(nameof(startSlot), string.Format(Resources.GORGFX_ERR_CBUFFER_SLOT_INVALID, GorgonConstantBuffers.MaximumConstantBufferCount));
            }

            StateCopy.CopyConstantBuffers(_worker.D3DState.CsConstantBuffers, constantBuffers, startSlot);
            return(this);
        }
        /// <summary>
        /// Function to assign a list of <see cref="GorgonBlendState"/> objects to the pipeline.
        /// </summary>
        /// <param name="states">The states to apply to the pipeline</param>
        /// <param name="startSlot">[Optional] The first slot to assign the states into.</param>
        /// <returns>The fluent builder interface.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="startSlot"/> is less than 0, or greater than/equal to 8.</exception>
        public GorgonPipelineStateBuilder BlendStates(IReadOnlyList <GorgonBlendState> states, int startSlot = 0)
        {
            if ((startSlot < 0) || (startSlot >= D3D11.OutputMergerStage.SimultaneousRenderTargetCount))
            {
                throw new ArgumentOutOfRangeException(nameof(startSlot), string.Format(Resources.GORGFX_ERR_BLEND_SLOT_INVALID, D3D11.OutputMergerStage.SimultaneousRenderTargetCount));
            }

            StateCopy.CopyBlendStates(_workState.RwBlendStates, states, startSlot);
            return(this);
        }
        /// <summary>
        /// Function to reset the builder to the specified draw call state.
        /// </summary>
        /// <param name="drawCall">[Optional] The specified draw call state to copy.</param>
        /// <returns>The fluent builder interface.</returns>
        public TB ResetTo(TDc drawCall = null)
        {
            if (drawCall == null)
            {
                return(Clear());
            }

            VertexBuffers(drawCall.InputLayout, drawCall.VertexBufferBindings);
            StreamOutBuffers(drawCall.StreamOutBufferBindings);

            // Copy over the available constants.
            ConstantBuffers(ShaderType.Pixel, drawCall.D3DState.PsConstantBuffers);
            ConstantBuffers(ShaderType.Vertex, drawCall.D3DState.VsConstantBuffers);
            ConstantBuffers(ShaderType.Geometry, drawCall.D3DState.GsConstantBuffers);
            ConstantBuffers(ShaderType.Domain, drawCall.D3DState.DsConstantBuffers);
            ConstantBuffers(ShaderType.Hull, drawCall.D3DState.HsConstantBuffers);

            SamplerStates(ShaderType.Pixel, drawCall.D3DState.PsSamplers);
            SamplerStates(ShaderType.Vertex, drawCall.D3DState.VsSamplers);
            SamplerStates(ShaderType.Geometry, drawCall.D3DState.GsSamplers);
            SamplerStates(ShaderType.Domain, drawCall.D3DState.DsSamplers);
            SamplerStates(ShaderType.Hull, drawCall.D3DState.HsSamplers);

            StateCopy.CopySrvs(DrawCall.D3DState.PsSrvs, drawCall.D3DState.PsSrvs);
            StateCopy.CopySrvs(DrawCall.D3DState.VsSrvs, drawCall.D3DState.VsSrvs);
            StateCopy.CopySrvs(DrawCall.D3DState.GsSrvs, drawCall.D3DState.GsSrvs);
            StateCopy.CopySrvs(DrawCall.D3DState.DsSrvs, drawCall.D3DState.DsSrvs);
            StateCopy.CopySrvs(DrawCall.D3DState.HsSrvs, drawCall.D3DState.HsSrvs);

            ReadWriteViews(drawCall.D3DState.ReadWriteViews);

            DrawCall.D3DState.PipelineState = new GorgonPipelineState(drawCall.PipelineState);
            // We need to copy the D3D states as well as they won't be updated unless we rebuild the pipeline state.
            DrawCall.D3DState.PipelineState.D3DBlendState        = drawCall.D3DState.PipelineState.D3DBlendState;
            DrawCall.D3DState.PipelineState.D3DRasterState       = drawCall.D3DState.PipelineState.D3DRasterState;
            DrawCall.D3DState.PipelineState.D3DDepthStencilState = drawCall.D3DState.PipelineState.D3DDepthStencilState;

            return(OnResetTo(drawCall));
        }
        /// <summary>
        /// Function to reset the pipeline state to the specified state passed in to the method.
        /// </summary>
        /// <param name="pipeState">The pipeline state to copy.</param>
        /// <returns>The fluent interface for the builder.</returns>
        public GorgonPipelineStateBuilder ResetTo(GorgonPipelineState pipeState)
        {
            if (pipeState == null)
            {
                Clear();
                return(this);
            }

            _workState.RasterState                  = pipeState.RasterState;
            _workState.DepthStencilState            = pipeState.DepthStencilState;
            _workState.PixelShader                  = pipeState.PixelShader;
            _workState.VertexShader                 = pipeState.VertexShader;
            _workState.GeometryShader               = pipeState.GeometryShader;
            _workState.DomainShader                 = pipeState.DomainShader;
            _workState.HullShader                   = pipeState.HullShader;
            _workState.PrimitiveType                = pipeState.PrimitiveType;
            _workState.IsIndependentBlendingEnabled = pipeState.IsIndependentBlendingEnabled;
            _workState.IsAlphaToCoverageEnabled     = pipeState.IsAlphaToCoverageEnabled;
            StateCopy.CopyBlendStates(_workState.RwBlendStates, pipeState.RwBlendStates, 0);

            return(this);
        }
        /// <summary>
        /// Function to return the draw call.
        /// </summary>
        /// <param name="allocator">The allocator used to create an instance of the object</param>
        /// <returns>The draw call created or updated by this builder.</returns>
        /// <exception cref="GorgonException">Thrown if a <see cref="GorgonVertexShader"/> is not assigned to the <see cref="GorgonPipelineState.VertexShader"/> property with the <see cref="PipelineState(GorgonPipelineStateBuilder)"/> command.</exception>
        /// <remarks>
        /// <para>
        /// Using an <paramref name="allocator"/> can provide different strategies when building draw calls.  If omitted, the draw call will be created using the standard <see langword="new"/> keyword.
        /// </para>
        /// <para>
        /// A custom allocator can be beneficial because it allows us to use a pool for allocating the objects, and thus allows for recycling of objects. This keeps the garbage collector happy by keeping objects
        /// around for as long as we need them, instead of creating objects that can potentially end up in the large object heap or in Gen 2.
        /// </para>
        /// <para>
        /// A draw call requires that at least a vertex shader be bound. If none is present, then the method will throw an exception.
        /// </para>
        /// </remarks>
        public TDc Build(GorgonDrawCallPoolAllocator <TDc> allocator)
        {
            TDc final = OnCreate(allocator);

            if ((allocator == null) ||
                (final.VertexShader.ConstantBuffers == null) ||
                (final.PixelShader.Samplers == null) ||
                (final.PixelShader.ShaderResources == null))
            {
                final.SetupConstantBuffers();
                final.SetupSamplers();
                final.SetupViews();
            }

            if (final.D3DState.VertexBuffers == null)
            {
                final.D3DState.VertexBuffers = new GorgonVertexBufferBindings();
            }

            if (final.D3DState.StreamOutBindings == null)
            {
                final.D3DState.StreamOutBindings = new GorgonStreamOutBindings();
            }

            StateCopy.CopyVertexBuffers(final.D3DState.VertexBuffers, DrawCall.VertexBufferBindings, DrawCall.InputLayout);
            StateCopy.CopyStreamOutBuffers(final.D3DState.StreamOutBindings, DrawCall.StreamOutBufferBindings);

            // Copy over the shader resources.
            if (DrawCall.D3DState.PipelineState?.PixelShader != null)
            {
                StateCopy.CopyConstantBuffers(final.D3DState.PsConstantBuffers, DrawCall.D3DState.PsConstantBuffers, 0);
                StateCopy.CopySamplers(final.D3DState.PsSamplers, DrawCall.D3DState.PsSamplers, 0);
                StateCopy.CopySrvs(final.D3DState.PsSrvs, DrawCall.D3DState.PsSrvs);
            }
            else
            {
                final.D3DState.PsConstantBuffers.Clear();
                final.D3DState.PsSamplers.Clear();
                final.D3DState.PsSrvs.Clear();
            }

            if (DrawCall.D3DState.PipelineState?.VertexShader != null)
            {
                StateCopy.CopyConstantBuffers(final.D3DState.VsConstantBuffers, DrawCall.D3DState.VsConstantBuffers, 0);
                StateCopy.CopySamplers(final.D3DState.VsSamplers, DrawCall.D3DState.VsSamplers, 0);
                StateCopy.CopySrvs(final.D3DState.VsSrvs, DrawCall.D3DState.VsSrvs);
            }
            else
            {
                final.D3DState.VsConstantBuffers.Clear();
                final.D3DState.VsSamplers.Clear();
                final.D3DState.VsSrvs.Clear();
            }

            if (DrawCall.D3DState.PipelineState?.GeometryShader != null)
            {
                StateCopy.CopyConstantBuffers(final.D3DState.GsConstantBuffers, DrawCall.D3DState.GsConstantBuffers, 0);
                StateCopy.CopySamplers(final.D3DState.GsSamplers, DrawCall.D3DState.GsSamplers, 0);
                StateCopy.CopySrvs(final.D3DState.GsSrvs, DrawCall.D3DState.GsSrvs);
            }
            else
            {
                final.D3DState.GsConstantBuffers.Clear();
                final.D3DState.GsSamplers.Clear();
                final.D3DState.GsSrvs.Clear();
            }

            if (DrawCall.D3DState.PipelineState?.DomainShader != null)
            {
                StateCopy.CopyConstantBuffers(final.D3DState.DsConstantBuffers, DrawCall.D3DState.DsConstantBuffers, 0);
                StateCopy.CopySamplers(final.D3DState.DsSamplers, DrawCall.D3DState.DsSamplers, 0);
                StateCopy.CopySrvs(final.D3DState.DsSrvs, DrawCall.D3DState.DsSrvs);
            }
            else
            {
                final.D3DState.DsConstantBuffers.Clear();
                final.D3DState.DsSamplers.Clear();
                final.D3DState.DsSrvs.Clear();
            }

            if (DrawCall.D3DState.PipelineState?.HullShader != null)
            {
                StateCopy.CopyConstantBuffers(final.D3DState.HsConstantBuffers, DrawCall.D3DState.HsConstantBuffers, 0);
                StateCopy.CopySamplers(final.D3DState.HsSamplers, DrawCall.D3DState.HsSamplers, 0);
                StateCopy.CopySrvs(final.D3DState.HsSrvs, DrawCall.D3DState.HsSrvs);
            }
            else
            {
                final.D3DState.HsConstantBuffers.Clear();
                final.D3DState.HsSamplers.Clear();
                final.D3DState.HsSrvs.Clear();
            }

            // Copy over unordered access views.
            StateCopy.CopyReadWriteViews(final.D3DState.ReadWriteViews, DrawCall.D3DState.ReadWriteViews, 0);

            final.D3DState.PipelineState = DrawCall.PipelineState;

            // Copy the cached states.
            final.PipelineState.D3DBlendState        = DrawCall.PipelineState.D3DBlendState;
            final.PipelineState.D3DDepthStencilState = DrawCall.PipelineState.D3DDepthStencilState;
            final.PipelineState.D3DRasterState       = DrawCall.PipelineState.D3DRasterState;

            OnUpdate(final);

            if (final.PipelineState.VertexShader == null)
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_ERR_NO_VERTEX_SHADER);
            }

            return(final);
        }
 /// <summary>
 /// Function to set the vertex buffer bindings for the draw call.
 /// </summary>
 /// <param name="layout">The input layout to use.</param>
 /// <param name="bindings">The vertex buffer bindings to set.</param>
 /// <returns>The fluent builder interface.</returns>
 /// <exception cref="ArgumentNullException">Thrown when the <paramref name="layout"/> parameter is <b>null</b>.</exception>
 public TB VertexBuffers(GorgonInputLayout layout, IReadOnlyList <GorgonVertexBufferBinding> bindings)
 {
     StateCopy.CopyVertexBuffers(DrawCall.D3DState.VertexBuffers, bindings, layout ?? throw new ArgumentNullException(nameof(layout)));
     return((TB)this);
 }