private void CreateLogicalDevice() { GetQueueFamilyIndices(); HashSet <uint> familyIndices = new HashSet <uint> { _graphicsQueueIndex, _presentQueueIndex }; RawList <VkDeviceQueueCreateInfo> queueCreateInfos = new RawList <VkDeviceQueueCreateInfo>(); foreach (uint index in familyIndices) { VkDeviceQueueCreateInfo queueCreateInfo = VkDeviceQueueCreateInfo.New(); queueCreateInfo.queueFamilyIndex = _graphicsQueueIndex; queueCreateInfo.queueCount = 1; float priority = 1f; queueCreateInfo.pQueuePriorities = &priority; queueCreateInfos.Add(queueCreateInfo); } VkPhysicalDeviceFeatures deviceFeatures = new VkPhysicalDeviceFeatures(); deviceFeatures.samplerAnisotropy = true; deviceFeatures.fillModeNonSolid = true; deviceFeatures.geometryShader = true; deviceFeatures.depthClamp = true; VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New(); fixed(VkDeviceQueueCreateInfo *qciPtr = &queueCreateInfos.Items[0]) { deviceCreateInfo.pQueueCreateInfos = qciPtr; deviceCreateInfo.queueCreateInfoCount = queueCreateInfos.Count; deviceCreateInfo.pEnabledFeatures = &deviceFeatures; StackList <IntPtr> layerNames = new StackList <IntPtr>(); layerNames.Add(CommonStrings.StandardValidationLayerName); deviceCreateInfo.enabledLayerCount = layerNames.Count; deviceCreateInfo.ppEnabledLayerNames = (byte **)layerNames.Data; byte *extensionNames = CommonStrings.VK_KHR_SWAPCHAIN_EXTENSION_NAME; deviceCreateInfo.enabledExtensionCount = 1; deviceCreateInfo.ppEnabledExtensionNames = &extensionNames; vkCreateDevice(_physicalDevice, ref deviceCreateInfo, null, out _device); } vkGetDeviceQueue(_device, _graphicsQueueIndex, 0, out _graphicsQueue); vkGetDeviceQueue(_device, _presentQueueIndex, 0, out _presentQueue); }
private void CopyDataMultiImage( IntPtr pixelsFront, IntPtr pixelsBack, IntPtr pixelsLeft, IntPtr pixelsRight, IntPtr pixelsTop, IntPtr pixelsBottom) { StackList <IntPtr, Size6IntPtr> faces = new StackList <IntPtr, Size6IntPtr>(); faces.Add(pixelsRight); faces.Add(pixelsLeft); faces.Add(pixelsTop); faces.Add(pixelsBottom); faces.Add(pixelsBack); faces.Add(pixelsFront); TransitionImageLayout(_image, (uint)MipLevels, 0, 6, _imageLayout, VkImageLayout.TransferDstOptimal); for (uint i = 0; i < 6; i++) { CreateImage( _device, _physicalDevice, _memoryManager, (uint)Width, (uint)Height, 1, _vkFormat, VkImageTiling.Linear, VkImageUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, out VkImage stagingImage, out VkMemoryBlock stagingMemory); VkImageSubresource subresource; subresource.aspectMask = VkImageAspectFlags.Color; subresource.arrayLayer = 0; subresource.mipLevel = 0; vkGetImageSubresourceLayout(_device, stagingImage, ref subresource, out VkSubresourceLayout stagingLayout); void * mappedPtr; VkResult result = vkMapMemory(_device, stagingMemory.DeviceMemory, stagingMemory.Offset, stagingLayout.size, 0, &mappedPtr); CheckResult(result); IntPtr data = faces[i]; ulong dataSizeInBytes = (ulong)(Width * Height * FormatHelpers.GetPixelSizeInBytes(_format)); ulong rowPitch = stagingLayout.rowPitch; if (rowPitch == (ulong)Width) { Buffer.MemoryCopy(data.ToPointer(), mappedPtr, dataSizeInBytes, dataSizeInBytes); } else { int pixelSizeInBytes = FormatHelpers.GetPixelSizeInBytes(_format); for (uint yy = 0; yy < Height; yy++) { byte *dstRowStart = ((byte *)mappedPtr) + (rowPitch * yy); byte *srcRowStart = ((byte *)data.ToPointer()) + (Width * yy * pixelSizeInBytes); Unsafe.CopyBlock(dstRowStart, srcRowStart, (uint)(Width * pixelSizeInBytes)); } } vkUnmapMemory(_device, stagingMemory.DeviceMemory); TransitionImageLayout(stagingImage, 1, 0, 1, VkImageLayout.Preinitialized, VkImageLayout.TransferSrcOptimal); CopyImage(stagingImage, 0, 0, _image, 0, i, (uint)Width, (uint)Height); vkDestroyImage(_device, stagingImage, null); _memoryManager.Free(stagingMemory); } }
private void CopyDataSingleStagingBuffer(IntPtr pixelsFront, IntPtr pixelsBack, IntPtr pixelsLeft, IntPtr pixelsRight, IntPtr pixelsTop, IntPtr pixelsBottom, VkMemoryRequirements memReqs) { VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New(); bufferCI.size = memReqs.size; bufferCI.usage = VkBufferUsageFlags.TransferSrc; vkCreateBuffer(_device, ref bufferCI, null, out VkBuffer stagingBuffer); vkGetBufferMemoryRequirements(_device, stagingBuffer, out VkMemoryRequirements stagingMemReqs); VkMemoryBlock stagingMemory = _memoryManager.Allocate( FindMemoryType( _physicalDevice, stagingMemReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent), stagingMemReqs.size, stagingMemReqs.alignment); VkResult result = vkBindBufferMemory(_device, stagingBuffer, stagingMemory.DeviceMemory, 0); CheckResult(result); StackList <IntPtr, Size6IntPtr> faces = new StackList <IntPtr, Size6IntPtr>(); faces.Add(pixelsRight); faces.Add(pixelsLeft); faces.Add(pixelsTop); faces.Add(pixelsBottom); faces.Add(pixelsBack); faces.Add(pixelsFront); for (uint i = 0; i < 6; i++) { VkImageSubresource subresource; subresource.aspectMask = VkImageAspectFlags.Color; subresource.arrayLayer = i; subresource.mipLevel = 0; vkGetImageSubresourceLayout(_device, _image, ref subresource, out VkSubresourceLayout faceLayout); void *mappedPtr; result = vkMapMemory(_device, stagingMemory.DeviceMemory, faceLayout.offset, faceLayout.size, 0, &mappedPtr); CheckResult(result); Buffer.MemoryCopy((void *)faces[i], mappedPtr, faceLayout.size, faceLayout.size); vkUnmapMemory(_device, stagingMemory.DeviceMemory); } StackList <VkBufferImageCopy, Size512Bytes> copyRegions = new StackList <VkBufferImageCopy, Size512Bytes>(); for (uint i = 0; i < 6; i++) { VkImageSubresource subres; subres.aspectMask = VkImageAspectFlags.Color; subres.mipLevel = 0; subres.arrayLayer = i; vkGetImageSubresourceLayout(_device, _image, ref subres, out VkSubresourceLayout layout); VkBufferImageCopy copyRegion; copyRegion.bufferOffset = layout.offset; copyRegion.bufferImageHeight = 0; copyRegion.bufferRowLength = 0; copyRegion.imageExtent.width = (uint)Width; copyRegion.imageExtent.height = (uint)Height; copyRegion.imageExtent.depth = 1; copyRegion.imageOffset.x = 0; copyRegion.imageOffset.y = 0; copyRegion.imageOffset.z = 0; copyRegion.imageSubresource.baseArrayLayer = i; copyRegion.imageSubresource.aspectMask = VkImageAspectFlags.Color; copyRegion.imageSubresource.layerCount = 1; copyRegion.imageSubresource.mipLevel = 0; copyRegions.Add(copyRegion); } VkFenceCreateInfo fenceCI = VkFenceCreateInfo.New(); result = vkCreateFence(_device, ref fenceCI, null, out VkFence copyFence); CheckResult(result); TransitionImageLayout(_image, (uint)MipLevels, 0, 6, _imageLayout, VkImageLayout.TransferDstOptimal); VkCommandBuffer copyCmd = _rc.BeginOneTimeCommands(); vkCmdCopyBufferToImage(copyCmd, stagingBuffer, _image, VkImageLayout.TransferDstOptimal, copyRegions.Count, (IntPtr)copyRegions.Data); _rc.EndOneTimeCommands(copyCmd, copyFence); result = vkWaitForFences(_device, 1, ref copyFence, true, ulong.MaxValue); CheckResult(result); vkDestroyBuffer(_device, stagingBuffer, null); _memoryManager.Free(stagingMemory); }
private void FlushFrameDrawCommands() { _scInfo.AcquireNextImage(_device, _imageAvailableSemaphore); for (int i = 0; i < _renderPassStates.Count; i++) { RenderPassInfo renderPassState = _renderPassStates[i]; VkCommandBuffer primaryCommandBuffer = GetPrimaryCommandBuffer(); renderPassState.PrimaryCommandBuffer = primaryCommandBuffer; VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New(); beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit; vkBeginCommandBuffer(primaryCommandBuffer, ref beginInfo); VkRenderPassBeginInfo renderPassBeginInfo = VkRenderPassBeginInfo.New(); VkFramebufferBase fbInfo = renderPassState.Framebuffer; renderPassBeginInfo.framebuffer = fbInfo.VkFramebuffer; renderPassBeginInfo.renderPass = renderPassState.ClearBuffer ? fbInfo.RenderPassClearBuffer : fbInfo.RenderPassNoClear; if (renderPassState.ClearBuffer) { VkClearColorValue colorClear = new VkClearColorValue { float32_0 = renderPassState.ClearColor.R, float32_1 = renderPassState.ClearColor.G, float32_2 = renderPassState.ClearColor.B, float32_3 = renderPassState.ClearColor.A }; VkClearDepthStencilValue depthClear = new VkClearDepthStencilValue() { depth = 1f, stencil = 0 }; StackList <VkClearValue, Size512Bytes> clearValues = new StackList <VkClearValue, Size512Bytes>(); if (fbInfo.ColorTexture != null) { clearValues.Add(new VkClearValue() { color = colorClear }); } if (fbInfo.DepthTexture != null) { clearValues.Add(new VkClearValue() { depthStencil = depthClear }); } renderPassBeginInfo.clearValueCount = clearValues.Count; renderPassBeginInfo.pClearValues = (VkClearValue *)clearValues.Data; } renderPassBeginInfo.renderArea.extent = new VkExtent2D(fbInfo.Width, fbInfo.Height); vkCmdBeginRenderPass(primaryCommandBuffer, ref renderPassBeginInfo, VkSubpassContents.SecondaryCommandBuffers); RawList <VkCommandBuffer> secondaryCBs = renderPassState.SecondaryCommandBuffers; if (secondaryCBs.Count > 0) { vkCmdExecuteCommands(primaryCommandBuffer, secondaryCBs.Count, ref secondaryCBs[0]); } vkCmdEndRenderPass(primaryCommandBuffer); vkEndCommandBuffer(primaryCommandBuffer); VkSubmitInfo submitInfo = VkSubmitInfo.New(); VkSemaphore waitSemaphore = (i == 0) ? _imageAvailableSemaphore : _renderPassSemaphores[i - 1]; VkPipelineStageFlags waitStages = VkPipelineStageFlags.ColorAttachmentOutput; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &waitSemaphore; submitInfo.pWaitDstStageMask = &waitStages; VkCommandBuffer cb = primaryCommandBuffer; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cb; VkSemaphore signalSemaphore = _renderPassSemaphores[i]; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &signalSemaphore; vkQueueSubmit(_graphicsQueue, 1, ref submitInfo, VkFence.Null); } }
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 void CreateInstance() { HashSet <string> availableInstanceLayers = new HashSet <string>(EnumerateInstanceLayers()); HashSet <string> availableInstanceExtensions = new HashSet <string>(EnumerateInstanceExtensions()); VkInstanceCreateInfo instanceCI = VkInstanceCreateInfo.New(); VkApplicationInfo applicationInfo = new VkApplicationInfo(); applicationInfo.apiVersion = new VkVersion(1, 0, 0); applicationInfo.applicationVersion = new VkVersion(1, 0, 0); applicationInfo.engineVersion = new VkVersion(1, 0, 0); applicationInfo.pApplicationName = s_name; applicationInfo.pEngineName = s_name; instanceCI.pApplicationInfo = &applicationInfo; StackList <IntPtr, Size64Bytes> instanceExtensions = new StackList <IntPtr, Size64Bytes>(); StackList <IntPtr, Size64Bytes> instanceLayers = new StackList <IntPtr, Size64Bytes>(); if (!availableInstanceExtensions.Contains(CommonStrings.VK_KHR_SURFACE_EXTENSION_NAME)) { throw new VeldridException($"The required instance extension was not available: {CommonStrings.VK_KHR_SURFACE_EXTENSION_NAME}"); } instanceExtensions.Add(CommonStrings.VK_KHR_SURFACE_EXTENSION_NAME); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (!availableInstanceExtensions.Contains(CommonStrings.VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) { throw new VeldridException($"The required instance extension was not available: {CommonStrings.VK_KHR_WIN32_SURFACE_EXTENSION_NAME}"); } instanceExtensions.Add(CommonStrings.VK_KHR_WIN32_SURFACE_EXTENSION_NAME); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { if (!availableInstanceExtensions.Contains(CommonStrings.VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) { throw new VeldridException($"The required instance extension was not available: {CommonStrings.VK_KHR_XLIB_SURFACE_EXTENSION_NAME}"); } instanceExtensions.Add(CommonStrings.VK_KHR_XLIB_SURFACE_EXTENSION_NAME); } else { throw new NotSupportedException("This platform does not support Vulkan."); } bool debug = false; #if DEBUG debug = true; #endif bool debugReportExtensionAvailable = false; if (debug) { if (availableInstanceExtensions.Contains(CommonStrings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { debugReportExtensionAvailable = true; instanceExtensions.Add(CommonStrings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } if (availableInstanceLayers.Contains(CommonStrings.StandardValidationLayerName)) { instanceLayers.Add(CommonStrings.StandardValidationLayerName); } } instanceCI.enabledExtensionCount = instanceExtensions.Count; instanceCI.ppEnabledExtensionNames = (byte **)instanceExtensions.Data; instanceCI.enabledLayerCount = instanceLayers.Count; instanceCI.ppEnabledLayerNames = (byte **)instanceLayers.Data; VkResult result = vkCreateInstance(ref instanceCI, null, out _instance); CheckResult(result); if (debug && debugReportExtensionAvailable) { EnableDebugCallback(VkDebugReportFlagsEXT.WarningEXT | VkDebugReportFlagsEXT.ErrorEXT | VkDebugReportFlagsEXT.PerformanceWarningEXT); } }
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); }