public unsafe void AddGeometryAabb(
            VulkanScene scene,
            uint aabbOffset,
            uint aabbCount,
            bool isOpaque)
        {
            var geometry = new AccelerationStructureGeometryKHR();

            geometry.SType                = StructureType.AccelerationStructureGeometryKhr;
            geometry.PNext                = null;
            geometry.GeometryType         = GeometryTypeKHR.GeometryTypeAabbsKhr;
            geometry.Geometry.Aabbs.SType = StructureType.AccelerationStructureGeometryAabbsDataKhr;
            geometry.Geometry.Aabbs.PNext = null;
            geometry.Geometry.Aabbs.Data.DeviceAddress = scene.AabbBuffer.GetDeviceAddress();
            geometry.Geometry.Aabbs.Stride             = (ulong)sizeof(AabbPositionsKHR);
            geometry.Flags = isOpaque ? GeometryFlagsKHR.GeometryOpaqueBitKhr : 0;

            var buildOffsetInfo = new AccelerationStructureBuildRangeInfoKHR();

            buildOffsetInfo.FirstVertex     = 0;
            buildOffsetInfo.PrimitiveOffset = aabbOffset;
            buildOffsetInfo.PrimitiveCount  = aabbCount;
            buildOffsetInfo.TransformOffset = 0;

            _geometry.Add(geometry);
            _buildOffsetInfo.Add(buildOffsetInfo);
        }
        public unsafe void AddGeometryTriangles(
            VulkanScene scene,
            uint vertexOffset, uint vertexCount,
            uint indexOffset, uint indexCount,
            bool isOpaque)
        {
            var geometry = new AccelerationStructureGeometryKHR();

            geometry.SType                    = StructureType.AccelerationStructureGeometryKhr;
            geometry.PNext                    = null;
            geometry.GeometryType             = GeometryTypeKHR.GeometryTypeTrianglesKhr;
            geometry.Geometry.Triangles.SType = StructureType.AccelerationStructureGeometryTrianglesDataKhr;
            geometry.Geometry.Triangles.PNext = null;
            geometry.Geometry.Triangles.VertexData.DeviceAddress = scene.VertexBuffer.GetDeviceAddress();
            geometry.Geometry.Triangles.VertexStride             = (ulong)sizeof(Vertex);
            geometry.Geometry.Triangles.MaxVertex               = vertexCount;
            geometry.Geometry.Triangles.VertexFormat            = Format.R32G32B32Sfloat;
            geometry.Geometry.Triangles.IndexData.DeviceAddress = scene.IndexBuffer.GetDeviceAddress();
            geometry.Geometry.Triangles.IndexType               = IndexType.Uint32;
            geometry.Geometry.Triangles.TransformData           = default;
            geometry.Flags = isOpaque ? GeometryFlagsKHR.GeometryOpaqueBitKhr : 0;

            var buildOffsetInfo = new AccelerationStructureBuildRangeInfoKHR();

            buildOffsetInfo.FirstVertex     = vertexOffset / (uint)sizeof(Vertex);
            buildOffsetInfo.PrimitiveOffset = indexOffset;
            buildOffsetInfo.PrimitiveCount  = indexCount / 3;
            buildOffsetInfo.TransformOffset = 0;

            _geometry.Add(geometry);
            _buildOffsetInfo.Add(buildOffsetInfo);
        }
Ejemplo n.º 3
0
        public unsafe RayTracingPipeline(
            Api api,
            SwapChain swapChain,
            TopLevelAccelerationStructure accelerationStructure,
            ImageView accumulationImageView,
            ImageView outputImageView,
            List <UniformBuffer> uniformBuffers,
            VulkanScene scene)
        {
            (_api, _swapChain) = (api, swapChain);

            // Create descriptor pool/sets.
            var descriptorBindings = new DescriptorBinding[]
            {
                // Top level acceleration structure.
                new DescriptorBinding(0, 1, DescriptorType.AccelerationStructureKhr, ShaderStageFlags.ShaderStageRaygenBitKhr),

                // Image accumulation & output
                new DescriptorBinding(1, 1, DescriptorType.StorageImage, ShaderStageFlags.ShaderStageRaygenBitKhr),
                new DescriptorBinding(2, 1, DescriptorType.StorageImage, ShaderStageFlags.ShaderStageRaygenBitKhr),

                // Camera information & co
                new DescriptorBinding(3, 1, DescriptorType.UniformBuffer, ShaderStageFlags.ShaderStageRaygenBitKhr | ShaderStageFlags.ShaderStageMissBitKhr),

                // Vertex buffer, Index buffer, Material buffer, Offset buffer, Transform buffer
                new DescriptorBinding(4, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr),
                new DescriptorBinding(5, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr),
                new DescriptorBinding(6, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr),
                new DescriptorBinding(7, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr),
                new DescriptorBinding(8, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr | ShaderStageFlags.ShaderStageIntersectionBitKhr),

                // Textures and image samplers
                new DescriptorBinding(9, (uint)scene.TextureSamplers.Count, DescriptorType.CombinedImageSampler, ShaderStageFlags.ShaderStageClosestHitBitKhr),

                // The Procedural buffer.
                new DescriptorBinding(10, 1, DescriptorType.StorageBuffer, ShaderStageFlags.ShaderStageClosestHitBitKhr | ShaderStageFlags.ShaderStageIntersectionBitKhr),
            };

            _descriptorSetManager = new DescriptorSetManager(_api, descriptorBindings, (ulong)uniformBuffers.Count);

            var descriptorSets = _descriptorSetManager.DescriptorSets;

            for (int i = 0; i != swapChain.VkImages.Count; i++)
            {
                // Top level acceleration structure.
                var _structureInfo = new WriteDescriptorSetAccelerationStructureKHR();
                _structureInfo.SType = StructureType.WriteDescriptorSetAccelerationStructureKhr;
                _structureInfo.PNext = null;
                _structureInfo.AccelerationStructureCount = 1;
                var accelerationStructurePinned = accelerationStructure.VkAccelerationStructure;
                _structureInfo.PAccelerationStructures = (AccelerationStructureKHR *)Unsafe.AsPointer(ref accelerationStructurePinned);

                // Accumulation image
                var _accumulationImageInfo = new DescriptorImageInfo();
                _accumulationImageInfo.ImageView   = accumulationImageView.VkImageView;
                _accumulationImageInfo.ImageLayout = ImageLayout.General;

                // Output image
                var _outputImageInfo = new DescriptorImageInfo();
                _outputImageInfo.ImageView   = outputImageView.VkImageView;
                _outputImageInfo.ImageLayout = ImageLayout.General;

                // Uniform buffer
                var _uniformBufferInfo = new DescriptorBufferInfo();
                _uniformBufferInfo.Buffer = uniformBuffers[i].Buffer.VkBuffer;
                _uniformBufferInfo.Range  = Vk.WholeSize;

                // Vertex buffer
                var _vertexBufferInfo = new DescriptorBufferInfo();
                _vertexBufferInfo.Buffer = scene.VertexBuffer.VkBuffer;
                _vertexBufferInfo.Range  = Vk.WholeSize;

                // Index buffer
                var _indexBufferInfo = new DescriptorBufferInfo();
                _indexBufferInfo.Buffer = scene.IndexBuffer.VkBuffer;
                _indexBufferInfo.Range  = Vk.WholeSize;

                // Material buffer
                var _materialBufferInfo = new DescriptorBufferInfo();
                _materialBufferInfo.Buffer = scene.MaterialBuffer.VkBuffer;
                _materialBufferInfo.Range  = Vk.WholeSize;

                // Offsets buffer
                var _offsetsBufferInfo = new DescriptorBufferInfo();
                _offsetsBufferInfo.Buffer = scene.OffsetsBuffer.VkBuffer;
                _offsetsBufferInfo.Range  = Vk.WholeSize;

                // Transforms buffer
                var _transformsBufferInfo = new DescriptorBufferInfo();
                _transformsBufferInfo.Buffer = scene.TransformsBuffer.VkBuffer;
                _transformsBufferInfo.Range  = Vk.WholeSize;

                // Image and texture samplers.
                var imageInfos = GC.AllocateArray <DescriptorImageInfo>(scene.TextureSamplers.Count, true);

                for (int t = 0; t != imageInfos.Length; ++t)
                {
                    var imageInfo = imageInfos[t];
                    imageInfo.ImageLayout = ImageLayout.ShaderReadOnlyOptimal;
                    imageInfo.ImageView   = scene.TextureImageViews[t];
                    imageInfo.Sampler     = scene.TextureSamplers[t];
                    imageInfos[t]         = imageInfo;
                }

                int descriptorWriteCt = scene.HasProcedurals ? 11 : 10;
#pragma warning disable CA2014 // Do not use stackalloc in loops
                Span <WriteDescriptorSet> descriptorWrites = stackalloc WriteDescriptorSet[descriptorWriteCt];
#pragma warning restore CA2014 // Do not use stackalloc in loops

                descriptorSets.Bind(i, 0, (WriteDescriptorSetAccelerationStructureKHR *)Unsafe.AsPointer(ref _structureInfo), out descriptorWrites[0]);
                descriptorSets.Bind(i, 1, (DescriptorImageInfo *)Unsafe.AsPointer(ref _accumulationImageInfo), out descriptorWrites[1]);
                descriptorSets.Bind(i, 2, (DescriptorImageInfo *)Unsafe.AsPointer(ref _outputImageInfo), out descriptorWrites[2]);
                descriptorSets.Bind(i, 3, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _uniformBufferInfo), out descriptorWrites[3]);
                descriptorSets.Bind(i, 4, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _vertexBufferInfo), out descriptorWrites[4]);
                descriptorSets.Bind(i, 5, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _indexBufferInfo), out descriptorWrites[5]);
                descriptorSets.Bind(i, 6, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _materialBufferInfo), out descriptorWrites[6]);
                descriptorSets.Bind(i, 7, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _offsetsBufferInfo), out descriptorWrites[7]);
                descriptorSets.Bind(i, 8, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _transformsBufferInfo), out descriptorWrites[8]);
                descriptorSets.Bind(i, 9, (DescriptorImageInfo *)Unsafe.AsPointer(ref imageInfos[0]), out descriptorWrites[9], (uint)imageInfos.Length);

                // Procedural buffer (optional)
                var _proceduralBufferInfo = new DescriptorBufferInfo();
                _proceduralBufferInfo.Buffer = scene.ProceduralBuffer.VkBuffer;
                _proceduralBufferInfo.Range  = Vk.WholeSize;

                if (scene.HasProcedurals)
                {
                    descriptorSets.Bind(i, 10, (DescriptorBufferInfo *)Unsafe.AsPointer(ref _proceduralBufferInfo), out descriptorWrites[10]);
                }

                descriptorSets.UpdateDescriptors(descriptorWrites);
            }

            _pipelineLayout = new PipelineLayout(_api, _descriptorSetManager.DescriptorSetLayout);

            // Load shaders.
            var rayGenShader                 = new ShaderModule(_api, "./assets/shaders/RayTracing.rgen.spv");
            var missShader                   = new ShaderModule(_api, "./assets/shaders/RayTracing.rmiss.spv");
            var closestHitShader             = new ShaderModule(_api, "./assets/shaders/RayTracing.rchit.spv");
            var proceduralClosestHitShader   = new ShaderModule(_api, "./assets/shaders/RayTracing.Procedural.rchit.spv");
            var proceduralIntersectionShader = new ShaderModule(_api, "./assets/shaders/RayTracing.Procedural.rint.spv");

            Span <PipelineShaderStageCreateInfo> shaderStages = stackalloc PipelineShaderStageCreateInfo[]
            {
                rayGenShader.CreateShaderStage(ShaderStageFlags.ShaderStageRaygenBitKhr),
                missShader.CreateShaderStage(ShaderStageFlags.ShaderStageMissBitKhr),
                closestHitShader.CreateShaderStage(ShaderStageFlags.ShaderStageClosestHitBitKhr),
                proceduralClosestHitShader.CreateShaderStage(ShaderStageFlags.ShaderStageClosestHitBitKhr),
                proceduralIntersectionShader.CreateShaderStage(ShaderStageFlags.ShaderStageIntersectionBitKhr)
            };

            const uint VK_SHADER_UNUSED_KHR = (~0U);

            // Shader groups
            var rayGenGroupInfo = new RayTracingShaderGroupCreateInfoKHR();
            rayGenGroupInfo.SType              = StructureType.RayTracingShaderGroupCreateInfoKhr;
            rayGenGroupInfo.PNext              = null;
            rayGenGroupInfo.Type               = RayTracingShaderGroupTypeKHR.RayTracingShaderGroupTypeGeneralKhr;
            rayGenGroupInfo.GeneralShader      = 0;
            rayGenGroupInfo.ClosestHitShader   = VK_SHADER_UNUSED_KHR;
            rayGenGroupInfo.AnyHitShader       = VK_SHADER_UNUSED_KHR;
            rayGenGroupInfo.IntersectionShader = VK_SHADER_UNUSED_KHR;
            _rayGenIndex = 0;

            var missGroupInfo = new RayTracingShaderGroupCreateInfoKHR();
            missGroupInfo.SType              = StructureType.RayTracingShaderGroupCreateInfoKhr;
            missGroupInfo.PNext              = null;
            missGroupInfo.Type               = RayTracingShaderGroupTypeKHR.RayTracingShaderGroupTypeGeneralKhr;
            missGroupInfo.GeneralShader      = 1;
            missGroupInfo.ClosestHitShader   = VK_SHADER_UNUSED_KHR;
            missGroupInfo.AnyHitShader       = VK_SHADER_UNUSED_KHR;
            missGroupInfo.IntersectionShader = VK_SHADER_UNUSED_KHR;
            _missIndex = 1;

            var triangleHitGroupInfo = new RayTracingShaderGroupCreateInfoKHR();
            triangleHitGroupInfo.SType              = StructureType.RayTracingShaderGroupCreateInfoKhr;
            triangleHitGroupInfo.PNext              = null;
            triangleHitGroupInfo.Type               = RayTracingShaderGroupTypeKHR.RayTracingShaderGroupTypeTrianglesHitGroupKhr;
            triangleHitGroupInfo.GeneralShader      = VK_SHADER_UNUSED_KHR;
            triangleHitGroupInfo.ClosestHitShader   = 2;
            triangleHitGroupInfo.AnyHitShader       = VK_SHADER_UNUSED_KHR;
            triangleHitGroupInfo.IntersectionShader = VK_SHADER_UNUSED_KHR;
            _triangleHitGroupIndex = 2;

            var proceduralHitGroupInfo = new RayTracingShaderGroupCreateInfoKHR();
            proceduralHitGroupInfo.SType              = StructureType.RayTracingShaderGroupCreateInfoKhr;
            proceduralHitGroupInfo.PNext              = null;
            proceduralHitGroupInfo.Type               = RayTracingShaderGroupTypeKHR.RayTracingShaderGroupTypeProceduralHitGroupKhr;
            proceduralHitGroupInfo.GeneralShader      = VK_SHADER_UNUSED_KHR;
            proceduralHitGroupInfo.ClosestHitShader   = 3;
            proceduralHitGroupInfo.AnyHitShader       = VK_SHADER_UNUSED_KHR;
            proceduralHitGroupInfo.IntersectionShader = 4;
            _proceduralHitGroupIndex = 3;

            Span <RayTracingShaderGroupCreateInfoKHR> groups = stackalloc RayTracingShaderGroupCreateInfoKHR[]
            {
                rayGenGroupInfo,
                missGroupInfo,
                triangleHitGroupInfo,
                proceduralHitGroupInfo,
            };

            // Create graphic pipeline
            var pipelineInfo = new RayTracingPipelineCreateInfoKHR();
            pipelineInfo.SType      = StructureType.RayTracingPipelineCreateInfoKhr;
            pipelineInfo.PNext      = null;
            pipelineInfo.Flags      = 0;
            pipelineInfo.StageCount = (uint)shaderStages.Length;
            pipelineInfo.PStages    = (PipelineShaderStageCreateInfo *)Unsafe.AsPointer(ref shaderStages[0]);
            pipelineInfo.GroupCount = (uint)groups.Length;
            pipelineInfo.PGroups    = (RayTracingShaderGroupCreateInfoKHR *)Unsafe.AsPointer(ref groups[0]);
            pipelineInfo.MaxPipelineRayRecursionDepth = 1;
            pipelineInfo.Layout             = _pipelineLayout.VkPipelineLayout;
            pipelineInfo.BasePipelineHandle = default;
            pipelineInfo.BasePipelineIndex  = 0;

            Util.Verify(
                _api.KhrRayTracingPipeline.CreateRayTracingPipelines(_api.Device.VkDevice, default, default, 1, pipelineInfo, default, out _pipeline),