public VkDescriptorSet GetDescriptorSet(ref VkDescriptorSetCacheKey cacheKey)
        {
            if (!_descriptorSets.TryGetValue(cacheKey, out VkDescriptorSet ret))
            {
                ret = CreateNewDescriptorSet(ref cacheKey);

                // Very efficient
                cacheKey.ConstantBuffers = (VkConstantBuffer[])cacheKey.ConstantBuffers.Clone();
                cacheKey.TextureBindings = (VkShaderTextureBinding[])cacheKey.TextureBindings.Clone();
                cacheKey.SamplerStates   = (VkSamplerState[])cacheKey.SamplerStates.Clone();
                _descriptorSets.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 VkDescriptorSet CreateNewDescriptorSet(ref VkDescriptorSetCacheKey cacheKey)
        {
            {
                VkDescriptorSetAllocateInfo descriptorSetAI = VkDescriptorSetAllocateInfo.New();
                descriptorSetAI.descriptorPool     = _descriptorPool;
                descriptorSetAI.descriptorSetCount = 1;
                VkDescriptorSetLayout layout = cacheKey.ShaderResourceBindingSlots.DescriptorSetLayout;
                descriptorSetAI.pSetLayouts = &layout;
                VkResult result = vkAllocateDescriptorSets(_device, ref descriptorSetAI, out VkDescriptorSet descriptorSet);
                CheckResult(result);

                int resourceCount = cacheKey.ShaderResourceBindingSlots.Resources.Length;
                VkWriteDescriptorSet[]  descriptorWrites = new VkWriteDescriptorSet[resourceCount];
                VkDescriptorBufferInfo *bufferInfos      = stackalloc VkDescriptorBufferInfo[resourceCount]; // TODO: Fix this.
                VkDescriptorImageInfo * imageInfos       = stackalloc VkDescriptorImageInfo[resourceCount];  // TODO: Fix this.

                for (uint binding = 0; binding < resourceCount; binding++)
                {
                    descriptorWrites[binding].sType           = VkStructureType.WriteDescriptorSet;
                    descriptorWrites[binding].descriptorCount = 1;
                    descriptorWrites[binding].dstBinding      = binding;
                    descriptorWrites[binding].dstSet          = descriptorSet;

                    ShaderResourceDescription resource = cacheKey.ShaderResourceBindingSlots.Resources[binding];
                    switch (resource.Type)
                    {
                    case ShaderResourceType.ConstantBuffer:
                    {
                        descriptorWrites[binding].descriptorType = VkDescriptorType.UniformBuffer;
                        VkConstantBuffer cb = cacheKey.ConstantBuffers[binding];
                        if (cb == null)
                        {
                            throw new VeldridException($"No constant buffer bound to required binding slot {binding}.");
                        }
                        VkDescriptorBufferInfo *cbInfo = &bufferInfos[binding];
                        cbInfo->buffer = cb.DeviceBuffer;
                        cbInfo->offset = 0;
                        cbInfo->range  = (ulong)resource.DataSizeInBytes;
                        descriptorWrites[binding].pBufferInfo = cbInfo;
                        break;
                    }

                    case ShaderResourceType.Texture:
                    {
                        descriptorWrites[binding].descriptorType = VkDescriptorType.SampledImage;
                        VkShaderTextureBinding textureBinding = cacheKey.TextureBindings[binding];
                        if (textureBinding == null)
                        {
                            throw new VeldridException($"No texture bound to required binding slot {binding}.");
                        }
                        VkDescriptorImageInfo *imageInfo = &imageInfos[binding];
                        imageInfo->imageLayout = textureBinding.ImageLayout;
                        imageInfo->imageView   = textureBinding.ImageView;
                        descriptorWrites[binding].pImageInfo = imageInfo;
                    }
                    break;

                    case ShaderResourceType.Sampler:
                    {
                        descriptorWrites[binding].descriptorType = VkDescriptorType.Sampler;
                        VkSamplerState         samplerState = cacheKey.SamplerStates[binding] ?? (VkSamplerState)_defaultSamplerState;
                        VkDescriptorImageInfo *imageInfo    = &imageInfos[binding];
                        imageInfo->sampler = samplerState.Sampler;
                        descriptorWrites[binding].pImageInfo = imageInfo;
                    }
                    break;

                    default:
                        throw Illegal.Value <ShaderResourceType>();
                    }
                }

                vkUpdateDescriptorSets(_device, (uint)resourceCount, ref descriptorWrites[0], 0, null);

                return(descriptorSet);
            }
        }