Ejemplo n.º 1
0
        // Helper function to create a renderpass (and fill a list) from a set of render targets
        // The color attachments will always come first, in the order they are specified
        private static Vk.RenderPass CreateRenderPass(Vk.Device device, PipelineDescription desc, List <RenderTarget> rts)
        {
            // Fill the list
            rts.Clear();
            if (desc.HasColorTargets)
            {
                rts.AddRange(desc.ColorTargets);
            }
            if (desc.HasDepthTarget)
            {
                rts.Add(desc.DepthTarget);
            }

            // Collect the attachment descriptions and create the references
            Vk.AttachmentDescription[] atts  = new Vk.AttachmentDescription[desc.TargetCount];
            Vk.AttachmentReference[]   crefs = new Vk.AttachmentReference[desc.TargetCount - (desc.HasDepthTarget ? 1 : 0)];
            if (desc.HasColorTargets)
            {
                for (int i = 0; i < desc._colorAIs.Length; ++i)
                {
                    atts[i]  = desc._colorAIs[i];
                    crefs[i] = new Vk.AttachmentReference(i, desc.ColorTargets[i].DefaultImageLayout);
                }
            }
            if (desc.HasDepthTarget)
            {
                atts[atts.Length - 1] = desc._depthAI.Value;
            }

            // Specify the lone subpass
            Vk.SubpassDescription subpass = new Vk.SubpassDescription(
                colorAttachments: crefs,
                depthStencilAttachment: desc.HasDepthTarget ?
                new Vk.AttachmentReference(atts.Length - 1, desc.DepthTarget.DefaultImageLayout) : (Vk.AttachmentReference?)null
                );

            // Create the renderpass
            var rpci = new Vk.RenderPassCreateInfo(
                new[] { subpass },
                attachments: atts,
                dependencies: new[] {                 // Create a two dependencies so that the color and depth buffers do not overwrite each other
                // TODO: Validate the flags used in these
                new Vk.SubpassDependency(Vk.Constant.SubpassExternal, 0, Vk.PipelineStages.ColorAttachmentOutput,
                                         Vk.PipelineStages.ColorAttachmentOutput, Vk.Accesses.None, Vk.Accesses.ColorAttachmentRead,
                                         Vk.Dependencies.ByRegion),
                new Vk.SubpassDependency(Vk.Constant.SubpassExternal, 0, Vk.PipelineStages.LateFragmentTests,
                                         Vk.PipelineStages.EarlyFragmentTests, Vk.Accesses.None, Vk.Accesses.DepthStencilAttachmentRead,
                                         Vk.Dependencies.ByRegion)
            }
                );

            return(device.CreateRenderPass(rpci));
        }
Ejemplo n.º 2
0
        /// <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);
        }