public DescriptorSetUpdater(VulkanRenderer gd, PipelineBase pipeline) { _gd = gd; _pipeline = pipeline; // Some of the bindings counts needs to be multiplied by 2 because we have buffer and // regular textures/images interleaved on the same descriptor set. _uniformBufferRefs = new Auto <DisposableBuffer> [Constants.MaxUniformBufferBindings]; _storageBufferRefs = new Auto <DisposableBuffer> [Constants.MaxStorageBufferBindings]; _textureRefs = new Auto <DisposableImageView> [Constants.MaxTextureBindings * 2]; _samplerRefs = new Auto <DisposableSampler> [Constants.MaxTextureBindings * 2]; _imageRefs = new Auto <DisposableImageView> [Constants.MaxImageBindings * 2]; _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2]; _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2]; _bufferImageFormats = new GAL.Format[Constants.MaxImageBindings * 2]; _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings]; _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings]; _textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage]; _images = new DescriptorImageInfo[Constants.MaxImagesPerStage]; _bufferTextures = new BufferView[Constants.MaxTexturesPerStage]; _bufferImages = new BufferView[Constants.MaxImagesPerStage]; var initialImageInfo = new DescriptorImageInfo() { ImageLayout = ImageLayout.General }; _textures.AsSpan().Fill(initialImageInfo); _images.AsSpan().Fill(initialImageInfo); _uniformSet = new bool[Constants.MaxUniformBufferBindings]; _storageSet = new bool[Constants.MaxStorageBufferBindings]; if (gd.Capabilities.SupportsNullDescriptors) { // If null descriptors are supported, we can pass null as the handle. _dummyBuffer = null; } else { // If null descriptors are not supported, we need to pass the handle of a dummy buffer on unused bindings. _dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true); } _dummyTexture = gd.CreateTextureView(new GAL.TextureCreateInfo( 1, 1, 1, 1, 1, 1, 1, 4, GAL.Format.R8G8B8A8Unorm, DepthStencilMode.Depth, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha), 1f); _dummySampler = (SamplerHolder)gd.CreateSampler(new GAL.SamplerCreateInfo( MinFilter.Nearest, MagFilter.Nearest, false, AddressMode.Repeat, AddressMode.Repeat, AddressMode.Repeat, CompareMode.None, GAL.CompareOp.Always, new ColorF(0, 0, 0, 0), 0, 0, 0, 1f)); }
public PipelineLayoutCacheEntry(VulkanRenderer gd, Device device, uint stages, bool usePd) : this(gd, device) { DescriptorSetLayouts = PipelineLayoutFactory.Create(gd, device, stages, usePd, out var pipelineLayout); PipelineLayout = pipelineLayout; }
public TextureView( VulkanRenderer gd, Device device, TextureCreateInfo info, TextureStorage storage, int firstLayer, int firstLevel) { _gd = gd; _device = device; _info = info; Storage = storage; FirstLayer = firstLayer; FirstLevel = firstLevel; storage.IncrementViewsCount(); gd.Textures.Add(this); var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); VkFormat = format; var type = info.Target.ConvertView(); var swizzleR = info.SwizzleR.Convert(); var swizzleG = info.SwizzleG.Convert(); var swizzleB = info.SwizzleB.Convert(); var swizzleA = info.SwizzleA.Convert(); if (info.Format == GAL.Format.R5G5B5A1Unorm || info.Format == GAL.Format.R5G5B5X1Unorm || info.Format == GAL.Format.R5G6B5Unorm) { var temp = swizzleR; swizzleR = swizzleB; swizzleB = temp; } else if (info.Format == GAL.Format.R4G4B4A4Unorm) { var tempG = swizzleG; var tempB = swizzleB; swizzleB = swizzleA; swizzleG = swizzleR; swizzleR = tempG; swizzleA = tempB; } else if (info.Format == GAL.Format.A1B5G5R5Unorm) { var tempB = swizzleB; var tempA = swizzleA; swizzleB = swizzleG; swizzleA = swizzleR; swizzleR = tempA; swizzleG = tempB; } var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA); var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode); var aspectFlagsDepth = info.Format.ConvertAspectFlags(DepthStencilMode.Depth); var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers); var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers); unsafe Auto <DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType) { var imageCreateInfo = new ImageViewCreateInfo() { SType = StructureType.ImageViewCreateInfo, Image = storage.GetImageForViewCreation(), ViewType = viewType, Format = format, Components = cm, SubresourceRange = sr }; gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError(); return(new Auto <DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage())); } _imageView = CreateImageView(componentMapping, subresourceRange, type); // Framebuffer attachments and storage images requires a identity component mapping. var identityComponentMapping = new ComponentMapping( ComponentSwizzle.R, ComponentSwizzle.G, ComponentSwizzle.B, ComponentSwizzle.A); _imageViewIdentity = CreateImageView(identityComponentMapping, subresourceRangeDepth, type); // Framebuffer attachments also require 3D textures to be bound as 2D array. if (info.Target == Target.Texture3D) { subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth); _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray); } Valid = true; }
private static void BlitDepthStencilWithBuffer( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, Extents2D srcRegion, Extents2D dstRegion) { int drBaseX = Math.Min(dstRegion.X1, dstRegion.X2); int drBaseY = Math.Min(dstRegion.Y1, dstRegion.Y2); int drWidth = Math.Abs(dstRegion.X2 - dstRegion.X1); int drHeight = Math.Abs(dstRegion.Y2 - dstRegion.Y1); var drOriginZero = new Extents2D( dstRegion.X1 - drBaseX, dstRegion.Y1 - drBaseY, dstRegion.X2 - drBaseX, dstRegion.Y2 - drBaseY); var d32SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.D32Float, 4); var d32DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.D32Float, 4, drWidth, drHeight); var s8SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.S8Uint, 1); var s8DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.S8Uint, 1, drWidth, drHeight); using var d32SrcStorage = gd.CreateTextureStorage(d32SrcStorageInfo, src.Storage.ScaleFactor); using var d32DstStorage = gd.CreateTextureStorage(d32DstStorageInfo, dst.Storage.ScaleFactor); using var s8SrcStorage = gd.CreateTextureStorage(s8SrcStorageInfo, src.Storage.ScaleFactor); using var s8DstStorage = gd.CreateTextureStorage(s8DstStorageInfo, dst.Storage.ScaleFactor); void SlowBlit(TextureStorage srcTemp, TextureStorage dstTemp, ImageAspectFlags aspectFlags) { int levels = Math.Min(src.Info.Levels, dst.Info.Levels); int srcSize = 0; int dstSize = 0; for (int l = 0; l < levels; l++) { srcSize += srcTemp.Info.GetMipSize2D(l); dstSize += dstTemp.Info.GetMipSize2D(l); } using var srcTempBuffer = gd.BufferManager.Create(gd, srcSize, deviceLocal: true); using var dstTempBuffer = gd.BufferManager.Create(gd, dstSize, deviceLocal: true); src.Storage.CopyFromOrToBuffer( cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, src.GetImage().Get(cbs).Value, srcSize, to: true, 0, 0, src.FirstLayer, src.FirstLevel, 1, levels, true, aspectFlags, false); BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, 0, srcSize); srcTemp.CopyFromOrToBuffer( cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, srcTemp.GetImage().Get(cbs).Value, srcSize, to: false, 0, 0, 0, 0, 1, levels, true, aspectFlags, false); InsertImageBarrier( gd.Api, cbs.CommandBuffer, srcTemp.GetImage().Get(cbs).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, aspectFlags, 0, 0, 1, levels); TextureCopy.Blit( gd.Api, cbs.CommandBuffer, srcTemp.GetImage().Get(cbs).Value, dstTemp.GetImage().Get(cbs).Value, srcTemp.Info, dstTemp.Info, srcRegion, drOriginZero, 0, 0, 0, 0, 1, levels, false, aspectFlags, aspectFlags); InsertImageBarrier( gd.Api, cbs.CommandBuffer, dstTemp.GetImage().Get(cbs).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, aspectFlags, 0, 0, 1, levels); dstTemp.CopyFromOrToBuffer( cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, dstTemp.GetImage().Get(cbs).Value, dstSize, to: true, 0, 0, 0, 0, 1, levels, true, aspectFlags, false); BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, 0, dstSize); dst.Storage.CopyFromOrToBuffer( cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, dst.GetImage().Get(cbs).Value, dstSize, to: false, drBaseX, drBaseY, dst.FirstLayer, dst.FirstLevel, 1, levels, true, aspectFlags, false); } SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit); SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit); }
private static void CopyMSToNonMS( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, Image srcImage, Image dstImage, int srcLayer, int dstLayer, int srcLevel, int dstLevel, int layers, int levels) { bool differentFormats = src.Info.Format != dst.Info.Format; var target = src.Info.Target switch { Target.Texture2D => Target.Texture2DMultisample, Target.Texture2DArray => Target.Texture2DMultisampleArray, Target.Texture2DMultisampleArray => Target.Texture2DArray, _ => Target.Texture2D }; var intermmediateTarget = differentFormats ? dst.Info.Target : target; using var intermmediate = CreateIntermmediateTexture(gd, src, ref dst._info, intermmediateTarget, layers, levels); var intermmediateImage = intermmediate.GetImage().Get(cbs).Value; if (differentFormats) { // If the formats are different, the resolve would perform format conversion. // So we need yet another intermmediate texture and do a copy to reinterpret the // data into the correct (destination) format, without doing any sort of conversion. using var intermmediate2 = CreateIntermmediateTexture(gd, src, ref src._info, target, layers, levels); var intermmediate2Image = intermmediate2.GetImage().Get(cbs).Value; TextureCopy.Copy( gd.Api, cbs.CommandBuffer, srcImage, intermmediate2Image, src.Info, intermmediate2.Info, src.FirstLayer, 0, src.FirstLevel, 0, srcLayer, 0, srcLevel, 0, layers, levels); TextureCopy.Copy( gd.Api, cbs.CommandBuffer, intermmediate2Image, intermmediateImage, intermmediate2.Info, intermmediate.Info, 0, 0, 0, 0, 0, 0, 0, 0, layers, levels); } else { TextureCopy.Copy( gd.Api, cbs.CommandBuffer, srcImage, intermmediateImage, src.Info, intermmediate.Info, src.FirstLayer, 0, src.FirstLevel, 0, srcLayer, 0, srcLevel, 0, layers, levels); } var srcRegion = new Extents2D(0, 0, src.Width, src.Height); var dstRegion = new Extents2D(0, 0, dst.Width, dst.Height); TextureCopy.Blit( gd.Api, cbs.CommandBuffer, intermmediateImage, dstImage, intermmediate.Info, dst.Info, srcRegion, dstRegion, 0, dst.FirstLevel + dstLevel, 0, dst.FirstLayer + dstLayer, layers, levels, true, ImageAspectFlags.ImageAspectColorBit, ImageAspectFlags.ImageAspectColorBit); }
public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout) { int stagesCount = BitOperations.PopCount(stages); int uCount = Constants.MaxUniformBuffersPerStage * stagesCount + 1; int tCount = Constants.MaxTexturesPerStage * 2 * stagesCount; int iCount = Constants.MaxImagesPerStage * 2 * stagesCount; DescriptorSetLayoutBinding *uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount]; DescriptorSetLayoutBinding *sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount]; DescriptorSetLayoutBinding *tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount]; DescriptorSetLayoutBinding *iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount]; uLayoutBindings[0] = new DescriptorSetLayoutBinding { Binding = 0, DescriptorType = DescriptorType.UniformBuffer, DescriptorCount = 1, StageFlags = SupportBufferStages }; int iter = 0; while (stages != 0) { int stage = BitOperations.TrailingZeroCount(stages); stages &= ~(1u << stage); var stageFlags = stage switch { 1 => ShaderStageFlags.ShaderStageFragmentBit, 2 => ShaderStageFlags.ShaderStageGeometryBit, 3 => ShaderStageFlags.ShaderStageTessellationControlBit, 4 => ShaderStageFlags.ShaderStageTessellationEvaluationBit, _ => ShaderStageFlags.ShaderStageVertexBit | ShaderStageFlags.ShaderStageComputeBit }; void Set(DescriptorSetLayoutBinding *bindings, int maxPerStage, DescriptorType type, int start, int skip) { int totalPerStage = maxPerStage * skip; for (int i = 0; i < maxPerStage; i++) { bindings[start + iter * totalPerStage + i] = new DescriptorSetLayoutBinding { Binding = (uint)(start + stage * totalPerStage + i), DescriptorType = type, DescriptorCount = 1, StageFlags = stageFlags }; } } void SetStorage(DescriptorSetLayoutBinding *bindings, int maxPerStage, int start = 0) { bindings[start + iter] = new DescriptorSetLayoutBinding { Binding = (uint)(start + stage * maxPerStage), DescriptorType = DescriptorType.StorageBuffer, DescriptorCount = (uint)maxPerStage, StageFlags = stageFlags }; } Set(uLayoutBindings, Constants.MaxUniformBuffersPerStage, DescriptorType.UniformBuffer, 1, 1); SetStorage(sLayoutBindings, Constants.MaxStorageBuffersPerStage); Set(tLayoutBindings, Constants.MaxTexturesPerStage, DescriptorType.CombinedImageSampler, 0, 2); Set(tLayoutBindings, Constants.MaxTexturesPerStage, DescriptorType.UniformTexelBuffer, Constants.MaxTexturesPerStage, 2); Set(iLayoutBindings, Constants.MaxImagesPerStage, DescriptorType.StorageImage, 0, 2); Set(iLayoutBindings, Constants.MaxImagesPerStage, DescriptorType.StorageTexelBuffer, Constants.MaxImagesPerStage, 2); iter++; } DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts]; var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = uLayoutBindings, BindingCount = (uint)uCount, Flags = usePd ? DescriptorSetLayoutCreateFlags.DescriptorSetLayoutCreatePushDescriptorBitKhr : 0 }; var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = sLayoutBindings, BindingCount = (uint)stagesCount }; var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = tLayoutBindings, BindingCount = (uint)tCount }; var iDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = iLayoutBindings, BindingCount = (uint)iCount }; gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError(); fixed(DescriptorSetLayout *pLayouts = layouts) { var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo() { SType = StructureType.PipelineLayoutCreateInfo, PSetLayouts = pLayouts, SetLayoutCount = PipelineFull.DescriptorSetLayouts }; gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); } return(layouts); }
public static unsafe DescriptorSetLayout[] CreateMinimal(VulkanRenderer gd, Device device, ShaderSource[] shaders, out PipelineLayout layout) { int stagesCount = shaders.Length; int uCount = 0; int tCount = 0; int iCount = 0; foreach (var shader in shaders) { uCount += shader.Bindings.UniformBufferBindings.Count; tCount += shader.Bindings.TextureBindings.Count; iCount += shader.Bindings.ImageBindings.Count; } DescriptorSetLayoutBinding *uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount]; DescriptorSetLayoutBinding *sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount]; DescriptorSetLayoutBinding *tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount]; DescriptorSetLayoutBinding *iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount]; int uIndex = 0; int sIndex = 0; int tIndex = 0; int iIndex = 0; foreach (var shader in shaders) { var stageFlags = shader.Stage.Convert(); void Set(DescriptorSetLayoutBinding *bindings, DescriptorType type, ref int start, IEnumerable <int> bds) { foreach (var b in bds) { bindings[start++] = new DescriptorSetLayoutBinding { Binding = (uint)b, DescriptorType = type, DescriptorCount = 1, StageFlags = stageFlags }; } } void SetStorage(DescriptorSetLayoutBinding *bindings, ref int start, int count) { bindings[start++] = new DescriptorSetLayoutBinding { Binding = (uint)start, DescriptorType = DescriptorType.StorageBuffer, DescriptorCount = (uint)count, StageFlags = stageFlags }; } // TODO: Support buffer textures and images here. // This is only used for the helper shaders on the backend, and we don't use buffer textures on them // so far, so it's not really necessary right now. Set(uLayoutBindings, DescriptorType.UniformBuffer, ref uIndex, shader.Bindings.UniformBufferBindings); SetStorage(sLayoutBindings, ref sIndex, shader.Bindings.StorageBufferBindings.Count); Set(tLayoutBindings, DescriptorType.CombinedImageSampler, ref tIndex, shader.Bindings.TextureBindings); Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings); } DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts]; var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = uLayoutBindings, BindingCount = (uint)uCount }; var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = sLayoutBindings, BindingCount = (uint)stagesCount }; var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = tLayoutBindings, BindingCount = (uint)tCount }; var iDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = iLayoutBindings, BindingCount = (uint)iCount }; gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError(); fixed(DescriptorSetLayout *pLayouts = layouts) { var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo() { SType = StructureType.PipelineLayoutCreateInfo, PSetLayouts = pLayouts, SetLayoutCount = PipelineFull.DescriptorSetLayouts }; gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); } return(layouts); }
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device) { const int MaxAttachments = Constants.MaxRenderTargets + 1; AttachmentDescription[] attachmentDescs = null; var subpass = new SubpassDescription() { PipelineBindPoint = PipelineBindPoint.Graphics }; AttachmentReference *attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; Span <int> attachmentIndices = stackalloc int[MaxAttachments]; Span <Silk.NET.Vulkan.Format> attachmentFormats = stackalloc Silk.NET.Vulkan.Format[MaxAttachments]; int attachmentCount = 0; int colorCount = 0; int maxColorAttachmentIndex = 0; for (int i = 0; i < state.AttachmentEnable.Length; i++) { if (state.AttachmentEnable[i]) { maxColorAttachmentIndex = i; attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]); attachmentIndices[attachmentCount++] = i; colorCount++; } } if (state.DepthStencilEnable) { attachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat); } if (attachmentCount != 0) { attachmentDescs = new AttachmentDescription[attachmentCount]; for (int i = 0; i < attachmentCount; i++) { int bindIndex = attachmentIndices[i]; attachmentDescs[i] = new AttachmentDescription( 0, attachmentFormats[i], TextureStorage.ConvertToSampleCountFlags((uint)state.SamplesCount), AttachmentLoadOp.Load, AttachmentStoreOp.Store, AttachmentLoadOp.Load, AttachmentStoreOp.Store, ImageLayout.General, ImageLayout.General); } int colorAttachmentsCount = colorCount; if (colorAttachmentsCount > MaxAttachments - 1) { colorAttachmentsCount = MaxAttachments - 1; } if (colorAttachmentsCount != 0) { int maxAttachmentIndex = Constants.MaxRenderTargets - 1; subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; subpass.PColorAttachments = &attachmentReferences[0]; // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. for (int i = 0; i <= maxAttachmentIndex; i++) { subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); } for (int i = 0; i < colorAttachmentsCount; i++) { int bindIndex = attachmentIndices[i]; subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); } } if (state.DepthStencilEnable) { uint dsIndex = (uint)attachmentCount - 1; subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); } } var subpassDependency = new SubpassDependency( 0, 0, PipelineStageFlags.PipelineStageAllGraphicsBit, PipelineStageFlags.PipelineStageAllGraphicsBit, AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, 0); fixed(AttachmentDescription *pAttachmentDescs = attachmentDescs) { var renderPassCreateInfo = new RenderPassCreateInfo() { SType = StructureType.RenderPassCreateInfo, PAttachments = pAttachmentDescs, AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, PSubpasses = &subpass, SubpassCount = 1, PDependencies = &subpassDependency, DependencyCount = 1 }; gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); return(new DisposableRenderPass(gd.Api, device, renderPass)); } }
public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd) { PipelineState pipeline = new PipelineState(); pipeline.Initialize(); // It is assumed that Dynamic State is enabled when this conversion is used. pipeline.BlendConstantA = state.BlendDescriptors[0].BlendConstant.Alpha; pipeline.BlendConstantB = state.BlendDescriptors[0].BlendConstant.Blue; pipeline.BlendConstantG = state.BlendDescriptors[0].BlendConstant.Green; pipeline.BlendConstantR = state.BlendDescriptors[0].BlendConstant.Red; pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone; pipeline.DepthBoundsTestEnable = false; // Not implemented. pipeline.DepthClampEnable = state.DepthClampEnable; pipeline.DepthTestEnable = state.DepthTest.TestEnable; pipeline.DepthWriteEnable = state.DepthTest.WriteEnable; pipeline.DepthCompareOp = state.DepthTest.Func.Convert(); pipeline.FrontFace = state.FrontFace.Convert(); pipeline.HasDepthStencil = state.DepthStencilEnable; pipeline.LineWidth = state.LineWidth; pipeline.LogicOpEnable = state.LogicOpEnable; pipeline.LogicOp = state.LogicOp.Convert(); pipeline.MinDepthBounds = 0f; // Not implemented. pipeline.MaxDepthBounds = 0f; // Not implemented. pipeline.PatchControlPoints = state.PatchControlPoints; pipeline.PolygonMode = Silk.NET.Vulkan.PolygonMode.Fill; // Not implemented. pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable; pipeline.RasterizerDiscardEnable = state.RasterizerDiscard; pipeline.SamplesCount = (uint)state.SamplesCount; if (gd.Capabilities.SupportsMultiView) { pipeline.ScissorsCount = Constants.MaxViewports; pipeline.ViewportsCount = Constants.MaxViewports; } else { pipeline.ScissorsCount = 1; pipeline.ViewportsCount = 1; } pipeline.DepthBiasEnable = state.BiasEnable != 0; // Stencil masks and ref are dynamic, so are 0 in the Vulkan pipeline. pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert(); pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert(); pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert(); pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert(); pipeline.StencilFrontCompareMask = 0; pipeline.StencilFrontWriteMask = 0; pipeline.StencilFrontReference = 0; pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert(); pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert(); pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert(); pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert(); pipeline.StencilBackCompareMask = 0; pipeline.StencilBackWriteMask = 0; pipeline.StencilBackReference = 0; pipeline.StencilTestEnable = state.StencilTest.TestEnable; pipeline.Topology = state.Topology.Convert(); int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); for (int i = 0; i < vaCount; i++) { var attribute = state.VertexAttribs[i]; var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1; pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription( (uint)i, (uint)bufferIndex, gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format), (uint)attribute.Offset); } int descriptorIndex = 1; pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex); int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount); for (int i = 0; i < vbCount; i++) { var vertexBuffer = state.VertexBuffers[i]; if (vertexBuffer.Enable) { var inputRate = vertexBuffer.Divisor != 0 ? VertexInputRate.Instance : VertexInputRate.Vertex; // TODO: Support divisor > 1 pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription( (uint)i + 1, (uint)vertexBuffer.Stride, inputRate); } } pipeline.VertexBindingDescriptionsCount = (uint)descriptorIndex; // NOTE: Viewports, Scissors are dynamic. for (int i = 0; i < 8; i++) { var blend = state.BlendDescriptors[i]; pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState( blend.Enable, blend.ColorSrcFactor.Convert(), blend.ColorDstFactor.Convert(), blend.ColorOp.Convert(), blend.AlphaSrcFactor.Convert(), blend.AlphaDstFactor.Convert(), blend.AlphaOp.Convert(), (ColorComponentFlags)state.ColorWriteMask[i]); } int maxAttachmentIndex = 0; for (int i = 0; i < 8; i++) { if (state.AttachmentEnable[i]) { pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]); } } if (state.DepthStencilEnable) { pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat); } pipeline.ColorBlendAttachmentStateCount = 8; pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); return(pipeline); }