internal static VkPipeline CreatePipeline(PipelineDescription desc, Renderer renderer, uint subpass, out BuildStates buildState) { // Validate var rlayout = (renderer.MSAA != MSAA.X1) ? renderer.MSAALayout ! : renderer.Layout; if (!desc.IsComplete) { throw new InvalidOperationException("Cannot create a pipeline from an incomplete description"); } if (desc.Shader !.IsDisposed) { throw new ObjectDisposedException("desc.Shader", "Cannot build a pipeline with a disposed shader"); } var cacnt = rlayout.Subpasses[subpass].ColorCount; if (desc.AllColorBlends !.Length != 1 && (cacnt != desc.AllColorBlends.Length)) { throw new InvalidOperationException("Invalid color blend count for pipeline"); } var hasds = rlayout.Subpasses[subpass].DepthOffset.HasValue; if (!hasds && (desc.DepthStencil !.Value.DepthMode != DepthMode.None)) { throw new InvalidOperationException( "Cannot perform depth/stencil operations on non-depth/stencil subpass"); } if (desc.Shader !.CheckCompatiblity(desc, renderer, subpass) is string shaderErr) { throw new InvalidOperationException($"Invalid shader for pipeline - {shaderErr}"); } // Describe the color blends var cblends = (desc.AllColorBlends.Length != 1) ? desc.AllColorBlends ! : Enumerable.Repeat((ColorBlendState)desc.SharedColorBlend !, (int)cacnt).ToArray(); // Vertex info CalculateVertexInfo(desc.VertexDescriptions !, out var vertexAttrs, out var vertexBinds); // Create the build states buildState = new( cblends, desc.BlendConstants, (DepthStencilState)desc.DepthStencil !, (VertexInput)desc.VertexInput !, vertexBinds, vertexAttrs, (RasterizerState)desc.Rasterizer ! ); // Create the initial pipeline return(CreatePipeline(buildState, renderer, subpass, desc.Shader !.Layout, desc.Shader.Program)); }
/// <summary> /// Create a new pipeline with the given description, for use in the given renderer and subpass. /// </summary> /// <param name="description">The description of the pipeline states to build into the pipeline.</param> /// <param name="renderer">The renderer to use the pipeline in.</param> /// <param name="subpass">The subpass index within the renderer to use the pipeline in.</param> public Pipeline(PipelineDescription description, Renderer renderer, uint subpass) : base(ResourceType.Pipeline) { // Create the pipeline handle Handle = CreatePipeline(description, renderer, subpass, out var cache); if (renderer.MSAALayout is not null) { BuildCache = cache; // Only save cache if we might rebuild from MSAA change } // Assign fields Layout = description.Shader !.Layout; Layout.IncRefCount(); ShaderProgram = description.Shader.Program; ShaderProgram.IncRefCount(); Renderer = renderer; Subpass = subpass; // Assign values VertexBindingCount = (uint)cache.VertexBindings.Length; // Register to the renderer renderer.AddPipeline(this); }