// Helper function to create a framebuffer from a renderpass and set of render targets private static Vk.Framebuffer CreateFramebuffer(Vk.RenderPass rp, List <RenderTarget> rts, Point size) { // Increment the ref count of the render targets as they are now part of a new framebuffer foreach (var rt in rts) { rt.IncRefCount(); } // Create the framebuffer var fbci = new Vk.FramebufferCreateInfo( rts.Select(rt => rt.VkView).ToArray(), size.X, size.Y, layers: 1 ); return(rp.CreateFramebuffer(fbci)); }
/// <summary> /// Creates a new render pipeline using the given description. /// </summary> /// <param name="desc">The pipeline description, which must be complete or an error will occur.</param> /// <param name="name">An optional name for the pipeline for debug purposes.</param> public Pipeline(PipelineDescription desc, string name = null) { if (desc == null) { throw new ArgumentNullException(nameof(desc)); } if (!desc.HasTargets) // Also checked by IsComplete, but this is used to give a more helpful error message { throw new InvalidOperationException("Cannot create a pipeline without any render targets."); } if (!desc.IsComplete) { throw new InvalidOperationException("Cannot create a pipeline from an incomplete description."); } Name = name; // Feature checking if ((desc.RasterizerState.Value.FillMode != FillMode.Solid) && !Device.Features.FillModeNonSolid) { throw new InvalidOperationException("Pipeline cannot be created with non-solid fill modes if that feature is not enabled."); } if (desc.RasterizerState.Value.LineWidth.HasValue && (desc.RasterizerState.Value.LineWidth.Value != 1) && !Device.Features.WideLines) { throw new InvalidOperationException("Pipeline cannot be created with wide lines if that feature is not enabled."); } if (desc.RasterizerState.Value.DepthClampEnable && !Device.Features.DepthClamp) { throw new InvalidOperationException("Pipeline cannot be created with depth clamping if that feature is not enabled."); } // Compatibility checking if ((desc._dssCI.Value.DepthTestEnable || desc._dssCI.Value.DepthWriteEnable) && !desc._depthAI.HasValue) { throw new InvalidOperationException("Pipelines with depth operations enabled must be given a depth buffer."); } if (!desc.CheckRenderTargetSizes()) { throw new InvalidOperationException("Pipeline render targets must all be the same size."); } // Create the renderpass, framebuffer, and layout VkRenderPass = CreateRenderPass(Device.VkDevice, desc, _renderTargets); VkFramebuffer = CreateFramebuffer(VkRenderPass, _renderTargets, desc.TargetSize); VkLayout = CreateLayout(Device.VkDevice); // Non-user-specified create infos var vsci = new Vk.PipelineViewportStateCreateInfo( DefaultViewport = desc.DefaultViewport.Value.ToVulkanNative(), DefaultScissor = desc.DefaultScissor.Value.ToVulkanNative() ); var mssci = new Vk.PipelineMultisampleStateCreateInfo(Vk.SampleCounts.Count1); // TODO: derive this from the framebuffer once we support multisampling // Pipeline creation var gpci = new Vk.GraphicsPipelineCreateInfo( VkLayout, VkRenderPass, 0, desc._shaderCIs, desc._piCI.Value, desc._vdCI.Value, desc._rsCI.Value, tessellationState: null, // TODO: control this once we support tessellation shaders viewportState: vsci, multisampleState: mssci, depthStencilState: desc._dssCI.Value, colorBlendState: desc._cbsCI.Value, dynamicState: DEFAULT_DYNAMIC_STATE, flags: Vk.PipelineCreateFlags.None, // TODO: look into derivative pipelines basePipelineHandle: null, // TODO: look into derivative pipelines basePipelineIndex: -1 // TODO: look into derivative pipelines ); VkPipeline = Device.VkDevice.CreateGraphicsPipeline(gpci, null, null); }