Example #1
0
        public VkPipeline GetGraphicsPipeline(ref VkPipelineCacheKey cacheKey)
        {
            if (!_pipelines.TryGetValue(cacheKey, out VkPipeline ret))
            {
                ret = CreateNewGraphicsPipeline(ref cacheKey);
                _pipelines.Add(cacheKey, ret);
            }

            return(ret);
        }
        public VkPipeline GetGraphicsPipeline(ref VkPipelineCacheKey cacheKey)
        {
            if (!_pipelines.TryGetValue(cacheKey, out VkPipeline ret))
            {
                ret = CreateNewGraphicsPipeline(ref cacheKey);

                // Very efficient
                cacheKey.VertexBindings = (VertexBuffer[])cacheKey.VertexBindings.Clone();
                _pipelines.Add(cacheKey, ret);
            }

            return(ret);
        }
        private void DrawPrimitives(int indexCount, int instanceCount, int startingIndex, int startingVertex)
        {
            RenderPassInfo     renderPassState  = GetCurrentRenderPass();
            VkPipelineLayout   layout           = ShaderResourceBindingSlots.PipelineLayout;
            VkPipelineCacheKey pipelineCacheKey = new VkPipelineCacheKey();

            pipelineCacheKey.RenderPass        = renderPassState.Framebuffer.RenderPassClearBuffer;
            pipelineCacheKey.PipelineLayout    = layout;
            pipelineCacheKey.BlendState        = (VkBlendState)BlendState;
            pipelineCacheKey.Framebuffer       = renderPassState.Framebuffer;
            pipelineCacheKey.DepthStencilState = (VkDepthStencilState)DepthStencilState;
            pipelineCacheKey.RasterizerState   = (VkRasterizerState)RasterizerState;
            pipelineCacheKey.PrimitiveTopology = _primitiveTopology;
            pipelineCacheKey.ShaderSet         = ShaderSet;
            pipelineCacheKey.VertexBindings    = VertexBuffers;
            VkPipeline graphicsPipeline = _resourceCache.GetGraphicsPipeline(ref pipelineCacheKey);

            VkDescriptorSetCacheKey descriptorSetCacheKey = new VkDescriptorSetCacheKey();

            descriptorSetCacheKey.ShaderResourceBindingSlots = ShaderResourceBindingSlots;
            descriptorSetCacheKey.ConstantBuffers            = _constantBuffers;
            descriptorSetCacheKey.TextureBindings            = _textureBindings;
            descriptorSetCacheKey.SamplerStates = _samplerStates;
            VkDescriptorSet descriptorSet = _resourceCache.GetDescriptorSet(ref descriptorSetCacheKey);

            VkCommandBuffer          cb        = GetCommandBuffer();
            VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New();

            beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit | VkCommandBufferUsageFlags.RenderPassContinue;
            VkCommandBufferInheritanceInfo inheritanceInfo = VkCommandBufferInheritanceInfo.New();

            inheritanceInfo.renderPass = renderPassState.Framebuffer.RenderPassClearBuffer;
            beginInfo.pInheritanceInfo = &inheritanceInfo;
            vkBeginCommandBuffer(cb, ref beginInfo);

            vkCmdBindPipeline(cb, VkPipelineBindPoint.Graphics, graphicsPipeline);
            vkCmdBindDescriptorSets(
                cb,
                VkPipelineBindPoint.Graphics,
                layout,
                0,
                1,
                ref descriptorSet,
                0,
                IntPtr.Zero);

            int vbCount = ShaderSet.InputLayout.InputDescriptions.Length;
            StackList <VkBuffer, Size512Bytes> vbs = new StackList <VkBuffer, Size512Bytes>();

            for (int vbIndex = 0; vbIndex < vbCount; vbIndex++)
            {
                vbs.Add(((VkVertexBuffer)VertexBuffers[vbIndex]).DeviceBuffer);
            }

            StackList <VkBuffer, Size512Bytes> offsets = new StackList <VkBuffer, Size512Bytes>();

            vkCmdBindVertexBuffers(cb, 0, vbs.Count, (IntPtr)vbs.Data, (IntPtr)offsets.Data);
            vkCmdBindIndexBuffer(cb, IndexBuffer.DeviceBuffer, 0, IndexBuffer.IndexType);
            VkViewport viewport = new VkViewport()
            {
                x        = Viewport.X,
                y        = Viewport.Y,
                width    = Viewport.Width,
                height   = Viewport.Height,
                minDepth = 0,
                maxDepth = 1
            };

            vkCmdSetViewport(cb, 0, 1, ref viewport);
            vkCmdSetScissor(cb, 0, 1, ref _scissorRect);
            vkCmdDrawIndexed(cb, (uint)indexCount, (uint)instanceCount, (uint)startingIndex, startingVertex, 0);
            vkEndCommandBuffer(cb);

            renderPassState.SecondaryCommandBuffers.Add(cb);
        }
        private VkPipeline CreateNewGraphicsPipeline(ref VkPipelineCacheKey cacheKey)
        {
            VkGraphicsPipelineCreateInfo pipelineCI = VkGraphicsPipelineCreateInfo.New();

            // RenderPass
            pipelineCI.renderPass = cacheKey.RenderPass;
            pipelineCI.subpass    = 0;

            pipelineCI.layout = cacheKey.PipelineLayout;

            // DynamicState
            VkPipelineDynamicStateCreateInfo dynamicStateCI = VkPipelineDynamicStateCreateInfo.New();
            VkDynamicState *dynamicStates = stackalloc VkDynamicState[2];

            dynamicStates[0] = VkDynamicState.Viewport;
            dynamicStates[1] = VkDynamicState.Scissor;
            dynamicStateCI.dynamicStateCount = 2;
            dynamicStateCI.pDynamicStates    = dynamicStates;
            pipelineCI.pDynamicState         = &dynamicStateCI;

            // ColorBlendState
            VkPipelineColorBlendAttachmentState colorBlendAttachementState = new VkPipelineColorBlendAttachmentState();

            colorBlendAttachementState.colorWriteMask      = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A;
            colorBlendAttachementState.blendEnable         = cacheKey.BlendState.IsBlendEnabled;
            colorBlendAttachementState.srcColorBlendFactor = VkFormats.VeldridToVkBlendFactor(cacheKey.BlendState.SourceColorBlend);
            colorBlendAttachementState.dstColorBlendFactor = VkFormats.VeldridToVkBlendFactor(cacheKey.BlendState.DestinationColorBlend);
            colorBlendAttachementState.colorBlendOp        = VkFormats.VeldridToVkBlendOp(cacheKey.BlendState.ColorBlendFunction);
            colorBlendAttachementState.srcAlphaBlendFactor = VkFormats.VeldridToVkBlendFactor(cacheKey.BlendState.SourceAlphaBlend);
            colorBlendAttachementState.dstAlphaBlendFactor = VkFormats.VeldridToVkBlendFactor(cacheKey.BlendState.DestinationAlphaBlend);
            colorBlendAttachementState.alphaBlendOp        = VkFormats.VeldridToVkBlendOp(cacheKey.BlendState.AlphaBlendFunction);

            VkPipelineColorBlendStateCreateInfo colorBlendStateCI = VkPipelineColorBlendStateCreateInfo.New();

            if (cacheKey.Framebuffer.ColorTexture != null)
            {
                colorBlendStateCI.attachmentCount  = 1;
                colorBlendStateCI.pAttachments     = &colorBlendAttachementState;
                colorBlendStateCI.blendConstants_0 = cacheKey.BlendState.BlendFactor.R;
                colorBlendStateCI.blendConstants_1 = cacheKey.BlendState.BlendFactor.G;
                colorBlendStateCI.blendConstants_2 = cacheKey.BlendState.BlendFactor.B;
                colorBlendStateCI.blendConstants_3 = cacheKey.BlendState.BlendFactor.A;
                pipelineCI.pColorBlendState        = &colorBlendStateCI;
            }

            // DepthStencilState
            VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = VkPipelineDepthStencilStateCreateInfo.New();

            depthStencilStateCI.depthCompareOp   = VkFormats.VeldridToVkDepthComparison(cacheKey.DepthStencilState.DepthComparison);
            depthStencilStateCI.depthWriteEnable = cacheKey.DepthStencilState.IsDepthWriteEnabled;
            depthStencilStateCI.depthTestEnable  = cacheKey.DepthStencilState.IsDepthEnabled;
            pipelineCI.pDepthStencilState        = &depthStencilStateCI;

            // MultisampleState
            VkPipelineMultisampleStateCreateInfo multisampleStateCI = VkPipelineMultisampleStateCreateInfo.New();

            multisampleStateCI.rasterizationSamples = VkSampleCountFlags.Count1;
            pipelineCI.pMultisampleState            = &multisampleStateCI;

            // RasterizationState
            VkPipelineRasterizationStateCreateInfo rasterizationStateCI = ((VkRasterizerState)cacheKey.RasterizerState).RasterizerStateCreateInfo;

            rasterizationStateCI.lineWidth = 1f;
            pipelineCI.pRasterizationState = &rasterizationStateCI;

            // ViewportState
            VkPipelineViewportStateCreateInfo viewportStateCI = VkPipelineViewportStateCreateInfo.New();

            viewportStateCI.viewportCount = 1;
            viewportStateCI.scissorCount  = 1;
            pipelineCI.pViewportState     = &viewportStateCI;

            // InputAssemblyState
            VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = VkPipelineInputAssemblyStateCreateInfo.New();

            inputAssemblyStateCI.topology  = cacheKey.PrimitiveTopology;
            pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;

            // VertexInputState
            VkPipelineVertexInputStateCreateInfo vertexInputStateCI = VkPipelineVertexInputStateCreateInfo.New();

            VertexInputDescription[] inputDescriptions = cacheKey.ShaderSet.InputLayout.InputDescriptions;
            uint bindingCount   = (uint)inputDescriptions.Length;
            uint attributeCount = (uint)inputDescriptions.Sum(desc => desc.Elements.Length);
            VkVertexInputBindingDescription *  bindingDescs   = stackalloc VkVertexInputBindingDescription[(int)bindingCount];
            VkVertexInputAttributeDescription *attributeDescs = stackalloc VkVertexInputAttributeDescription[(int)attributeCount];

            int targetIndex    = 0;
            int targetLocation = 0;

            for (int binding = 0; binding < inputDescriptions.Length; binding++)
            {
                VertexInputDescription inputDesc = inputDescriptions[binding];
                bindingDescs[targetIndex] = new VkVertexInputBindingDescription()
                {
                    binding   = (uint)binding,
                    inputRate = (inputDesc.Elements[0].StorageClassifier == VertexElementInputClass.PerInstance) ? VkVertexInputRate.Instance : VkVertexInputRate.Vertex,
                    stride    = ((VkVertexBuffer)cacheKey.VertexBindings[binding]).Stride
                };

                uint currentOffset = 0;
                for (int location = 0; location < inputDesc.Elements.Length; location++)
                {
                    VertexInputElement inputElement = inputDesc.Elements[location];

                    attributeDescs[targetIndex] = new VkVertexInputAttributeDescription()
                    {
                        format   = VkFormats.VeldridToVkVertexElementFormat(inputElement.ElementFormat),
                        binding  = (uint)binding,
                        location = (uint)(targetLocation + location),
                        offset   = currentOffset
                    };

                    targetIndex   += 1;
                    currentOffset += inputElement.SizeInBytes;
                }

                targetLocation += inputDesc.Elements.Length;
            }

            vertexInputStateCI.vertexBindingDescriptionCount   = bindingCount;
            vertexInputStateCI.pVertexBindingDescriptions      = bindingDescs;
            vertexInputStateCI.vertexAttributeDescriptionCount = attributeCount;
            vertexInputStateCI.pVertexAttributeDescriptions    = attributeDescs;
            pipelineCI.pVertexInputState = &vertexInputStateCI;

            // ShaderStage
            StackList <VkPipelineShaderStageCreateInfo> shaderStageCIs = new StackList <VkPipelineShaderStageCreateInfo>();

            VkPipelineShaderStageCreateInfo vertexStage = VkPipelineShaderStageCreateInfo.New();

            vertexStage.stage  = VkShaderStageFlags.Vertex;
            vertexStage.module = cacheKey.ShaderSet.VertexShader.ShaderModule;
            vertexStage.pName  = CommonStrings.main;
            shaderStageCIs.Add(vertexStage);

            VkPipelineShaderStageCreateInfo fragmentStage = VkPipelineShaderStageCreateInfo.New();

            fragmentStage.stage  = VkShaderStageFlags.Fragment;
            fragmentStage.module = cacheKey.ShaderSet.FragmentShader.ShaderModule;
            fragmentStage.pName  = CommonStrings.main;
            shaderStageCIs.Add(fragmentStage);

            if (cacheKey.ShaderSet.TessellationControlShader != null)
            {
                VkPipelineShaderStageCreateInfo tcStage = VkPipelineShaderStageCreateInfo.New();
                tcStage.stage  = VkShaderStageFlags.TessellationControl;
                tcStage.module = cacheKey.ShaderSet.TessellationControlShader.ShaderModule;
                tcStage.pName  = CommonStrings.main;
                shaderStageCIs.Add(tcStage);
            }

            if (cacheKey.ShaderSet.TessellationEvaluationShader != null)
            {
                VkPipelineShaderStageCreateInfo teStage = VkPipelineShaderStageCreateInfo.New();
                teStage.stage  = VkShaderStageFlags.TessellationEvaluation;
                teStage.module = cacheKey.ShaderSet.TessellationEvaluationShader.ShaderModule;
                teStage.pName  = CommonStrings.main;
                shaderStageCIs.Add(teStage);
            }

            if (cacheKey.ShaderSet.GeometryShader != null)
            {
                VkPipelineShaderStageCreateInfo geometryStage = VkPipelineShaderStageCreateInfo.New();
                geometryStage.stage  = VkShaderStageFlags.Geometry;
                geometryStage.module = cacheKey.ShaderSet.GeometryShader.ShaderModule;
                geometryStage.pName  = CommonStrings.main;
                shaderStageCIs.Add(geometryStage);
            }

            pipelineCI.stageCount = shaderStageCIs.Count;
            pipelineCI.pStages    = (VkPipelineShaderStageCreateInfo *)shaderStageCIs.Data;

            VkResult result = vkCreateGraphicsPipelines(_device, VkPipelineCache.Null, 1, ref pipelineCI, null, out VkPipeline ret);

            CheckResult(result);
            return(ret);
        }