/// <summary> /// 頂点入力の情報を構築します。 /// </summary> /// <returns></returns> private VkPipelineVertexInputStateCreateInfo CreateVertexInputState() { var attribPosition = new VkVertexInputAttributeDescription() { location = 0, binding = 0, offset = 0, format = VkFormat.VK_FORMAT_R32G32B32_SFLOAT, }; var attribCol0 = new VkVertexInputAttributeDescription() { location = 1, binding = 0, offset = 12, format = VkFormat.VK_FORMAT_R32G32B32A32_SFLOAT, }; var vertexInputBindingDesc = new VkVertexInputBindingDescription() { binding = 0, inputRate = VkVertexInputRate.VK_VERTEX_INPUT_RATE_VERTEX, stride = (uint)Marshal.SizeOf <Vertex>(), }; var vertexInputState = new VkPipelineVertexInputStateCreateInfo() { attributeDescriptions = new[] { attribPosition, attribCol0 }, bindingDescriptions = new[] { vertexInputBindingDesc }, }; return(vertexInputState); }
void setupVertexDescriptions() { // Binding description vDescription.bindingDescriptions = VkVertexInputBindingDescription.Alloc(); vDescription.bindingDescriptions[0].binding = VERTEX_BUFFER_BIND_ID; vDescription.bindingDescriptions[0].stride = (uint)sizeof(Vertex); vDescription.bindingDescriptions[0].inputRate = VkVertexInputRate.Vertex; // Attribute descriptions // Describes memory layout and shader positions vDescription.attributeDescriptions = VkVertexInputAttributeDescription.Alloc(3); // Location 0 : Position vDescription.attributeDescriptions[0].binding = VERTEX_BUFFER_BIND_ID; vDescription.attributeDescriptions[0].location = 0; vDescription.attributeDescriptions[0].format = VkFormat.R32g32b32Sfloat; vDescription.attributeDescriptions[0].offset = Vertex.PositionOffset; // Location 1 : Texture coordinates vDescription.attributeDescriptions[1].binding = VERTEX_BUFFER_BIND_ID; vDescription.attributeDescriptions[1].location = 1; vDescription.attributeDescriptions[1].format = VkFormat.R32g32Sfloat; vDescription.attributeDescriptions[1].offset = Vertex.UvOffset; // Location 1 : Vertex normal vDescription.attributeDescriptions[2].binding = VERTEX_BUFFER_BIND_ID; vDescription.attributeDescriptions[2].location = 2; vDescription.attributeDescriptions[2].format = VkFormat.R32g32b32Sfloat; vDescription.attributeDescriptions[2].offset = Vertex.NormalOffset; vDescription.inputState = VkPipelineVertexInputStateCreateInfo.Alloc(); vDescription.inputState[0].vertexBindingDescriptions.count = 1; vDescription.inputState[0].vertexBindingDescriptions.pointer = vDescription.bindingDescriptions; vDescription.inputState[0].vertexAttributeDescriptions.count = 3; vDescription.inputState[0].vertexAttributeDescriptions.pointer = vDescription.attributeDescriptions; }
// Creates the set of vertex attributes and bindings from the descriptions private static void CalculateVertexInfo(VertexDescription[] descs, out VkVertexInputAttributeDescription[] attrs, out VkVertexInputBindingDescription[] binds) { // Create arrays var attrcnt = (int)descs.Sum(vd => vd.BindingCount); attrs = new VkVertexInputAttributeDescription[attrcnt]; binds = new VkVertexInputBindingDescription[descs.Length]; // Populate attributes & bindings var attroff = 0; for (var bi = 0; bi < descs.Length; ++bi) { var vd = descs[bi]; for (var ei = 0; ei < vd.Elements.Count; ++ei) { var copyCount = vd.Elements[ei].BindingCount; // TODO: Won't work once we add double/long types for (uint ai = 0; ai < copyCount; ++ai) { attrs[attroff++] = new( location : vd.Locations[ei] + ai, binding : (uint)bi, format : vd.Elements[ei].Format.GetVulkanFormat(), offset : vd.Elements[ei].Offset + (ai * vd.Elements[ei].Format.GetSize()) ); } } binds[bi] = new( binding : (uint)bi, stride : vd.Stride, inputRate : (VkVertexInputRate)vd.Rate ); } }
public static List <VkVertexInputAttributeDescription> GetAttributeDescriptions() { Vertex v = new Vertex(); var desc1 = new VkVertexInputAttributeDescription(); desc1.binding = 0; desc1.location = 0; desc1.format = VkFormat.R32G32B32_Sfloat; desc1.offset = (int)Interop.Offset(ref v, ref v.position); var desc2 = new VkVertexInputAttributeDescription(); desc2.binding = 0; desc2.location = 1; desc2.format = VkFormat.R32G32B32_Sfloat; desc2.offset = (int)Interop.Offset(ref v, ref v.color); var desc3 = new VkVertexInputAttributeDescription(); desc3.binding = 0; desc3.location = 2; desc3.format = VkFormat.R32G32_Sfloat; desc3.offset = (int)Interop.Offset(ref v, ref v.texCoord); return(new List <VkVertexInputAttributeDescription> { desc1, desc2, desc3 }); }
public static VkVertexInputAttributeDescription vertexInputAttributeDescription( uint binding, uint location, VkFormat format, uint offset) { VkVertexInputAttributeDescription vInputAttribDescription = new VkVertexInputAttributeDescription(); vInputAttribDescription.location = location; vInputAttribDescription.binding = binding; vInputAttribDescription.format = format; vInputAttribDescription.offset = offset; return(vInputAttribDescription); }
public static VkVertexInputAttributeDescription[] getAttributeDescriptions() { VkVertexInputAttributeDescription[] attributeDescriptions = new VkVertexInputAttributeDescription[2]; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; attributeDescriptions[0].format = VkFormat.VK_FORMAT_R32G32_SFLOAT; attributeDescriptions[0].offset = (int)Marshal.OffsetOf(typeof(Vertex), nameof(Vertex.pos)); attributeDescriptions[1].binding = 0; attributeDescriptions[1].location = 1; attributeDescriptions[1].format = VkFormat.VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[1].offset = (int)Marshal.OffsetOf(typeof(Vertex), nameof(Vertex.color)); return(attributeDescriptions); }
void setupVertexDescriptions() { // Binding description vBindingDescriptions = new VkVertexInputBindingDescription[1]; vBindingDescriptions[0] = new VkVertexInputBindingDescription(); vBindingDescriptions[0].binding = VERTEX_BUFFER_BIND_ID; vBindingDescriptions[0].stride = (uint)sizeof(Vertex); vBindingDescriptions[0].inputRate = VkVertexInputRate.Vertex; // Attribute descriptions // Describes memory layout and shader positions vAttrDescriptions = new VkVertexInputAttributeDescription[4]; // Location 0 : Position vAttrDescriptions[0] = new VkVertexInputAttributeDescription(); vAttrDescriptions[0].binding = VERTEX_BUFFER_BIND_ID; vAttrDescriptions[0].location = 0; vAttrDescriptions[0].format = VkFormat.R32g32b32Sfloat; vAttrDescriptions[0].offset = Vertex.PositionOffset; // Location 1 : Normal vAttrDescriptions[1] = new VkVertexInputAttributeDescription(); vAttrDescriptions[1].binding = VERTEX_BUFFER_BIND_ID; vAttrDescriptions[1].location = 1; vAttrDescriptions[1].format = VkFormat.R32g32b32Sfloat; vAttrDescriptions[1].offset = Vertex.NormalOffset; // Location 2 : Texture coordinates vAttrDescriptions[2] = new VkVertexInputAttributeDescription(); vAttrDescriptions[2].binding = VERTEX_BUFFER_BIND_ID; vAttrDescriptions[2].location = 2; vAttrDescriptions[2].format = VkFormat.R32g32Sfloat; vAttrDescriptions[2].offset = Vertex.UvOffset; // Location 3 : Color vAttrDescriptions[3] = new VkVertexInputAttributeDescription(); vAttrDescriptions[3].binding = VERTEX_BUFFER_BIND_ID; vAttrDescriptions[3].location = 3; vAttrDescriptions[3].format = VkFormat.R32g32b32Sfloat; vAttrDescriptions[3].offset = Vertex.ColorOffset; vInputStateInfo = VkPipelineVertexInputStateCreateInfo.Alloc(); vInputStateInfo->vertexBindingDescriptions = vBindingDescriptions; vInputStateInfo->vertexAttributeDescriptions = vAttrDescriptions; }
public static List <VkVertexInputAttributeDescription> GetAttributeDescriptions() { Vertex v = new Vertex(); var a = new VkVertexInputAttributeDescription(); a.binding = 0; a.location = 0; a.format = VkFormat.R32G32B32_Sfloat; a.offset = (int)Interop.Offset(ref v, ref v.position); var b = new VkVertexInputAttributeDescription(); b.binding = 0; b.location = 1; b.format = VkFormat.R32G32B32_Sfloat; b.offset = (int)Interop.Offset(ref v, ref v.color); return(new List <VkVertexInputAttributeDescription> { a, b }); }
void setupVertexDescriptions() { // Binding description bindingDescs = new VkVertexInputBindingDescription[1]; bindingDescs[0].binding = VERTEX_BUFFER_BIND_ID; bindingDescs[0].stride = vertexLayout.stride(); bindingDescs[0].inputRate = VkVertexInputRate.Vertex;// VK_VERTEX_INPUT_RATE_VERTEX; // Attribute descriptions attributeDescs = VkVertexInputAttributeDescription.Alloc(4); // Location 0 : Position attributeDescs[0].binding = VERTEX_BUFFER_BIND_ID; attributeDescs[0].location = 0; attributeDescs[0].format = VkFormat.R32g32b32Sfloat;// VK_FORMAT_R32G32B32_SFLOAT, attributeDescs[0].offset = 0; // Location 1 : Texture coordinates attributeDescs[1].binding = VERTEX_BUFFER_BIND_ID; attributeDescs[1].location = 1; attributeDescs[1].format = VkFormat.R32g32Sfloat;// VK_FORMAT_R32G32_SFLOAT, attributeDescs[1].offset = sizeof(float) * 3; // Location 2 : Color attributeDescs[2].binding = VERTEX_BUFFER_BIND_ID; attributeDescs[2].location = 2; attributeDescs[2].format = VkFormat.R32g32b32Sfloat;// VK_FORMAT_R32G32B32_SFLOAT, attributeDescs[2].offset = sizeof(float) * 5; // Location 3 : Normal attributeDescs[3].binding = VERTEX_BUFFER_BIND_ID; attributeDescs[3].location = 3; attributeDescs[3].format = VkFormat.R32g32b32Sfloat;// VK_FORMAT_R32G32B32_SFLOAT, attributeDescs[3].offset = sizeof(float) * 8; inputInfo = VkPipelineVertexInputStateCreateInfo.Alloc(); inputInfo[0].vertexBindingDescriptions = bindingDescs; inputInfo[0].vertexAttributeDescriptions.count = 4; inputInfo[0].vertexAttributeDescriptions.pointer = attributeDescs; }
private unsafe void Recreate() { if (Description.RootSignature == null) { return; } CreateRenderPass(Description); CreatePipelineLayout(Description); // Create shader stages Dictionary <int, string> inputAttributeNames; // Note: important to pin this so that stages[x].Name is valid during this whole function void *defaultEntryPointData = Core.Interop.Fixed(defaultEntryPoint); var stages = CreateShaderStages(Description, out inputAttributeNames); var inputAttributes = new VkVertexInputAttributeDescription[Description.InputElements.Length]; int inputAttributeCount = 0; var inputBindings = new VkVertexInputBindingDescription[inputAttributes.Length]; int inputBindingCount = 0; for (int inputElementIndex = 0; inputElementIndex < inputAttributes.Length; inputElementIndex++) { var inputElement = Description.InputElements[inputElementIndex]; var slotIndex = inputElement.InputSlot; if (inputElement.InstanceDataStepRate > 1) { throw new NotImplementedException(); } VkFormat format; int size; bool isCompressed; VulkanConvertExtensions.ConvertPixelFormat(inputElement.Format, out format, out size, out isCompressed); var location = inputAttributeNames.FirstOrDefault(x => x.Value == inputElement.SemanticName && inputElement.SemanticIndex == 0 || x.Value == inputElement.SemanticName + inputElement.SemanticIndex); if (location.Value != null) { inputAttributes[inputAttributeCount++] = new VkVertexInputAttributeDescription { format = format, offset = (uint)inputElement.AlignedByteOffset, binding = (uint)inputElement.InputSlot, location = (uint)location.Key }; } inputBindings[slotIndex].binding = (uint)slotIndex; inputBindings[slotIndex].inputRate = inputElement.InputSlotClass == InputClassification.Vertex ? VkVertexInputRate.Vertex : VkVertexInputRate.Instance; // TODO VULKAN: This is currently an argument to Draw() overloads. if (inputBindings[slotIndex].stride < inputElement.AlignedByteOffset + size) { inputBindings[slotIndex].stride = (uint)(inputElement.AlignedByteOffset + size); } if (inputElement.InputSlot >= inputBindingCount) { inputBindingCount = inputElement.InputSlot + 1; } } var inputAssemblyState = new VkPipelineInputAssemblyStateCreateInfo { sType = VkStructureType.PipelineInputAssemblyStateCreateInfo, topology = VulkanConvertExtensions.ConvertPrimitiveType(Description.PrimitiveType), primitiveRestartEnable = VulkanConvertExtensions.ConvertPrimitiveRestart(Description.PrimitiveType), }; // TODO VULKAN: Tessellation and multisampling var multisampleState = new VkPipelineMultisampleStateCreateInfo { sType = VkStructureType.PipelineMultisampleStateCreateInfo, rasterizationSamples = VkSampleCountFlags.Count1, }; var tessellationState = new VkPipelineTessellationStateCreateInfo { sType = VkStructureType.PipelineTessellationStateCreateInfo, }; var rasterizationState = CreateRasterizationState(Description.RasterizerState); var depthStencilState = CreateDepthStencilState(Description); var description = Description.BlendState; var renderTargetCount = Description.Output.RenderTargetCount; var colorBlendAttachments = new VkPipelineColorBlendAttachmentState[renderTargetCount]; var renderTargetBlendState = &description.RenderTarget0; for (int i = 0; i < renderTargetCount; i++) { colorBlendAttachments[i] = new VkPipelineColorBlendAttachmentState { blendEnable = renderTargetBlendState->BlendEnable, alphaBlendOp = VulkanConvertExtensions.ConvertBlendFunction(renderTargetBlendState->AlphaBlendFunction), colorBlendOp = VulkanConvertExtensions.ConvertBlendFunction(renderTargetBlendState->ColorBlendFunction), dstAlphaBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->AlphaDestinationBlend), dstColorBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->ColorDestinationBlend), srcAlphaBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->AlphaSourceBlend), srcColorBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->ColorSourceBlend), colorWriteMask = VulkanConvertExtensions.ConvertColorWriteChannels(renderTargetBlendState->ColorWriteChannels), }; if (description.IndependentBlendEnable) { renderTargetBlendState++; } } var viewportState = new VkPipelineViewportStateCreateInfo { sType = VkStructureType.PipelineViewportStateCreateInfo, scissorCount = 1, viewportCount = 1, }; fixed(VkDynamicState *dynamicStatesPointer = &dynamicStates[0]) { var vertexInputState = new VkPipelineVertexInputStateCreateInfo { sType = VkStructureType.PipelineVertexInputStateCreateInfo, vertexAttributeDescriptionCount = (uint)inputAttributeCount, pVertexAttributeDescriptions = inputAttributes.Length > 0 ? (VkVertexInputAttributeDescription *)Core.Interop.Fixed(inputAttributes) : null, vertexBindingDescriptionCount = (uint)inputBindingCount, pVertexBindingDescriptions = inputBindings.Length > 0 ? (VkVertexInputBindingDescription *)Core.Interop.Fixed(inputBindings) : null, }; var colorBlendState = new VkPipelineColorBlendStateCreateInfo { sType = VkStructureType.PipelineColorBlendStateCreateInfo, attachmentCount = (uint)renderTargetCount, pAttachments = colorBlendAttachments.Length > 0 ? (VkPipelineColorBlendAttachmentState *)Core.Interop.Fixed(colorBlendAttachments) : null, }; var dynamicState = new VkPipelineDynamicStateCreateInfo { sType = VkStructureType.PipelineDynamicStateCreateInfo, dynamicStateCount = (uint)dynamicStates.Length, pDynamicStates = dynamicStatesPointer, }; var createInfo = new VkGraphicsPipelineCreateInfo { sType = VkStructureType.GraphicsPipelineCreateInfo, layout = NativeLayout, stageCount = (uint)stages.Length, pStages = stages.Length > 0 ? (VkPipelineShaderStageCreateInfo *)Core.Interop.Fixed(stages) : null, //tessellationState = &tessellationState, pVertexInputState = &vertexInputState, pInputAssemblyState = &inputAssemblyState, pRasterizationState = &rasterizationState, pMultisampleState = &multisampleState, pDepthStencilState = &depthStencilState, pColorBlendState = &colorBlendState, pDynamicState = &dynamicState, pViewportState = &viewportState, renderPass = NativeRenderPass, subpass = 0, }; fixed(VkPipeline *nativePipelinePtr = &NativePipeline) vkCreateGraphicsPipelines(GraphicsDevice.NativeDevice, VkPipelineCache.Null, 1, &createInfo, null, nativePipelinePtr); } // Cleanup shader modules foreach (var stage in stages) { vkDestroyShaderModule(GraphicsDevice.NativeDevice, stage.module, null); } }
//[HandleProcessCorruptedStateExceptionsAttribute, SecurityCriticalAttribute] private unsafe void Recreate() { errorDuringCreate = false; if (Description.RootSignature == null) { return; } VkPipelineShaderStageCreateInfo[] stages; // create render pass bool hasDepthStencilAttachment = Description.Output.DepthStencilFormat != PixelFormat.None; var renderTargetCount = Description.Output.RenderTargetCount; var attachmentCount = renderTargetCount; if (hasDepthStencilAttachment) { attachmentCount++; } var attachments = new VkAttachmentDescription[attachmentCount]; var colorAttachmentReferences = new VkAttachmentReference[renderTargetCount]; fixed(PixelFormat *renderTargetFormat = &Description.Output.RenderTargetFormat0) fixed(BlendStateRenderTargetDescription * blendDescription = &Description.BlendState.RenderTarget0) { for (int i = 0; i < renderTargetCount; i++) { var currentBlendDesc = Description.BlendState.IndependentBlendEnable ? (blendDescription + i) : blendDescription; attachments[i] = new VkAttachmentDescription { format = VulkanConvertExtensions.ConvertPixelFormat(*(renderTargetFormat + i)), samples = VkSampleCountFlags.Count1, loadOp = currentBlendDesc->BlendEnable ? VkAttachmentLoadOp.Load : VkAttachmentLoadOp.DontCare, // TODO VULKAN: Only if any destination blend? storeOp = VkAttachmentStoreOp.Store, stencilLoadOp = VkAttachmentLoadOp.DontCare, stencilStoreOp = VkAttachmentStoreOp.DontCare, initialLayout = VkImageLayout.ColorAttachmentOptimal, finalLayout = VkImageLayout.ColorAttachmentOptimal, }; colorAttachmentReferences[i] = new VkAttachmentReference { attachment = (uint)i, layout = VkImageLayout.ColorAttachmentOptimal, }; } } if (hasDepthStencilAttachment) { attachments[attachmentCount - 1] = new VkAttachmentDescription { format = Texture.GetFallbackDepthStencilFormat(GraphicsDevice, VulkanConvertExtensions.ConvertPixelFormat(Description.Output.DepthStencilFormat)), samples = VkSampleCountFlags.Count1, loadOp = VkAttachmentLoadOp.Load, // TODO VULKAN: Only if depth read enabled? storeOp = VkAttachmentStoreOp.Store, // TODO VULKAN: Only if depth write enabled? stencilLoadOp = VkAttachmentLoadOp.DontCare, // TODO VULKAN: Handle stencil stencilStoreOp = VkAttachmentStoreOp.DontCare, initialLayout = VkImageLayout.DepthStencilAttachmentOptimal, finalLayout = VkImageLayout.DepthStencilAttachmentOptimal, }; } var depthAttachmentReference = new VkAttachmentReference { attachment = (uint)attachments.Length - 1, layout = VkImageLayout.DepthStencilAttachmentOptimal, }; var subpass = new VkSubpassDescription { pipelineBindPoint = VkPipelineBindPoint.Graphics, colorAttachmentCount = (uint)renderTargetCount, pColorAttachments = colorAttachmentReferences.Length > 0 ? (VkAttachmentReference *)Core.Interop.Fixed(colorAttachmentReferences) : null, pDepthStencilAttachment = hasDepthStencilAttachment ? &depthAttachmentReference : null, }; var renderPassCreateInfo = new VkRenderPassCreateInfo { sType = VkStructureType.RenderPassCreateInfo, attachmentCount = (uint)attachmentCount, pAttachments = attachments.Length > 0 ? (VkAttachmentDescription *)Core.Interop.Fixed(attachments) : null, subpassCount = 1, pSubpasses = &subpass, }; // create pipeline layout // Remap descriptor set indices to those in the shader. This ordering generated by the ShaderCompiler var resourceGroups = Description.EffectBytecode.Reflection.ResourceBindings.Select(x => x.ResourceGroup ?? "Globals").Distinct().ToList(); ResourceGroupCount = resourceGroups.Count; var layouts = Description.RootSignature.EffectDescriptorSetReflection.Layouts; // Get binding indices used by the shader var destinationBindings = Description.EffectBytecode.Stages .SelectMany(x => BinarySerialization.Read <ShaderInputBytecode>(x.Data).ResourceBindings) .GroupBy(x => x.Key, x => x.Value) .ToDictionary(x => x.Key, x => x.First()); var maxBindingIndex = destinationBindings.Max(x => x.Value); var destinationEntries = new DescriptorSetLayoutBuilder.Entry[maxBindingIndex + 1]; DescriptorBindingMapping = new List <DescriptorSetInfo>(); for (int i = 0; i < resourceGroups.Count; i++) { var resourceGroupName = resourceGroups[i] == "Globals" ? Description.RootSignature.EffectDescriptorSetReflection.DefaultSetSlot : resourceGroups[i]; var layoutIndex = resourceGroups[i] == null ? 0 : layouts.FindIndex(x => x.Name == resourceGroupName); // Check if the resource group is used by the shader if (layoutIndex == -1) { continue; } var sourceEntries = layouts[layoutIndex].Layout.Entries; for (int sourceBinding = 0; sourceBinding < sourceEntries.Count; sourceBinding++) { var sourceEntry = sourceEntries[sourceBinding]; int destinationBinding; if (destinationBindings.TryGetValue(sourceEntry.Key.Name, out destinationBinding)) { destinationEntries[destinationBinding] = sourceEntry; // No need to umpdate immutable samplers if (sourceEntry.Class == EffectParameterClass.Sampler && sourceEntry.ImmutableSampler != null) { continue; } DescriptorBindingMapping.Add(new DescriptorSetInfo { SourceSet = layoutIndex, SourceBinding = sourceBinding, DestinationBinding = destinationBinding, DescriptorType = VulkanConvertExtensions.ConvertDescriptorType(sourceEntry.Class, sourceEntry.Type) }); } } } // Create default sampler, used by texture and buffer loads destinationEntries[0] = new DescriptorSetLayoutBuilder.Entry { Class = EffectParameterClass.Sampler, Type = EffectParameterType.Sampler, ImmutableSampler = GraphicsDevice.SamplerStates.PointWrap, ArraySize = 1, }; // Create descriptor set layout NativeDescriptorSetLayout = DescriptorSetLayout.CreateNativeDescriptorSetLayout(GraphicsDevice, destinationEntries, out DescriptorTypeCounts); // Create pipeline layout var nativeDescriptorSetLayout = NativeDescriptorSetLayout; var pipelineLayoutCreateInfo = new VkPipelineLayoutCreateInfo { sType = VkStructureType.PipelineLayoutCreateInfo, setLayoutCount = 1, pSetLayouts = &nativeDescriptorSetLayout, }; // Create shader stages Dictionary <int, string> inputAttributeNames; // Note: important to pin this so that stages[x].Name is valid during this whole function void *defaultEntryPointData = Core.Interop.Fixed(defaultEntryPoint); stages = CreateShaderStages(Description, out inputAttributeNames); var inputAttributes = new VkVertexInputAttributeDescription[Description.InputElements.Length]; int inputAttributeCount = 0; var inputBindings = new VkVertexInputBindingDescription[inputAttributes.Length]; int inputBindingCount = 0; for (int inputElementIndex = 0; inputElementIndex < inputAttributes.Length; inputElementIndex++) { var inputElement = Description.InputElements[inputElementIndex]; var slotIndex = inputElement.InputSlot; if (inputElement.InstanceDataStepRate > 1) { throw new NotImplementedException(); } VkFormat format; int size; bool isCompressed; VulkanConvertExtensions.ConvertPixelFormat(inputElement.Format, out format, out size, out isCompressed); var location = inputAttributeNames.FirstOrDefault(x => x.Value == inputElement.SemanticName && inputElement.SemanticIndex == 0 || x.Value == inputElement.SemanticName + inputElement.SemanticIndex); if (location.Value != null) { inputAttributes[inputAttributeCount++] = new VkVertexInputAttributeDescription { format = format, offset = (uint)inputElement.AlignedByteOffset, binding = (uint)inputElement.InputSlot, location = (uint)location.Key }; } inputBindings[slotIndex].binding = (uint)slotIndex; inputBindings[slotIndex].inputRate = inputElement.InputSlotClass == InputClassification.Vertex ? VkVertexInputRate.Vertex : VkVertexInputRate.Instance; // TODO VULKAN: This is currently an argument to Draw() overloads. if (inputBindings[slotIndex].stride < inputElement.AlignedByteOffset + size) { inputBindings[slotIndex].stride = (uint)(inputElement.AlignedByteOffset + size); } if (inputElement.InputSlot >= inputBindingCount) { inputBindingCount = inputElement.InputSlot + 1; } } var inputAssemblyState = new VkPipelineInputAssemblyStateCreateInfo { sType = VkStructureType.PipelineInputAssemblyStateCreateInfo, topology = VulkanConvertExtensions.ConvertPrimitiveType(Description.PrimitiveType), primitiveRestartEnable = VulkanConvertExtensions.ConvertPrimitiveRestart(Description.PrimitiveType) ? (uint)1 : (uint)0, }; // TODO VULKAN: Tessellation and multisampling var multisampleState = new VkPipelineMultisampleStateCreateInfo { sType = VkStructureType.PipelineMultisampleStateCreateInfo, rasterizationSamples = VkSampleCountFlags.Count1, }; var rasterizationState = new VkPipelineRasterizationStateCreateInfo { sType = VkStructureType.PipelineRasterizationStateCreateInfo, cullMode = VulkanConvertExtensions.ConvertCullMode(Description.RasterizerState.CullMode), frontFace = Description.RasterizerState.FrontFaceCounterClockwise ? VkFrontFace.CounterClockwise : VkFrontFace.Clockwise, polygonMode = VulkanConvertExtensions.ConvertFillMode(Description.RasterizerState.FillMode), depthBiasEnable = 1, // TODO VULKAN depthBiasConstantFactor = Description.RasterizerState.DepthBias, depthBiasSlopeFactor = Description.RasterizerState.SlopeScaleDepthBias, depthBiasClamp = Description.RasterizerState.DepthBiasClamp, lineWidth = 1.0f, depthClampEnable = Description.RasterizerState.DepthClipEnable ? (uint)0 : (uint)1, rasterizerDiscardEnable = 0, }; var depthStencilState = new VkPipelineDepthStencilStateCreateInfo { sType = VkStructureType.PipelineDepthStencilStateCreateInfo, depthTestEnable = Description.DepthStencilState.DepthBufferEnable ? (uint)1 : (uint)0, stencilTestEnable = Description.DepthStencilState.StencilEnable ? (uint)1 : (uint)0, depthWriteEnable = Description.DepthStencilState.DepthBufferWriteEnable ? (uint)1 : (uint)0, minDepthBounds = 0.0f, maxDepthBounds = 1.0f, depthCompareOp = VulkanConvertExtensions.ConvertComparisonFunction(Description.DepthStencilState.DepthBufferFunction), front = { compareOp = VulkanConvertExtensions.ConvertComparisonFunction(Description.DepthStencilState.FrontFace.StencilFunction), depthFailOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.FrontFace.StencilDepthBufferFail), failOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.FrontFace.StencilFail), passOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.FrontFace.StencilPass), compareMask = Description.DepthStencilState.StencilMask, writeMask = Description.DepthStencilState.StencilWriteMask }, back = { compareOp = VulkanConvertExtensions.ConvertComparisonFunction(Description.DepthStencilState.BackFace.StencilFunction), depthFailOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.BackFace.StencilDepthBufferFail), failOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.BackFace.StencilFail), passOp = VulkanConvertExtensions.ConvertStencilOperation(Description.DepthStencilState.BackFace.StencilPass), compareMask = Description.DepthStencilState.StencilMask, writeMask = Description.DepthStencilState.StencilWriteMask } }; var description = Description.BlendState; var colorBlendAttachments = new VkPipelineColorBlendAttachmentState[renderTargetCount]; var renderTargetBlendState = &description.RenderTarget0; for (int i = 0; i < renderTargetCount; i++) { colorBlendAttachments[i] = new VkPipelineColorBlendAttachmentState { blendEnable = renderTargetBlendState->BlendEnable ? (uint)1 : (uint)0, alphaBlendOp = VulkanConvertExtensions.ConvertBlendFunction(renderTargetBlendState->AlphaBlendFunction), colorBlendOp = VulkanConvertExtensions.ConvertBlendFunction(renderTargetBlendState->ColorBlendFunction), dstAlphaBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->AlphaDestinationBlend), dstColorBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->ColorDestinationBlend), srcAlphaBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->AlphaSourceBlend), srcColorBlendFactor = VulkanConvertExtensions.ConvertBlend(renderTargetBlendState->ColorSourceBlend), colorWriteMask = VulkanConvertExtensions.ConvertColorWriteChannels(renderTargetBlendState->ColorWriteChannels), }; if (description.IndependentBlendEnable) { renderTargetBlendState++; } } var viewportState = new VkPipelineViewportStateCreateInfo { sType = VkStructureType.PipelineViewportStateCreateInfo, scissorCount = 1, viewportCount = 1, }; fixed(void *dynamicStatesPointer = dynamicStates.Length == 0?null : dynamicStates, inputAttributesPointer = inputAttributes.Length == 0?null : inputAttributes, inputBindingsPointer = inputBindings.Length == 0?null : inputBindings, colorBlendAttachmentsPointer = colorBlendAttachments.Length == 0?null : colorBlendAttachments, stagesPointer = stages.Length == 0?null : stages) { var vertexInputState = new VkPipelineVertexInputStateCreateInfo { sType = VkStructureType.PipelineVertexInputStateCreateInfo, vertexAttributeDescriptionCount = (uint)inputAttributeCount, pVertexAttributeDescriptions = (Vortice.Vulkan.VkVertexInputAttributeDescription *)inputAttributesPointer, vertexBindingDescriptionCount = (uint)inputBindingCount, pVertexBindingDescriptions = (Vortice.Vulkan.VkVertexInputBindingDescription *)inputBindingsPointer, }; var colorBlendState = new VkPipelineColorBlendStateCreateInfo { sType = VkStructureType.PipelineColorBlendStateCreateInfo, attachmentCount = (uint)renderTargetCount, pAttachments = (Vortice.Vulkan.VkPipelineColorBlendAttachmentState *)colorBlendAttachmentsPointer, }; var dynamicState = new VkPipelineDynamicStateCreateInfo { sType = VkStructureType.PipelineDynamicStateCreateInfo, dynamicStateCount = (uint)dynamicStates.Length, pDynamicStates = (Vortice.Vulkan.VkDynamicState *)dynamicStatesPointer, }; var createInfo = new VkGraphicsPipelineCreateInfo { sType = VkStructureType.GraphicsPipelineCreateInfo, layout = NativeLayout, stageCount = (uint)stages.Length, pVertexInputState = &vertexInputState, pInputAssemblyState = &inputAssemblyState, pRasterizationState = &rasterizationState, pMultisampleState = &multisampleState, pDepthStencilState = &depthStencilState, pColorBlendState = &colorBlendState, pDynamicState = &dynamicState, pStages = (Vortice.Vulkan.VkPipelineShaderStageCreateInfo *)stagesPointer, pViewportState = &viewportState, renderPass = NativeRenderPass, subpass = 0, }; using (GraphicsDevice.QueueLock.ReadLock()) { vkCreateRenderPass(GraphicsDevice.NativeDevice, &renderPassCreateInfo, null, out NativeRenderPass); vkCreatePipelineLayout(GraphicsDevice.NativeDevice, &pipelineLayoutCreateInfo, null, out NativeLayout); createInfo.layout = NativeLayout; createInfo.renderPass = NativeRenderPass; try { fixed(VkPipeline *nativePipelinePtr = &NativePipeline) vkCreateGraphicsPipelines(GraphicsDevice.NativeDevice, VkPipelineCache.Null, 1, &createInfo, null, nativePipelinePtr); } catch (Exception e) { errorDuringCreate = true; NativePipeline = VkPipeline.Null; } } } // Cleanup shader modules for (int i = 0; i < stages.Length; i++) { vkDestroyShaderModule(GraphicsDevice.NativeDevice, stages[i].module, null); } }
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); }
public VkPipeline(VkGraphicsDevice gd, ref PipelineDescription description) { _gd = gd; VkGraphicsPipelineCreateInfo pipelineCI = VkGraphicsPipelineCreateInfo.New(); // Blend State VkPipelineColorBlendStateCreateInfo blendStateCI = VkPipelineColorBlendStateCreateInfo.New(); int attachmentsCount = description.BlendState.AttachmentStates.Length; VkPipelineColorBlendAttachmentState *attachmentsPtr = stackalloc VkPipelineColorBlendAttachmentState[attachmentsCount]; for (int i = 0; i < attachmentsCount; i++) { BlendAttachmentDescription vdDesc = description.BlendState.AttachmentStates[i]; VkPipelineColorBlendAttachmentState attachmentState = new VkPipelineColorBlendAttachmentState(); attachmentState.srcColorBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.SourceColorFactor); attachmentState.dstColorBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.DestinationColorFactor); attachmentState.colorBlendOp = VkFormats.VdToVkBlendOp(vdDesc.ColorFunction); attachmentState.srcAlphaBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.SourceAlphaFactor); attachmentState.dstAlphaBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.DestinationAlphaFactor); attachmentState.alphaBlendOp = VkFormats.VdToVkBlendOp(vdDesc.AlphaFunction); attachmentState.blendEnable = vdDesc.BlendEnabled; attachmentState.colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A; attachmentsPtr[i] = attachmentState; } blendStateCI.attachmentCount = (uint)attachmentsCount; blendStateCI.pAttachments = attachmentsPtr; RgbaFloat blendFactor = description.BlendState.BlendFactor; blendStateCI.blendConstants_0 = blendFactor.R; blendStateCI.blendConstants_1 = blendFactor.G; blendStateCI.blendConstants_2 = blendFactor.B; blendStateCI.blendConstants_3 = blendFactor.A; pipelineCI.pColorBlendState = &blendStateCI; // Rasterizer State RasterizerStateDescription rsDesc = description.RasterizerState; VkPipelineRasterizationStateCreateInfo rsCI = VkPipelineRasterizationStateCreateInfo.New(); rsCI.cullMode = VkFormats.VdToVkCullMode(rsDesc.CullMode); rsCI.polygonMode = VkFormats.VdToVkPolygonMode(rsDesc.FillMode); rsCI.depthClampEnable = !rsDesc.DepthClipEnabled; rsCI.frontFace = VkFrontFace.Clockwise; rsCI.lineWidth = 1f; pipelineCI.pRasterizationState = &rsCI; // Dynamic State 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; // Depth Stencil State DepthStencilStateDescription vdDssDesc = description.DepthStencilState; VkPipelineDepthStencilStateCreateInfo dssCI = VkPipelineDepthStencilStateCreateInfo.New(); dssCI.depthWriteEnable = vdDssDesc.DepthWriteEnabled; dssCI.depthTestEnable = vdDssDesc.DepthTestEnabled; dssCI.depthCompareOp = VkFormats.VdToVkCompareOp(vdDssDesc.ComparisonKind); pipelineCI.pDepthStencilState = &dssCI; // Multisample VkPipelineMultisampleStateCreateInfo multisampleCI = VkPipelineMultisampleStateCreateInfo.New(); multisampleCI.rasterizationSamples = VkSampleCountFlags.Count1; pipelineCI.pMultisampleState = &multisampleCI; // Input Assembly VkPipelineInputAssemblyStateCreateInfo inputAssemblyCI = VkPipelineInputAssemblyStateCreateInfo.New(); inputAssemblyCI.topology = VkFormats.VdToVkPrimitiveTopology(description.PrimitiveTopology); pipelineCI.pInputAssemblyState = &inputAssemblyCI; // Vertex Input State VkPipelineVertexInputStateCreateInfo vertexInputCI = VkPipelineVertexInputStateCreateInfo.New(); VertexLayoutDescription[] inputDescriptions = description.ShaderSet.VertexLayouts; uint bindingCount = (uint)inputDescriptions.Length; uint attributeCount = 0; for (int i = 0; i < inputDescriptions.Length; i++) { attributeCount += (uint)inputDescriptions[i].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++) { VertexLayoutDescription inputDesc = inputDescriptions[binding]; bindingDescs[targetIndex] = new VkVertexInputBindingDescription() { binding = (uint)binding, inputRate = (inputDesc.Elements[0].InstanceStepRate != 0) ? VkVertexInputRate.Instance : VkVertexInputRate.Vertex, stride = inputDesc.Stride }; uint currentOffset = 0; for (int location = 0; location < inputDesc.Elements.Length; location++) { VertexElementDescription inputElement = inputDesc.Elements[location]; attributeDescs[targetIndex] = new VkVertexInputAttributeDescription() { format = VkFormats.VdToVkVertexElementFormat(inputElement.Format), binding = (uint)binding, location = (uint)(targetLocation + location), offset = currentOffset }; targetIndex += 1; currentOffset += FormatHelpers.GetSizeInBytes(inputElement.Format); } targetLocation += inputDesc.Elements.Length; } vertexInputCI.vertexBindingDescriptionCount = bindingCount; vertexInputCI.pVertexBindingDescriptions = bindingDescs; vertexInputCI.vertexAttributeDescriptionCount = attributeCount; vertexInputCI.pVertexAttributeDescriptions = attributeDescs; pipelineCI.pVertexInputState = &vertexInputCI; // Shader Stage ShaderStageDescription[] stageDescs = description.ShaderSet.ShaderStages; StackList <VkPipelineShaderStageCreateInfo> stages = new StackList <VkPipelineShaderStageCreateInfo>(); foreach (ShaderStageDescription stageDesc in stageDescs) { VkShader vkShader = Util.AssertSubtype <Shader, VkShader>(stageDesc.Shader); VkPipelineShaderStageCreateInfo stageCI = VkPipelineShaderStageCreateInfo.New(); stageCI.module = vkShader.ShaderModule; stageCI.stage = VkFormats.VdToVkShaderStages(stageDesc.Stage); stageCI.pName = CommonStrings.main; // Meh stages.Add(stageCI); } pipelineCI.stageCount = stages.Count; pipelineCI.pStages = (VkPipelineShaderStageCreateInfo *)stages.Data; // ViewportState VkPipelineViewportStateCreateInfo viewportStateCI = VkPipelineViewportStateCreateInfo.New(); viewportStateCI.viewportCount = 1; viewportStateCI.scissorCount = 1; pipelineCI.pViewportState = &viewportStateCI; // Pipeline Layout ResourceLayout[] resourceLayouts = description.ResourceLayouts; VkPipelineLayoutCreateInfo pipelineLayoutCI = VkPipelineLayoutCreateInfo.New(); pipelineLayoutCI.setLayoutCount = (uint)resourceLayouts.Length; VkDescriptorSetLayout *dsls = stackalloc VkDescriptorSetLayout[resourceLayouts.Length]; for (int i = 0; i < resourceLayouts.Length; i++) { dsls[i] = Util.AssertSubtype <ResourceLayout, VkResourceLayout>(resourceLayouts[i]).DescriptorSetLayout; } pipelineLayoutCI.pSetLayouts = dsls; vkCreatePipelineLayout(_gd.Device, ref pipelineLayoutCI, null, out _pipelineLayout); pipelineCI.layout = _pipelineLayout; // Create fake RenderPass for compatibility. VkRenderPassCreateInfo renderPassCI = VkRenderPassCreateInfo.New(); OutputDescription outputDesc = description.Outputs; if (outputDesc.ColorAttachments.Length > 1) { throw new NotImplementedException("Laziness"); } VkAttachmentDescription colorAttachmentDesc = new VkAttachmentDescription(); colorAttachmentDesc.format = outputDesc.ColorAttachments.Length > 0 ? VkFormats.VdToVkPixelFormat(outputDesc.ColorAttachments[0].Format) : 0; colorAttachmentDesc.samples = VkSampleCountFlags.Count1; colorAttachmentDesc.loadOp = VkAttachmentLoadOp.Clear; colorAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; colorAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; colorAttachmentDesc.initialLayout = VkImageLayout.Undefined; colorAttachmentDesc.finalLayout = VkImageLayout.PresentSrcKHR; VkAttachmentReference colorAttachmentRef = new VkAttachmentReference(); colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VkImageLayout.ColorAttachmentOptimal; VkAttachmentDescription depthAttachmentDesc = new VkAttachmentDescription(); VkAttachmentReference depthAttachmentRef = new VkAttachmentReference(); if (outputDesc.DepthAttachment != null) { depthAttachmentDesc.format = VkFormats.VdToVkPixelFormat(outputDesc.DepthAttachment.Value.Format, toDepthFormat: true); depthAttachmentDesc.samples = VkSampleCountFlags.Count1; depthAttachmentDesc.loadOp = VkAttachmentLoadOp.Clear; depthAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; depthAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; depthAttachmentDesc.initialLayout = VkImageLayout.Undefined; depthAttachmentDesc.finalLayout = VkImageLayout.DepthStencilAttachmentOptimal; depthAttachmentRef.attachment = outputDesc.ColorAttachments.Length == 0 ? 0u : 1u; depthAttachmentRef.layout = VkImageLayout.DepthStencilAttachmentOptimal; } VkSubpassDescription subpass = new VkSubpassDescription(); StackList <VkAttachmentDescription, Size512Bytes> attachments = new StackList <VkAttachmentDescription, Size512Bytes>(); subpass.pipelineBindPoint = VkPipelineBindPoint.Graphics; if (outputDesc.ColorAttachments.Length > 0) { subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; attachments.Add(colorAttachmentDesc); } if (outputDesc.DepthAttachment != null) { subpass.pDepthStencilAttachment = &depthAttachmentRef; attachments.Add(depthAttachmentDesc); } VkSubpassDependency subpassDependency = new VkSubpassDependency(); subpassDependency.srcSubpass = SubpassExternal; subpassDependency.srcStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; if (outputDesc.DepthAttachment != null) { subpassDependency.dstAccessMask |= VkAccessFlags.DepthStencilAttachmentRead | VkAccessFlags.DepthStencilAttachmentWrite; } renderPassCI.attachmentCount = attachments.Count; renderPassCI.pAttachments = (VkAttachmentDescription *)attachments.Data; renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpass; renderPassCI.dependencyCount = 1; renderPassCI.pDependencies = &subpassDependency; VkResult creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPass); CheckResult(creationResult); pipelineCI.renderPass = _renderPass; VkResult result = vkCreateGraphicsPipelines(_gd.Device, VkPipelineCache.Null, 1, ref pipelineCI, null, out _devicePipeline); CheckResult(result); ResourceSetCount = (uint)description.ResourceLayouts.Length; }
public FGraphicsPipeline(VkDevice device, VkPhysicalDevice physicalDevice, VkPipelineCache pipelineCache, VkRenderPass renderPass, string shaderPath, uint swapchainImageCount, FTexture textureArray) { this.device = device; this.swapchainImageCount = swapchainImageCount; this.renderPass = renderPass; desclayout = CreateDescriptorLayout(device, 1); descriptorPool = CreateDescriptorPool(device, swapchainImageCount, 7); descriptorSets = AllocateDescriptorSets(device, desclayout, descriptorPool, swapchainImageCount); sampler = CreateSampler(device, textureArray.MipLevels); for (int i = 0; i < swapchainImageCount; i++) { VkDescriptorImageInfo imageInfo = new VkDescriptorImageInfo(); imageInfo.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; imageInfo.imageView = textureArray.imageView; imageInfo.sampler = sampler; VkWriteDescriptorSet[] writes = new VkWriteDescriptorSet[1]; writes[0].dstSet = descriptorSets[i]; writes[0].dstBinding = 0; writes[0].dstArrayElement = 0; writes[0].descriptorType = VkDescriptorType.CombinedImageSampler; writes[0].descriptorCount = 1; writes[0].pImageInfo = &imageInfo; fixed(VkWriteDescriptorSet *ptr = writes) vkUpdateDescriptorSets(device, (uint)writes.Length, ptr, 0, null); } uniformdata = CreateUniformBuffer(device, physicalDevice, 1); VkShaderModule vs = LoadShader(device, $"{shaderPath}.vert.spv"); VkShaderModule fs = LoadShader(device, $"{shaderPath}.frag.spv"); VkGraphicsPipelineCreateInfo pCreateInfo = VkGraphicsPipelineCreateInfo.New(); pCreateInfo.flags = VkPipelineCreateFlags.DisableOptimization; VkPipelineShaderStageCreateInfo[] shaderStages = new VkPipelineShaderStageCreateInfo[2]; shaderStages[0] = VkPipelineShaderStageCreateInfo.New(); shaderStages[0].stage = VkShaderStageFlags.Vertex; shaderStages[0].module = vs; byte[] vsFuncName = Encoding.UTF8.GetBytes("main" + char.MinValue); fixed(byte *ptr = &(vsFuncName[0])) shaderStages[0].pName = ptr; shaderStages[1] = VkPipelineShaderStageCreateInfo.New(); shaderStages[1].stage = VkShaderStageFlags.Fragment; shaderStages[1].module = fs; byte[] fsFuncName = Encoding.UTF8.GetBytes("main" + char.MinValue); fixed(byte *ptr = &(fsFuncName[0])) shaderStages[1].pName = ptr; fixed(VkPipelineShaderStageCreateInfo *ptr = shaderStages) pCreateInfo.pStages = ptr; pCreateInfo.stageCount = 2; VkVertexInputBindingDescription[] bindings = new VkVertexInputBindingDescription[4]; bindings[0] = new VkVertexInputBindingDescription(); bindings[0].binding = 0; bindings[0].stride = (uint)sizeof(VoxelRenderer.VoxelVertex); bindings[0].inputRate = VkVertexInputRate.Vertex; bindings[1] = new VkVertexInputBindingDescription(); bindings[1].binding = 1; bindings[1].stride = (uint)sizeof(VoxelRenderer.VoxelVertex); bindings[1].inputRate = VkVertexInputRate.Vertex; bindings[2] = new VkVertexInputBindingDescription(); bindings[2].binding = 2; bindings[2].stride = (uint)sizeof(VoxelRenderer.VoxelVertex); bindings[2].inputRate = VkVertexInputRate.Vertex; bindings[3] = new VkVertexInputBindingDescription(); bindings[3].binding = 3; bindings[3].stride = (uint)sizeof(VoxelRenderer.VoxelVertex); bindings[3].inputRate = VkVertexInputRate.Vertex; VkVertexInputAttributeDescription[] attribs = new VkVertexInputAttributeDescription[4]; attribs[0].binding = 0; attribs[0].location = 0; attribs[0].format = VkFormat.R32g32b32Sfloat; attribs[0].offset = 0; attribs[1].binding = 1; attribs[1].location = 1; attribs[1].format = VkFormat.R32g32b32Sfloat; attribs[1].offset = 0; attribs[2].binding = 2; attribs[2].location = 2; attribs[2].format = VkFormat.R32g32b32Sfloat; attribs[2].offset = 0; attribs[3].binding = 3; attribs[3].location = 3; attribs[3].format = VkFormat.R32Uint; attribs[3].offset = 0; VkPipelineVertexInputStateCreateInfo vertexInput = VkPipelineVertexInputStateCreateInfo.New(); fixed(VkVertexInputBindingDescription *ptr = bindings) vertexInput.pVertexBindingDescriptions = ptr; vertexInput.vertexBindingDescriptionCount = (uint)bindings.Length; fixed(VkVertexInputAttributeDescription *ptr = attribs) vertexInput.pVertexAttributeDescriptions = ptr; vertexInput.vertexAttributeDescriptionCount = (uint)attribs.Length; pCreateInfo.pVertexInputState = &vertexInput; VkPipelineInputAssemblyStateCreateInfo inputAssembly = VkPipelineInputAssemblyStateCreateInfo.New(); inputAssembly.topology = VkPrimitiveTopology.TriangleList; pCreateInfo.pInputAssemblyState = &inputAssembly; VkPipelineViewportStateCreateInfo viewportState = VkPipelineViewportStateCreateInfo.New(); viewportState.viewportCount = 1; viewportState.scissorCount = 1; pCreateInfo.pViewportState = &viewportState; VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo.New(); rasterizationState.lineWidth = 1; rasterizationState.frontFace = VkFrontFace.Clockwise; rasterizationState.cullMode = VkCullModeFlags.Back; rasterizationState.polygonMode = VkPolygonMode.Fill;//TODO add line debug render pCreateInfo.pRasterizationState = &rasterizationState; VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo.New(); multisampleState.rasterizationSamples = VkSampleCountFlags.Count1; pCreateInfo.pMultisampleState = &multisampleState; VkPipelineDepthStencilStateCreateInfo depthState = VkPipelineDepthStencilStateCreateInfo.New(); depthState.depthTestEnable = VkBool32.True; depthState.depthWriteEnable = VkBool32.True; depthState.depthCompareOp = VkCompareOp.Less; pCreateInfo.pDepthStencilState = &depthState; VkPipelineColorBlendAttachmentState colourAttachment = new VkPipelineColorBlendAttachmentState(); colourAttachment.colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A; VkPipelineColorBlendStateCreateInfo colourState = VkPipelineColorBlendStateCreateInfo.New(); colourState.pAttachments = &colourAttachment; colourState.attachmentCount = 1; pCreateInfo.pColorBlendState = &colourState; VkDynamicState[] dynamicStates = new VkDynamicState[2]; dynamicStates[0] = VkDynamicState.Viewport; dynamicStates[1] = VkDynamicState.Scissor; VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.New(); dynamicState.dynamicStateCount = (uint)dynamicStates.Length; fixed(VkDynamicState *ptr = &(dynamicStates[0])) dynamicState.pDynamicStates = ptr; pCreateInfo.pDynamicState = &dynamicState; this.pipelineLayout = CreatePipelineLayout(device, desclayout); pCreateInfo.layout = this.pipelineLayout; pCreateInfo.renderPass = renderPass; pCreateInfo.subpass = 0; VkPipeline pipeline = VkPipeline.Null; Assert(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pCreateInfo, null, &pipeline)); this.pipeline = pipeline; }
private VkPipeline CreateVulkanPipeline() { var pipelineShaderStageCreateInfos = stackalloc VkPipelineShaderStageCreateInfo[2]; uint pipelineShaderStageCreateInfosCount = 0; try { VkPipeline vulkanPipeline; var device = Device; var surface = device.Surface; var vertexInputBindingDescription = new VkVertexInputBindingDescription { inputRate = VK_VERTEX_INPUT_RATE_VERTEX, }; var vertexInputAttributeDescriptions = Array.Empty <VkVertexInputAttributeDescription>(); var pipelineVertexInputStateCreateInfo = new VkPipelineVertexInputStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, vertexBindingDescriptionCount = 1, pVertexBindingDescriptions = &vertexInputBindingDescription, }; var pipelineInputAssemblyStateCreateInfo = new VkPipelineInputAssemblyStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, }; var pipelineViewportStateCreateInfo = new VkPipelineViewportStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, viewportCount = 1, scissorCount = 1, }; var pipelineRasterizationStateCreateInfo = new VkPipelineRasterizationStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, frontFace = VK_FRONT_FACE_CLOCKWISE, cullMode = VK_CULL_MODE_BACK_BIT, lineWidth = 1.0f, }; var pipelineMultisampleStateCreateInfo = new VkPipelineMultisampleStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, }; var pipelineDepthStencilStateCreateInfo = new VkPipelineDepthStencilStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, depthCompareOp = VK_COMPARE_OP_ALWAYS, front = new VkStencilOpState { compareOp = VK_COMPARE_OP_ALWAYS, }, back = new VkStencilOpState { compareOp = VK_COMPARE_OP_ALWAYS, }, }; var pipelineColorBlendAttachmentState = new VkPipelineColorBlendAttachmentState { colorWriteMask = VK_COLOR_COMPONENT_A_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_R_BIT, }; var pipelineColorBlendStateCreateInfo = new VkPipelineColorBlendStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, attachmentCount = 1, pAttachments = &pipelineColorBlendAttachmentState, }; var dynamicStates = stackalloc VkDynamicState[2] { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, }; var pipelineDynamicStateCreateInfo = new VkPipelineDynamicStateCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, dynamicStateCount = 2, pDynamicStates = dynamicStates, }; var pipelineCreateInfo = new VkGraphicsPipelineCreateInfo { sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, pViewportState = &pipelineViewportStateCreateInfo, pRasterizationState = &pipelineRasterizationStateCreateInfo, pMultisampleState = &pipelineMultisampleStateCreateInfo, pDepthStencilState = &pipelineDepthStencilStateCreateInfo, pColorBlendState = &pipelineColorBlendStateCreateInfo, pDynamicState = &pipelineDynamicStateCreateInfo, layout = Signature.VulkanPipelineLayout, renderPass = device.VulkanRenderPass, }; var vertexShader = VertexShader; if (vertexShader != null) { var shaderIndex = pipelineShaderStageCreateInfosCount++; var entryPointName = vertexShader.EntryPointName.GetUtf8Span(); var entryPointNameLength = (nuint)entryPointName.Length + 1; pipelineShaderStageCreateInfos[shaderIndex] = new VkPipelineShaderStageCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, stage = VK_SHADER_STAGE_VERTEX_BIT, module = vertexShader.VulkanShaderModule, pName = AllocateArray <sbyte>(entryPointNameLength), }; var destination = new Span <sbyte>(pipelineShaderStageCreateInfos[shaderIndex].pName, (int)entryPointNameLength); entryPointName.CopyTo(destination); destination[entryPointName.Length] = 0x00; var inputs = Signature.Inputs; var inputsLength = inputs.Length; var inputElementsCount = GetInputElementsCount(inputs); var inputElementsIndex = 0; if (inputElementsCount != 0) { vertexInputAttributeDescriptions = new VkVertexInputAttributeDescription[inputElementsCount]; for (var inputIndex = 0; inputIndex < inputsLength; inputIndex++) { var input = inputs[inputIndex]; var inputElements = input.Elements; var inputElementsLength = inputElements.Length; uint inputBindingStride = 0; for (var inputElementIndex = 0; inputElementIndex < inputElementsLength; inputElementIndex++) { var inputElement = inputElements[inputElementIndex]; vertexInputAttributeDescriptions[inputElementsIndex] = new VkVertexInputAttributeDescription { location = unchecked ((uint)inputElementIndex), binding = unchecked ((uint)inputIndex), format = GetInputElementFormat(inputElement.Type), offset = inputBindingStride, }; inputBindingStride += inputElement.Size; inputElementsIndex++; } vertexInputBindingDescription.stride = inputBindingStride; } } pipelineCreateInfo.pVertexInputState = &pipelineVertexInputStateCreateInfo; pipelineCreateInfo.pInputAssemblyState = &pipelineInputAssemblyStateCreateInfo; } var pixelShader = PixelShader; if (pixelShader != null) { var shaderIndex = pipelineShaderStageCreateInfosCount++; var entryPointName = pixelShader.EntryPointName.GetUtf8Span(); var entryPointNameLength = (nuint)entryPointName.Length + 1; pipelineShaderStageCreateInfos[shaderIndex] = new VkPipelineShaderStageCreateInfo { sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, stage = VK_SHADER_STAGE_FRAGMENT_BIT, module = pixelShader.VulkanShaderModule, pName = AllocateArray <sbyte>(entryPointNameLength), }; var destination = new Span <sbyte>(pipelineShaderStageCreateInfos[shaderIndex].pName, (int)entryPointNameLength); entryPointName.CopyTo(destination); destination[entryPointName.Length] = 0x00; } if (pipelineShaderStageCreateInfosCount != 0) { pipelineCreateInfo.stageCount = pipelineShaderStageCreateInfosCount; pipelineCreateInfo.pStages = pipelineShaderStageCreateInfos; } fixed(VkVertexInputAttributeDescription *pVertexInputAttributeDescriptions = vertexInputAttributeDescriptions) { pipelineVertexInputStateCreateInfo.vertexAttributeDescriptionCount = unchecked ((uint)vertexInputAttributeDescriptions.Length); pipelineVertexInputStateCreateInfo.pVertexAttributeDescriptions = pVertexInputAttributeDescriptions; ThrowExternalExceptionIfNotSuccess(vkCreateGraphicsPipelines(device.VulkanDevice, pipelineCache: VK_NULL_HANDLE, 1, &pipelineCreateInfo, pAllocator: null, (ulong *)&vulkanPipeline), nameof(vkCreateGraphicsPipelines)); } return(vulkanPipeline); } finally { for (uint index = 0; index < pipelineShaderStageCreateInfosCount; index++) { var entryPointName = pipelineShaderStageCreateInfos[index].pName; Free(entryPointName); } }
public VkPipeline(VkGraphicsDevice gd, ref GraphicsPipelineDescription description) : base(ref description) { _gd = gd; IsComputePipeline = false; RefCount = new ResourceRefCount(DisposeCore); VkGraphicsPipelineCreateInfo pipelineCI = VkGraphicsPipelineCreateInfo.New(); // Blend State VkPipelineColorBlendStateCreateInfo blendStateCI = VkPipelineColorBlendStateCreateInfo.New(); int attachmentsCount = description.BlendState.AttachmentStates.Length; VkPipelineColorBlendAttachmentState *attachmentsPtr = stackalloc VkPipelineColorBlendAttachmentState[attachmentsCount]; for (int i = 0; i < attachmentsCount; i++) { BlendAttachmentDescription vdDesc = description.BlendState.AttachmentStates[i]; VkPipelineColorBlendAttachmentState attachmentState = new VkPipelineColorBlendAttachmentState(); attachmentState.srcColorBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.SourceColorFactor); attachmentState.dstColorBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.DestinationColorFactor); attachmentState.colorBlendOp = VkFormats.VdToVkBlendOp(vdDesc.ColorFunction); attachmentState.srcAlphaBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.SourceAlphaFactor); attachmentState.dstAlphaBlendFactor = VkFormats.VdToVkBlendFactor(vdDesc.DestinationAlphaFactor); attachmentState.alphaBlendOp = VkFormats.VdToVkBlendOp(vdDesc.AlphaFunction); attachmentState.blendEnable = vdDesc.BlendEnabled; attachmentState.colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A; attachmentsPtr[i] = attachmentState; } blendStateCI.attachmentCount = (uint)attachmentsCount; blendStateCI.pAttachments = attachmentsPtr; RgbaFloat blendFactor = description.BlendState.BlendFactor; blendStateCI.blendConstants_0 = blendFactor.R; blendStateCI.blendConstants_1 = blendFactor.G; blendStateCI.blendConstants_2 = blendFactor.B; blendStateCI.blendConstants_3 = blendFactor.A; pipelineCI.pColorBlendState = &blendStateCI; // Rasterizer State RasterizerStateDescription rsDesc = description.RasterizerState; VkPipelineRasterizationStateCreateInfo rsCI = VkPipelineRasterizationStateCreateInfo.New(); rsCI.cullMode = VkFormats.VdToVkCullMode(rsDesc.CullMode); rsCI.polygonMode = VkFormats.VdToVkPolygonMode(rsDesc.FillMode); rsCI.depthClampEnable = !rsDesc.DepthClipEnabled; rsCI.frontFace = rsDesc.FrontFace == FrontFace.Clockwise ? VkFrontFace.Clockwise : VkFrontFace.CounterClockwise; rsCI.lineWidth = 1f; pipelineCI.pRasterizationState = &rsCI; ScissorTestEnabled = rsDesc.ScissorTestEnabled; // Dynamic State 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; // Depth Stencil State DepthStencilStateDescription vdDssDesc = description.DepthStencilState; VkPipelineDepthStencilStateCreateInfo dssCI = VkPipelineDepthStencilStateCreateInfo.New(); dssCI.depthWriteEnable = vdDssDesc.DepthWriteEnabled; dssCI.depthTestEnable = vdDssDesc.DepthTestEnabled; dssCI.depthCompareOp = VkFormats.VdToVkCompareOp(vdDssDesc.DepthComparison); dssCI.stencilTestEnable = vdDssDesc.StencilTestEnabled; dssCI.front.failOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilFront.Fail); dssCI.front.passOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilFront.Pass); dssCI.front.depthFailOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilFront.DepthFail); dssCI.front.compareOp = VkFormats.VdToVkCompareOp(vdDssDesc.StencilFront.Comparison); dssCI.front.compareMask = vdDssDesc.StencilReadMask; dssCI.front.writeMask = vdDssDesc.StencilWriteMask; dssCI.front.reference = vdDssDesc.StencilReference; dssCI.back.failOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilBack.Fail); dssCI.back.passOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilBack.Pass); dssCI.back.depthFailOp = VkFormats.VdToVkStencilOp(vdDssDesc.StencilBack.DepthFail); dssCI.back.compareOp = VkFormats.VdToVkCompareOp(vdDssDesc.StencilBack.Comparison); dssCI.back.compareMask = vdDssDesc.StencilReadMask; dssCI.back.writeMask = vdDssDesc.StencilWriteMask; dssCI.back.reference = vdDssDesc.StencilReference; pipelineCI.pDepthStencilState = &dssCI; // Multisample VkPipelineMultisampleStateCreateInfo multisampleCI = VkPipelineMultisampleStateCreateInfo.New(); VkSampleCountFlags vkSampleCount = VkFormats.VdToVkSampleCount(description.Outputs.SampleCount); multisampleCI.rasterizationSamples = vkSampleCount; multisampleCI.alphaToCoverageEnable = description.BlendState.AlphaToCoverageEnabled; pipelineCI.pMultisampleState = &multisampleCI; // Input Assembly VkPipelineInputAssemblyStateCreateInfo inputAssemblyCI = VkPipelineInputAssemblyStateCreateInfo.New(); inputAssemblyCI.topology = VkFormats.VdToVkPrimitiveTopology(description.PrimitiveTopology); pipelineCI.pInputAssemblyState = &inputAssemblyCI; // Vertex Input State VkPipelineVertexInputStateCreateInfo vertexInputCI = VkPipelineVertexInputStateCreateInfo.New(); VertexLayoutDescription[] inputDescriptions = description.ShaderSet.VertexLayouts; uint bindingCount = (uint)inputDescriptions.Length; uint attributeCount = 0; for (int i = 0; i < inputDescriptions.Length; i++) { attributeCount += (uint)inputDescriptions[i].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++) { VertexLayoutDescription inputDesc = inputDescriptions[binding]; bindingDescs[binding] = new VkVertexInputBindingDescription() { binding = (uint)binding, inputRate = (inputDesc.InstanceStepRate != 0) ? VkVertexInputRate.Instance : VkVertexInputRate.Vertex, stride = inputDesc.Stride }; uint currentOffset = 0; for (int location = 0; location < inputDesc.Elements.Length; location++) { VertexElementDescription inputElement = inputDesc.Elements[location]; attributeDescs[targetIndex] = new VkVertexInputAttributeDescription() { format = VkFormats.VdToVkVertexElementFormat(inputElement.Format), binding = (uint)binding, location = (uint)(targetLocation + location), offset = inputElement.Offset != 0 ? inputElement.Offset : currentOffset }; targetIndex += 1; currentOffset += FormatHelpers.GetSizeInBytes(inputElement.Format); } targetLocation += inputDesc.Elements.Length; } vertexInputCI.vertexBindingDescriptionCount = bindingCount; vertexInputCI.pVertexBindingDescriptions = bindingDescs; vertexInputCI.vertexAttributeDescriptionCount = attributeCount; vertexInputCI.pVertexAttributeDescriptions = attributeDescs; pipelineCI.pVertexInputState = &vertexInputCI; // Shader Stage VkSpecializationInfo specializationInfo; SpecializationConstant[] specDescs = description.ShaderSet.Specializations; if (specDescs != null) { uint specDataSize = 0; foreach (SpecializationConstant spec in specDescs) { specDataSize += VkFormats.GetSpecializationConstantSize(spec.Type); } byte *fullSpecData = stackalloc byte[(int)specDataSize]; int specializationCount = specDescs.Length; VkSpecializationMapEntry *mapEntries = stackalloc VkSpecializationMapEntry[specializationCount]; uint specOffset = 0; for (int i = 0; i < specializationCount; i++) { ulong data = specDescs[i].Data; byte *srcData = (byte *)&data; uint dataSize = VkFormats.GetSpecializationConstantSize(specDescs[i].Type); Unsafe.CopyBlock(fullSpecData + specOffset, srcData, dataSize); mapEntries[i].constantID = specDescs[i].ID; mapEntries[i].offset = specOffset; mapEntries[i].size = (UIntPtr)dataSize; specOffset += dataSize; } specializationInfo.dataSize = (UIntPtr)specDataSize; specializationInfo.pData = fullSpecData; specializationInfo.mapEntryCount = (uint)specializationCount; specializationInfo.pMapEntries = mapEntries; } Shader[] shaders = description.ShaderSet.Shaders; StackList <VkPipelineShaderStageCreateInfo> stages = new StackList <VkPipelineShaderStageCreateInfo>(); foreach (Shader shader in shaders) { VkShader vkShader = Util.AssertSubtype <Shader, VkShader>(shader); VkPipelineShaderStageCreateInfo stageCI = VkPipelineShaderStageCreateInfo.New(); stageCI.module = vkShader.ShaderModule; stageCI.stage = VkFormats.VdToVkShaderStages(shader.Stage); // stageCI.pName = CommonStrings.main; // Meh stageCI.pName = new FixedUtf8String(shader.EntryPoint); // TODO: DONT ALLOCATE HERE stageCI.pSpecializationInfo = &specializationInfo; stages.Add(stageCI); } pipelineCI.stageCount = stages.Count; pipelineCI.pStages = (VkPipelineShaderStageCreateInfo *)stages.Data; // ViewportState VkPipelineViewportStateCreateInfo viewportStateCI = VkPipelineViewportStateCreateInfo.New(); viewportStateCI.viewportCount = 1; viewportStateCI.scissorCount = 1; pipelineCI.pViewportState = &viewportStateCI; // Pipeline Layout ResourceLayout[] resourceLayouts = description.ResourceLayouts; VkPipelineLayoutCreateInfo pipelineLayoutCI = VkPipelineLayoutCreateInfo.New(); pipelineLayoutCI.setLayoutCount = (uint)resourceLayouts.Length; VkDescriptorSetLayout *dsls = stackalloc VkDescriptorSetLayout[resourceLayouts.Length]; for (int i = 0; i < resourceLayouts.Length; i++) { dsls[i] = Util.AssertSubtype <ResourceLayout, VkResourceLayout>(resourceLayouts[i]).DescriptorSetLayout; } pipelineLayoutCI.pSetLayouts = dsls; vkCreatePipelineLayout(_gd.Device, ref pipelineLayoutCI, null, out _pipelineLayout); pipelineCI.layout = _pipelineLayout; // Create fake RenderPass for compatibility. VkRenderPassCreateInfo renderPassCI = VkRenderPassCreateInfo.New(); OutputDescription outputDesc = description.Outputs; StackList <VkAttachmentDescription, Size512Bytes> attachments = new StackList <VkAttachmentDescription, Size512Bytes>(); // TODO: A huge portion of this next part is duplicated in VkFramebuffer.cs. StackList <VkAttachmentDescription> colorAttachmentDescs = new StackList <VkAttachmentDescription>(); StackList <VkAttachmentReference> colorAttachmentRefs = new StackList <VkAttachmentReference>(); for (uint i = 0; i < outputDesc.ColorAttachments.Length; i++) { colorAttachmentDescs[i].format = VkFormats.VdToVkPixelFormat(outputDesc.ColorAttachments[i].Format); colorAttachmentDescs[i].samples = vkSampleCount; colorAttachmentDescs[i].loadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDescs[i].storeOp = VkAttachmentStoreOp.Store; colorAttachmentDescs[i].stencilLoadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDescs[i].stencilStoreOp = VkAttachmentStoreOp.DontCare; colorAttachmentDescs[i].initialLayout = VkImageLayout.Undefined; colorAttachmentDescs[i].finalLayout = VkImageLayout.ShaderReadOnlyOptimal; attachments.Add(colorAttachmentDescs[i]); colorAttachmentRefs[i].attachment = i; colorAttachmentRefs[i].layout = VkImageLayout.ColorAttachmentOptimal; } VkAttachmentDescription depthAttachmentDesc = new VkAttachmentDescription(); VkAttachmentReference depthAttachmentRef = new VkAttachmentReference(); if (outputDesc.DepthAttachment != null) { PixelFormat depthFormat = outputDesc.DepthAttachment.Value.Format; bool hasStencil = FormatHelpers.IsStencilFormat(depthFormat); depthAttachmentDesc.format = VkFormats.VdToVkPixelFormat(outputDesc.DepthAttachment.Value.Format, toDepthFormat: true); depthAttachmentDesc.samples = vkSampleCount; depthAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; depthAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.stencilStoreOp = hasStencil ? VkAttachmentStoreOp.Store : VkAttachmentStoreOp.DontCare; depthAttachmentDesc.initialLayout = VkImageLayout.Undefined; depthAttachmentDesc.finalLayout = VkImageLayout.DepthStencilAttachmentOptimal; depthAttachmentRef.attachment = (uint)outputDesc.ColorAttachments.Length; depthAttachmentRef.layout = VkImageLayout.DepthStencilAttachmentOptimal; } VkSubpassDescription subpass = new VkSubpassDescription(); subpass.pipelineBindPoint = VkPipelineBindPoint.Graphics; subpass.colorAttachmentCount = (uint)outputDesc.ColorAttachments.Length; subpass.pColorAttachments = (VkAttachmentReference *)colorAttachmentRefs.Data; for (int i = 0; i < colorAttachmentDescs.Count; i++) { attachments.Add(colorAttachmentDescs[i]); } if (outputDesc.DepthAttachment != null) { subpass.pDepthStencilAttachment = &depthAttachmentRef; attachments.Add(depthAttachmentDesc); } VkSubpassDependency subpassDependency = new VkSubpassDependency(); subpassDependency.srcSubpass = SubpassExternal; subpassDependency.srcStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; renderPassCI.attachmentCount = attachments.Count; renderPassCI.pAttachments = (VkAttachmentDescription *)attachments.Data; renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpass; renderPassCI.dependencyCount = 1; renderPassCI.pDependencies = &subpassDependency; VkResult creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPass); CheckResult(creationResult); pipelineCI.renderPass = _renderPass; VkResult result = vkCreateGraphicsPipelines(_gd.Device, VkPipelineCache.Null, 1, ref pipelineCI, null, out _devicePipeline); CheckResult(result); ResourceSetCount = (uint)description.ResourceLayouts.Length; DynamicOffsetsCount = 0; foreach (VkResourceLayout layout in description.ResourceLayouts) { DynamicOffsetsCount += layout.DynamicBufferCount; } }
public Pipeline Build() { var stages = _stages.ToArray(); var vertexBindings = new VkVertexInputBindingDescription[_vertexBindingDescriptions.Count]; { var i = 0; foreach (var kv in _vertexBindingDescriptions) { vertexBindings[i++] = kv.Value; } } var attributeBindings = new VkVertexInputAttributeDescription[_vertexAttributeDescriptions.Count]; { var i = 0; foreach (var kv in _vertexAttributeDescriptions) { attributeBindings[i++] = kv.Value; } } var blendStates = new VkPipelineColorBlendAttachmentState[_blendAttachmentStates.Count]; foreach (var kv in _blendAttachmentStates) { blendStates[kv.Key] = kv.Value; } var viewports = _viewports.ToArray(); var scissors = _viewportScissors.ToArray(); var dynamicStates = _dynamicStates.ToArray(); try { unsafe { fixed(VkViewport *viewportPtr = viewports) fixed(VkRect2D * scissorPtr = scissors) fixed(VkDynamicState * dynamicPtr = dynamicStates) fixed(VkPipelineColorBlendAttachmentState * blendPtr = blendStates) fixed(VkVertexInputBindingDescription * vertexPtr = vertexBindings) fixed(VkVertexInputAttributeDescription * attributePtr = attributeBindings) fixed(VkPipelineShaderStageCreateInfo * stagePtr = stages) { if (_basePipeline != null) { _flags |= VkPipelineCreateFlag.Derivative; } else { _flags &= ~VkPipelineCreateFlag.Derivative; } var vertexInputState = new VkPipelineVertexInputStateCreateInfo() { SType = VkStructureType.PipelineVertexInputStateCreateInfo, PNext = IntPtr.Zero, Flags = 0, VertexBindingDescriptionCount = (uint)vertexBindings.Length, PVertexBindingDescriptions = vertexPtr, VertexAttributeDescriptionCount = (uint)attributeBindings.Length, PVertexAttributeDescriptions = attributePtr }; var assemblyState = _asmInfo; var tessState = _tessInfo; var viewportState = new VkPipelineViewportStateCreateInfo() { SType = VkStructureType.PipelineViewportStateCreateInfo, PNext = IntPtr.Zero, Flags = 0, ViewportCount = (uint)viewports.Length, PViewports = viewportPtr, ScissorCount = (uint)scissors.Length, PScissors = scissorPtr }; var rasterState = _rasterInfo; var multisampleState = _multisampleInfo; var depthStencilState = _depthStencilInfo; var colorBlendState = _colorBlendInfo; colorBlendState.AttachmentCount = (uint)blendStates.Length; colorBlendState.PAttachments = blendPtr; var dynamicState = new VkPipelineDynamicStateCreateInfo() { SType = VkStructureType.PipelineDynamicStateCreateInfo, PNext = IntPtr.Zero, Flags = 0, DynamicStateCount = (uint)dynamicStates.Length, PDynamicStates = dynamicPtr }; var info = new VkGraphicsPipelineCreateInfo() { SType = VkStructureType.GraphicsPipelineCreateInfo, PNext = IntPtr.Zero, Flags = _flags, StageCount = (uint)stages.Length, PStages = stagePtr, PVertexInputState = &vertexInputState, PInputAssemblyState = &assemblyState, PTessellationState = &tessState, PViewportState = &viewportState, PRasterizationState = &rasterState, PMultisampleState = &multisampleState, PDepthStencilState = &depthStencilState, PColorBlendState = &colorBlendState, PDynamicState = dynamicStates.Length > 0 ? &dynamicState : (VkPipelineDynamicStateCreateInfo *)0, Layout = _pipelineLayout.Handle, RenderPass = _pass.Handle, Subpass = _subpassId, BasePipelineHandle = _basePipeline?.Handle ?? VkPipeline.Null, BasePipelineIndex = _basePipelineIndex }; VkPipeline result = VkPipeline.Null; VkException.Check(VkDevice.vkCreateGraphicsPipelines(_pass.Device.Handle, VkPipelineCache.Null, 1, &info, _pass.Instance.AllocationCallbacks, &result)); Debug.Assert(result != VkPipeline.Null); return(new Pipeline(_pass.Device, VkPipelineBindPoint.Graphics, _pipelineLayout, result)); } } } finally { foreach (var pin in _pins) { pin.Free(); } foreach (var strPin in _strPins) { Marshal.FreeHGlobal(strPin); } } }