Example #1
0
        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;
 }
Example #3
0
        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;
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        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));
            }
        }
Example #9
0
        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);
        }