예제 #1
0
        public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
        {
            _platformInterface = platformInterface;

            var device = VulkanInitialization.CreateDevice(platformInterface.Api,
                                                           platformInterface.PhysicalDevice.InternalHandle,
                                                           platformInterface.PhysicalDevice.QueueFamilyIndex,
                                                           VulkanInitialization.GetSupportedExtensions(platformInterface.Api, platformInterface.PhysicalDevice.InternalHandle),
                                                           platformInterface.PhysicalDevice.QueueCount);

            Device = new VulkanDevice(device, platformInterface.PhysicalDevice, platformInterface.Api);

            Display = VulkanDisplay.CreateDisplay(
                platformInterface.Instance,
                Device,
                platformInterface.PhysicalDevice,
                surface);
            Surface = surface;

            // Skia seems to only create surfaces from images with unorm format
            IsRgba = Display.SurfaceFormat.Format >= Format.R8G8B8A8Unorm &&
                     Display.SurfaceFormat.Format <= Format.R8G8B8A8Srgb;

            _format = IsRgba ? Format.R8G8B8A8Unorm : Format.B8G8R8A8Unorm;
        }
예제 #2
0
        public unsafe ReturnSet <bool> InitializeLogicalDevice(VulkanDevice physicalDevice, Logger logger)
        {
            uint queuePriorities = 0;

            var deviceQueueCreateInfo = new DeviceQueueCreateInfo
            {
                StructureType    = StructureType.DeviceQueueCreateInfo,
                QueueFamilyIndex = 0,
                QueueCount       = 1,
                QueuePriorities  = new IntPtr(&queuePriorities)
            };

            var physicalDeviceFeatures = new PhysicalDeviceFeatures
            {
                ShaderClipDistance = true,
            };

            var enabledLayerNames = new[]
            {
                ExtensionNames.VK_LAYER_LUNARG_standard_validation.ToIntPtr()
            };

            var enabledExtensionNames = new[]
            {
                ExtensionNames.VK_KHR_swapchain.ToIntPtr()
            };

            fixed(void *enabledLayerNamesPointer = &enabledLayerNames[0])
            fixed(void *enabledExtensionNamesPointer = &enabledExtensionNames[0])
            {
                var deviceCreateInfo = new DeviceCreateInfo
                {
                    StructureType         = StructureType.DeviceCreateInfo,
                    QueueCreateInfoCount  = 1,
                    QueueCreateInfos      = new IntPtr(&deviceQueueCreateInfo),
                    EnabledExtensionCount = (uint)enabledExtensionNames.Length,
                    EnabledExtensionNames = new IntPtr(enabledExtensionNamesPointer),
                    EnabledFeatures       = new IntPtr(&physicalDeviceFeatures),
                    EnabledLayerCount     = (uint)enabledLayerNames.Length,
                    EnabledLayerNames     = new IntPtr(enabledLayerNamesPointer)
                };

                physicalDevice.CreateLogicalDevice(deviceCreateInfo);

                logger.AddMessage("Logical Device created successfully");

                _queue = physicalDevice.CreateQueue(_surface);

                logger.AddMessage($"Queue created on {physicalDevice.Name}");

                _form.Show();

                return(new ReturnSet <bool>(true));
            }
        }
예제 #3
0
        // Prepare and initialize uniform buffer containing shader uniforms
        void prepareUniformBuffers()
        {
            // Create the vertex shader uniform buffer block
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.UniformBuffer,
                                 VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                 uniformBuffer,
                                 (ulong)sizeof(UboVS)));

            // Map persistent
            Util.CheckResult(uniformBuffer.map());

            updateUniformBuffers();
        }
예제 #4
0
        // Prepare and initialize uniform buffer containing shader uniforms
        void prepareUniformBuffers()
        {
            var localUboVS = uboVS;

            // Vertex shader uniform buffer block
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.UniformBuffer,
                                 VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                 uniformBufferVS,
                                 (uint)sizeof(UboVS),
                                 &localUboVS));

            updateUniformBuffers();
        }
예제 #5
0
            internal unsafe VulkanCommandBuffer(VulkanDevice device, VulkanCommandBufferPool commandBufferPool)
            {
                _device            = device;
                _commandBufferPool = commandBufferPool;

                InternalHandle = _commandBufferPool.AllocateCommandBuffer();

                var fenceCreateInfo = new FenceCreateInfo()
                {
                    SType = StructureType.FenceCreateInfo,
                    Flags = FenceCreateFlags.FenceCreateSignaledBit
                };

                device.Api.CreateFence(device.InternalHandle, fenceCreateInfo, null, out _fence);
            }
예제 #6
0
        void generateQuad()
        {
            // Setup vertices for a single uv-mapped quad made from two triangles
            NativeList <Vertex> vertices = new NativeList <Vertex>()
            {
                new Vertex()
                {
                    pos = new Vector3(1.0f, 1.0f, 0.0f), uv = new Vector2(1.0f, 1.0f), normal = new Vector3(0.0f, 0.0f, 1.0f)
                },
                new Vertex()
                {
                    pos = new Vector3(-1.0f, 1.0f, 0.0f), uv = new Vector2(0.0f, 1.0f), normal = new Vector3(0.0f, 0.0f, 1.0f)
                },
                new Vertex()
                {
                    pos = new Vector3(-1.0f, -1.0f, 0.0f), uv = new Vector2(0.0f, 0.0f), normal = new Vector3(0.0f, 0.0f, 1.0f)
                },
                new Vertex()
                {
                    pos = new Vector3(1.0f, -1.0f, 0.0f), uv = new Vector2(1.0f, 0.0f), normal = new Vector3(0.0f, 0.0f, 1.0f)
                },
            };

            // Setup indices
            NativeList <uint> indices = new NativeList <uint> {
                0, 1, 2, 2, 3, 0
            };

            indexCount = indices.Count;

            // Create buffers
            // For the sake of simplicity we won't stage the vertex data to the gpu memory
            // Vertex buffer
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.VertexBuffer,
                                 VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                 vertexBuffer,
                                 (ulong)(vertices.Count * sizeof(Vertex)),
                                 vertices.Data.ToPointer()));
            // Index buffer
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.IndexBuffer,
                                 VkMemoryPropertyFlags.HostCoherent | VkMemoryPropertyFlags.HostCoherent,
                                 indexBuffer,
                                 indices.Count * sizeof(uint),
                                 indices.Data.ToPointer()));
        }
        public VulkanComputeContext Translate(Expression expression, VulkanDevice device)
        {
            _device = device;
            _shader = new GlslComputeShader();

            _ctx = new VulkanComputeContext(device);

            Visit(expression);

            _ctx.Output = ResolveOutput(_ctx.Inputs[0].Count, expression);
            GlslVariable outputVar = _shader.AddBuffer(_ctx.Output.ElementType, false, true);

            _shader.Main.AppendLine($"{outputVar.Name} = {SrcVariable.Name};");

            _ctx.SpirV = _shader.CompileToSpirV();

            return(_ctx);
        }
예제 #8
0
        protected virtual void SetupDepthStencil()
        {
            VkImageCreateInfo image = VkImageCreateInfo.New();

            image.imageType = VkImageType._2d;
            image.format    = DepthFormat;
            image.extent    = new VkExtent3D()
            {
                width = Width, height = Height, depth = 1
            };
            image.mipLevels   = 1;
            image.arrayLayers = 1;
            image.samples     = VkSampleCountFlags._1;
            image.tiling      = VkImageTiling.Optimal;
            image.usage       = (VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.TransferSrc);
            image.flags       = 0;

            VkMemoryAllocateInfo mem_alloc = VkMemoryAllocateInfo.New();

            mem_alloc.allocationSize  = 0;
            mem_alloc.memoryTypeIndex = 0;

            VkImageViewCreateInfo depthStencilView = VkImageViewCreateInfo.New();

            depthStencilView.viewType                        = VkImageViewType._2d;
            depthStencilView.format                          = DepthFormat;
            depthStencilView.flags                           = 0;
            depthStencilView.subresourceRange                = new VkImageSubresourceRange();
            depthStencilView.subresourceRange.aspectMask     = (VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil);
            depthStencilView.subresourceRange.baseMipLevel   = 0;
            depthStencilView.subresourceRange.levelCount     = 1;
            depthStencilView.subresourceRange.baseArrayLayer = 0;
            depthStencilView.subresourceRange.layerCount     = 1;

            Util.CheckResult(vkCreateImage(Device, &image, null, out DepthStencil.Image));
            vkGetImageMemoryRequirements(Device, DepthStencil.Image, out VkMemoryRequirements memReqs);
            mem_alloc.allocationSize  = memReqs.size;
            mem_alloc.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);
            Util.CheckResult(vkAllocateMemory(Device, &mem_alloc, null, out DepthStencil.Mem));
            Util.CheckResult(vkBindImageMemory(Device, DepthStencil.Image, DepthStencil.Mem, 0));

            depthStencilView.image = DepthStencil.Image;
            Util.CheckResult(vkCreateImageView(Device, ref depthStencilView, null, out DepthStencil.View));
        }
예제 #9
0
        // Prepare and initialize uniform buffer containing shader uniforms
        void prepareUniformBuffers()
        {
            // Objact vertex shader uniform buffer
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.UniformBuffer,
                                 VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                 uniformBuffers_object,
                                 (ulong)sizeof(UboVS)));

            // Skybox vertex shader uniform buffer
            Util.CheckResult(VulkanDevice.createBuffer(
                                 VkBufferUsageFlags.UniformBuffer,
                                 VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                 uniformBuffers_skybox,
                                 (uint)sizeof(UboVS)));

            // Map persistent
            Util.CheckResult(uniformBuffers_object.map());
            Util.CheckResult(uniformBuffers_skybox.map());

            updateUniformBuffers();
        }
예제 #10
0
        void loadCubemap(string filename, VkFormat format, bool forceLinearTiling)
        {
            KtxFile texCube;

            using (var fs = File.OpenRead(filename))
            {
                texCube = KtxFile.Load(fs, readKeyValuePairs: false);
            }

            cubeMap.width     = texCube.Header.PixelWidth;
            cubeMap.height    = texCube.Header.PixelHeight;
            cubeMap.mipLevels = texCube.Header.NumberOfMipmapLevels;

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs;

            // Create a host-visible staging buffer that contains the raw image data
            VkBuffer       stagingBuffer;
            VkDeviceMemory stagingMemory;

            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();

            bufferCreateInfo.size = texCube.GetTotalSize();
            // This buffer is used as a transfer source for the buffer copy
            bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

            Util.CheckResult(vkCreateBuffer(Device, &bufferCreateInfo, null, &stagingBuffer));

            // Get memory requirements for the staging buffer (alignment, memory type bits)
            vkGetBufferMemoryRequirements(Device, stagingBuffer, &memReqs);
            memAllocInfo.allocationSize = memReqs.size;
            // Get memory type index for a host visible buffer
            memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
            Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &stagingMemory));
            Util.CheckResult(vkBindBufferMemory(Device, stagingBuffer, stagingMemory, 0));

            // Copy texture data into staging buffer
            byte *data;

            Util.CheckResult(vkMapMemory(Device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
            byte[] allTextureData = texCube.GetAllTextureData();
            fixed(byte *texCubeDataPtr = &allTextureData[0])
            {
                Unsafe.CopyBlock(data, texCubeDataPtr, (uint)allTextureData.Length);
            }

            vkUnmapMemory(Device, stagingMemory);

            // Create optimal tiled target image
            VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();

            imageCreateInfo.imageType     = VkImageType._2d;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = cubeMap.mipLevels;
            imageCreateInfo.samples       = VkSampleCountFlags._1;
            imageCreateInfo.tiling        = VkImageTiling.Optimal;
            imageCreateInfo.usage         = VkImageUsageFlags.Sampled;
            imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
            imageCreateInfo.initialLayout = VkImageLayout.Undefined;
            imageCreateInfo.extent        = new VkExtent3D {
                width = cubeMap.width, height = cubeMap.height, depth = 1
            };
            imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;
            // Cube faces count as array layers in Vulkan
            imageCreateInfo.arrayLayers = 6;
            // This flag is required for cube map images
            imageCreateInfo.flags = VkImageCreateFlags.CubeCompatible;

            Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, out cubeMap.image));

            vkGetImageMemoryRequirements(Device, cubeMap.image, &memReqs);

            memAllocInfo.allocationSize  = memReqs.size;
            memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

            Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, out cubeMap.DeviceMemory));
            Util.CheckResult(vkBindImageMemory(Device, cubeMap.image, cubeMap.DeviceMemory, 0));

            VkCommandBuffer copyCmd = createCommandBuffer(VkCommandBufferLevel.Primary, true);

            // Setup buffer copy regions for each face including all of it's miplevels
            NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
            uint offset = 0;

            for (uint face = 0; face < 6; face++)
            {
                for (uint level = 0; level < cubeMap.mipLevels; level++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = level;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = face;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = texCube.Faces[face].Mipmaps[level].Width;
                    bufferCopyRegion.imageExtent.height = texCube.Faces[face].Mipmaps[level].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    // Increase offset into staging buffer for next level / face
                    offset += texCube.Faces[face].Mipmaps[level].SizeInBytes;
                }
            }

            // Image barrier for optimal image (target)
            // Set initial layout for all array layers (faces) of the optimal (target) tiled texture
            VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();

            subresourceRange.aspectMask   = VkImageAspectFlags.Color;
            subresourceRange.baseMipLevel = 0;
            subresourceRange.levelCount   = cubeMap.mipLevels;
            subresourceRange.layerCount   = 6;

            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.Undefined,
                VkImageLayout.TransferDstOptimal,
                subresourceRange);

            // Copy the cube map faces from the staging buffer to the optimal tiled image
            vkCmdCopyBufferToImage(
                copyCmd,
                stagingBuffer,
                cubeMap.image,
                VkImageLayout.TransferDstOptimal,
                bufferCopyRegions.Count,
                bufferCopyRegions.Data);

            // Change texture image layout to shader read after all faces have been copied
            cubeMap.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.TransferDstOptimal,
                cubeMap.imageLayout,
                subresourceRange);

            flushCommandBuffer(copyCmd, Queue, true);

            // Create sampler
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();

            sampler.magFilter     = VkFilter.Linear;
            sampler.minFilter     = VkFilter.Linear;
            sampler.mipmapMode    = VkSamplerMipmapMode.Linear;
            sampler.addressModeU  = VkSamplerAddressMode.ClampToEdge;
            sampler.addressModeV  = sampler.addressModeU;
            sampler.addressModeW  = sampler.addressModeU;
            sampler.mipLodBias    = 0.0f;
            sampler.compareOp     = VkCompareOp.Never;
            sampler.minLod        = 0.0f;
            sampler.maxLod        = cubeMap.mipLevels;
            sampler.borderColor   = VkBorderColor.FloatOpaqueWhite;
            sampler.maxAnisotropy = 1.0f;
            if (VulkanDevice.Features.samplerAnisotropy == 1)
            {
                sampler.maxAnisotropy    = VulkanDevice.Properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            Util.CheckResult(vkCreateSampler(Device, &sampler, null, out cubeMap.sampler));

            // Create image view
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();

            // Cube map view type
            view.viewType   = VkImageViewType.Cube;
            view.format     = format;
            view.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            view.subresourceRange = new VkImageSubresourceRange {
                aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, layerCount = 1, baseArrayLayer = 0, levelCount = 1
            };
            // 6 array layers (faces)
            view.subresourceRange.layerCount = 6;
            // Set number of mip levels
            view.subresourceRange.levelCount = cubeMap.mipLevels;
            view.image = cubeMap.image;
            Util.CheckResult(vkCreateImageView(Device, &view, null, out cubeMap.view));

            // Clean up staging resources
            vkFreeMemory(Device, stagingMemory, null);
            vkDestroyBuffer(Device, stagingBuffer, null);
        }
예제 #11
0
        private static int Main(string[] args)
        {
            var loopCount  = 4;
            var numThreads = Ncnn.GetGpuCount();
            var powerSave  = 0;
            var gpuDevice  = -1;

            if (args.Length >= 1)
            {
                loopCount = int.Parse(args[0]);
            }
            if (args.Length >= 2)
            {
                numThreads = int.Parse(args[1]);
            }
            if (args.Length >= 3)
            {
                powerSave = int.Parse(args[2]);
            }
            if (args.Length >= 4)
            {
                gpuDevice = int.Parse(args[3]);
            }

            var useVulkanCompute = gpuDevice != -1;

            g_loop_count = loopCount;

            g_blob_pool_allocator.SetSizeCompareRatio(0.0f);
            g_workspace_pool_allocator.SetSizeCompareRatio(0.5f);

            if (useVulkanCompute)
            {
                g_warmup_loop_count   = 10;
                g_vkdev               = Ncnn.GetGpuDevice(gpuDevice);
                g_blob_vkallocator    = new VkBlobBufferAllocator(g_vkdev);
                g_staging_vkallocator = new VkStagingBufferAllocator(g_vkdev);
            }

            // default option
            using var opt          = new Option();
            opt.LightMode          = true;
            opt.NumThreads         = numThreads;
            opt.BlobAllocator      = g_blob_pool_allocator;
            opt.WorkspaceAllocator = g_workspace_pool_allocator;
            if (Ncnn.IsSupportVulkan)
            {
                opt.BlobVkAllocator      = g_blob_vkallocator;
                opt.WorkspaceVkAllocator = g_blob_vkallocator;
                opt.StagingVkAllocator   = g_staging_vkallocator;
            }
            opt.UseWinogradConvolution = true;
            opt.UseSgemmConvolution    = true;
            opt.UseInt8Inference       = true;
            opt.UseVulkanCompute       = useVulkanCompute;
            opt.UseFP16Packed          = true;
            opt.UseFP16Storage         = true;
            opt.UseFP16Arithmetic      = true;
            opt.UseInt8Storage         = true;
            opt.UseInt8Arithmetic      = true;
            opt.UsePackingLayout       = true;

            Ncnn.SetCpuPowerSave((PowerSave)powerSave);

            Ncnn.SetOmpDynamic(0);
            Ncnn.SetOmpNumThreads(numThreads);

            Console.WriteLine($"loop_count = {loopCount}");
            Console.WriteLine($"num_threads = {numThreads}");
            Console.WriteLine($"powersave = {(int)Ncnn.SetCpuPowerSave()}");
            Console.WriteLine($"gpu_device = {gpuDevice}");


            // run
            Benchmark("squeezenet", new Mat(227, 227, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("squeezenet_int8", new Mat(227, 227, 3), opt);
            }

            Benchmark("mobilenet", new Mat(224, 224, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("mobilenet_int8", new Mat(224, 224, 3), opt);
            }

            Benchmark("mobilenet_v2", new Mat(224, 224, 3), opt);

            //if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            //{
            //    Benchmark("mobilenet_v2_int8", new Mat(224, 224, 3), opt);
            //}

            Benchmark("mobilenet_v3", new Mat(224, 224, 3), opt);

            Benchmark("shufflenet", new Mat(224, 224, 3), opt);

            Benchmark("shufflenet_v2", new Mat(224, 224, 3), opt);

            Benchmark("mnasnet", new Mat(224, 224, 3), opt);

            Benchmark("proxylessnasnet", new Mat(224, 224, 3), opt);

            Benchmark("googlenet", new Mat(224, 224, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("googlenet_int8", new Mat(224, 224, 3), opt);
            }

            Benchmark("resnet18", new Mat(224, 224, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("resnet18_int8", new Mat(224, 224, 3), opt);
            }

            Benchmark("alexnet", new Mat(227, 227, 3), opt);

            Benchmark("vgg16", new Mat(224, 224, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("vgg16_int8", new Mat(224, 224, 3), opt);
            }

            Benchmark("resnet50", new Mat(224, 224, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("resnet50_int8", new Mat(224, 224, 3), opt);
            }

            Benchmark("squeezenet_ssd", new Mat(300, 300, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("squeezenet_ssd_int8", new Mat(300, 300, 3), opt);
            }

            Benchmark("mobilenet_ssd", new Mat(300, 300, 3), opt);

            if (!Ncnn.IsSupportVulkan || !useVulkanCompute)
            {
                Benchmark("mobilenet_ssd_int8", new Mat(300, 300, 3), opt);
            }

            Benchmark("mobilenet_yolo", new Mat(416, 416, 3), opt);

            Benchmark("mobilenetv2_yolov3", new Mat(352, 352, 3), opt);

            if (Ncnn.IsSupportVulkan)
            {
                g_blob_vkallocator?.Dispose();
                g_staging_vkallocator?.Dispose();
            }

            return(0);
        }
예제 #12
0
        public static int TestLayer <T>(int typeIndex, ParamDict pd, ModelBin mb, Option opt, Mat a, float epsilon = 0.001f)
            where T : Layer, new()
        {
            using (var op = Ncnn.CreateLayer <T>(typeIndex))
            {
                if (!op.SupportPacking)
                {
                    opt.UsePackingLayout = false;
                }

                VulkanDevice                   vkDev = null;
                VkWeightBufferAllocator        gWeightVkAllocator        = null;
                VkWeightStagingBufferAllocator gWeightStagingVkAllocator = null;
                VkBlobBufferAllocator          gBlobVkAllocator          = null;
                VkStagingBufferAllocator       gStagingVkAllocator       = null;

                if (Ncnn.IsSupportVulkan)
                {
                    vkDev = Ncnn.GetGpuDevice();

                    gWeightVkAllocator        = new VkWeightBufferAllocator(vkDev);
                    gWeightStagingVkAllocator = new VkWeightStagingBufferAllocator(vkDev);

                    gBlobVkAllocator    = new VkBlobBufferAllocator(vkDev);
                    gStagingVkAllocator = new VkStagingBufferAllocator(vkDev);

                    opt.BlobVkAllocator      = gBlobVkAllocator;
                    opt.WorkspaceVkAllocator = gBlobVkAllocator;
                    opt.StagingVkAllocator   = gStagingVkAllocator;

                    if (!vkDev.Info.SupportFP16Storage)
                    {
                        opt.UseFP16Storage = false;
                    }
                    if (!vkDev.Info.SupportFP16Packed)
                    {
                        opt.UseFP16Packed = false;
                    }

                    op.VkDev = vkDev;
                }

                op.LoadParam(pd);

                op.LoadModel(mb);

                op.CreatePipeline(opt);

                if (Ncnn.IsSupportVulkan)
                {
                    if (opt.UseVulkanCompute)
                    {
                        using var cmd = new VkTransfer(vkDev)
                              {
                                  WeightVkAllocator  = gWeightVkAllocator,
                                  StagingVkAllocator = gWeightStagingVkAllocator
                              };

                        op.UploadModel(cmd, opt);

                        cmd.SubmitAndWait();

                        gWeightStagingVkAllocator?.Clear();
                    }
                }

                using var b = new Mat();
                ((T)op).Forward(a, b, opt);

                var c = new Mat();
                {
                    Mat a4;
                    if (opt.UsePackingLayout)
                    {
                        a4 = new Mat();
                        Ncnn.ConvertPacking(a, a4, 4, opt);
                    }
                    else
                    {
                        a4 = a;
                    }

                    var c4 = new Mat();
                    op.Forward(a4, c4, opt);

                    if (opt.UsePackingLayout)
                    {
                        Ncnn.ConvertPacking(c4, c, 1, opt);
                        c4.Dispose();
                    }
                    else
                    {
                        c?.Dispose();
                        c = c4;
                    }
                }

                Mat d = null;

                try
                {
                    if (Ncnn.IsSupportVulkan)
                    {
                        d = new Mat();

                        if (opt.UseVulkanCompute)
                        {
                            using var a4 = new Mat();
                            Mat a4_fp16 = null;

                            try
                            {
                                // pack
                                Ncnn.ConvertPacking(a, a4, 4, opt);

                                // fp16
                                if (opt.UseFP16Storage || a4.ElemPack == 4 && opt.UseFP16Packed)
                                {
                                    a4_fp16 = new Mat();
                                    Ncnn.CastFloat32ToFloat16(a4, a4_fp16, opt);
                                }
                                else
                                {
                                    a4_fp16 = a4;
                                }

                                // upload
                                using var a4_fp16_gpu = new VkMat();
                                a4_fp16_gpu.CreateLike(a4_fp16, gBlobVkAllocator, gStagingVkAllocator);
                                a4_fp16_gpu.PrepareStagingBuffer();
                                a4_fp16_gpu.Upload(a4_fp16);

                                // forward
                                using var cmd = new VkCompute(vkDev);

                                cmd.RecordUpload(a4_fp16_gpu);

                                using var d4_fp16_gpu = new VkMat();
                                op.Forward(a4_fp16_gpu, d4_fp16_gpu, cmd, opt);

                                d4_fp16_gpu.PrepareStagingBuffer();

                                cmd.RecordDownload(d4_fp16_gpu);

                                cmd.SubmitAndWait();

                                // download
                                using var d4_fp16 = new Mat();
                                d4_fp16.CreateLike(d4_fp16_gpu);
                                d4_fp16_gpu.Download(d4_fp16);

                                // fp32
                                Mat d4 = null;

                                try
                                {
                                    if (opt.UseFP16Storage || d4_fp16.ElemPack == 4 && opt.UseFP16Packed)
                                    {
                                        d4 = new Mat();
                                        Ncnn.CastFloat16ToFloat32(d4_fp16, d4, opt);
                                    }
                                    else
                                    {
                                        d4 = d4_fp16;
                                    }

                                    // unpack
                                    Ncnn.ConvertPacking(d4, d, 1, opt);
                                }
                                finally
                                {
                                    d4?.Dispose();
                                }
                            }
                            finally
                            {
                                a4_fp16?.Dispose();
                            }
                        }
                    }

                    op.DestroyPipeline(opt);

                    // Must dispose here!!
                    op.Dispose();

                    if (Ncnn.IsSupportVulkan)
                    {
                        gBlobVkAllocator.Clear();
                        gStagingVkAllocator.Clear();
                        gWeightVkAllocator.Clear();

                        gBlobVkAllocator?.Dispose();
                        gStagingVkAllocator?.Dispose();
                        gWeightVkAllocator?.Dispose();
                        gWeightStagingVkAllocator?.Dispose();
                    }

                    if (CompareMat(b, c, epsilon) != 0)
                    {
                        Console.Error.WriteLine("test_layer failed cpu");
                        return(-1);
                    }

                    if (Ncnn.IsSupportVulkan)
                    {
                        if (opt.UseVulkanCompute && CompareMat(b, d, epsilon) != 0)
                        {
                            Console.Error.WriteLine("test_layer failed gpu");
                            return(-1);
                        }
                    }
                }
                finally
                {
                    c?.Dispose();
                    d?.Dispose();
                }
            }

            return(0);
        }
예제 #13
0
        // Load a model from file using the ASSIMP model loader and generate all resources required to render the model
        void loadModel(string filename)
        {
            // Load the model from file using ASSIMP

            // Flags for loading the mesh
            PostProcessSteps assimpFlags = PostProcessSteps.FlipWindingOrder | PostProcessSteps.Triangulate | PostProcessSteps.PreTransformVertices;

            var scene = new AssimpContext().ImportFile(filename, assimpFlags);

            // Generate vertex buffer from ASSIMP scene data
            float scale = 1.0f;
            NativeList <Vertex> vertexBuffer = new NativeList <Vertex>();

            // Iterate through all meshes in the file and extract the vertex components
            for (int m = 0; m < scene.MeshCount; m++)
            {
                for (int v = 0; v < scene.Meshes[(int)m].VertexCount; v++)
                {
                    Vertex vertex;
                    Mesh   mesh = scene.Meshes[m];

                    // Use glm make_* functions to convert ASSIMP vectors to glm vectors
                    vertex.pos    = new Vector3(mesh.Vertices[v].X, mesh.Vertices[v].Y, mesh.Vertices[v].Z) * scale;
                    vertex.normal = new Vector3(mesh.Normals[v].X, mesh.Normals[v].Y, mesh.Normals[v].Z);
                    // Texture coordinates and colors may have multiple channels, we only use the first [0] one
                    vertex.uv = new Vector2(mesh.TextureCoordinateChannels[0][v].X, mesh.TextureCoordinateChannels[0][v].Y);
                    // Mesh may not have vertex colors
                    if (mesh.HasVertexColors(0))
                    {
                        vertex.color = new Vector3(mesh.VertexColorChannels[0][v].R, mesh.VertexColorChannels[0][v].G, mesh.VertexColorChannels[0][v].B);
                    }
                    else
                    {
                        vertex.color = new Vector3(1f);
                    }

                    // Vulkan uses a right-handed NDC (contrary to OpenGL), so simply flip Y-Axis
                    vertex.pos.Y *= -1.0f;

                    vertexBuffer.Add(vertex);
                }
            }
            ulong vertexBufferSize = (ulong)(vertexBuffer.Count * sizeof(Vertex));

            // Generate index buffer from ASSIMP scene data
            NativeList <uint> indexBuffer = new NativeList <uint>();

            for (int m = 0; m < scene.MeshCount; m++)
            {
                uint indexBase = indexBuffer.Count;
                for (int f = 0; f < scene.Meshes[m].FaceCount; f++)
                {
                    // We assume that all faces are triangulated
                    for (int i = 0; i < 3; i++)
                    {
                        indexBuffer.Add((uint)scene.Meshes[m].Faces[f].Indices[i] + indexBase);
                    }
                }
            }
            ulong indexBufferSize = (ulong)(indexBuffer.Count * sizeof(uint));

            model_indices_count = (int)indexBuffer.Count;

            // Static mesh should always be Device local

            bool useStaging = true;

            if (useStaging)
            {
                VkBuffer       vertexStaging_buffer;
                VkDeviceMemory vertexStaging_memory;
                VkBuffer       indexStaging_buffer;
                VkDeviceMemory indexStaging_memory;

                // Create staging buffers
                // Vertex data
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.TransferSrc,
                                     VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                     vertexBufferSize,
                                     &vertexStaging_buffer,
                                     &vertexStaging_memory,
                                     vertexBuffer.Data.ToPointer()));
                // Index data
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.TransferSrc,
                                     VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                                     indexBufferSize,
                                     &indexStaging_buffer,
                                     &indexStaging_memory,
                                     indexBuffer.Data.ToPointer()));

                // Create Device local buffers
                // Vertex buffer
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst,
                                     VkMemoryPropertyFlags.DeviceLocal,
                                     vertexBufferSize,
                                     out model_vertices_buffer,
                                     out model_vertices_memory));
                // Index buffer
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst,
                                     VkMemoryPropertyFlags.DeviceLocal,
                                     indexBufferSize,
                                     out model_indices_buffer,
                                     out model_indices_memory));

                // Copy from staging buffers
                VkCommandBuffer copyCmd = createCommandBuffer(VkCommandBufferLevel.Primary, true);

                VkBufferCopy copyRegion = new VkBufferCopy();

                copyRegion.size = vertexBufferSize;

                vkCmdCopyBuffer(
                    copyCmd,
                    vertexStaging_buffer,
                    model_vertices_buffer,
                    1,
                    &copyRegion);

                copyRegion.size = indexBufferSize;

                vkCmdCopyBuffer(
                    copyCmd,
                    indexStaging_buffer,
                    model_indices_buffer,
                    1,
                    &copyRegion);

                flushCommandBuffer(copyCmd, Queue, true);


                vkDestroyBuffer(Device, vertexStaging_buffer, null);

                vkFreeMemory(Device, vertexStaging_memory, null);

                vkDestroyBuffer(Device, indexStaging_buffer, null);

                vkFreeMemory(Device, indexStaging_memory, null);
            }
            else
            {
                // Vertex buffer
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.VertexBuffer,
                                     VkMemoryPropertyFlags.HostVisible,
                                     vertexBufferSize,
                                     out model_vertices_buffer,
                                     out model_vertices_memory,
                                     vertexBuffer.Data.ToPointer()));
                // Index buffer
                Util.CheckResult(VulkanDevice.createBuffer(
                                     VkBufferUsageFlags.IndexBuffer,
                                     VkMemoryPropertyFlags.HostVisible,
                                     indexBufferSize,
                                     out model_indices_buffer,
                                     out model_indices_memory,
                                     indexBuffer.Data.ToPointer()));
            }
        }
예제 #14
0
        void loadTexture(string fileName, VkFormat format, bool forceLinearTiling)
        {
            KtxFile tex2D;

            using (var fs = File.OpenRead(fileName))
            {
                tex2D = KtxFile.Load(fs, false);
            }

            VkFormatProperties formatProperties;

            texture.width     = tex2D.Header.PixelWidth;
            texture.height    = tex2D.Header.PixelHeight;
            texture.mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get Device properites for the requested texture format
            vkGetPhysicalDeviceFormatProperties(PhysicalDevice, format, &formatProperties);

            // Only use linear tiling if requested (and supported by the Device)
            // Support for linear tiling is mostly limited, so prefer to use
            // optimal tiling instead
            // On most implementations linear tiling will only support a very
            // limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
            uint useStaging = 1;

            // Only use linear tiling if forced
            if (forceLinearTiling)
            {
                // Don't use linear if format is not supported for (linear) shader sampling
                useStaging = ((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != VkFormatFeatureFlags.SampledImage) ? 1u : 0u;
            }

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs      = new VkMemoryRequirements();

            if (useStaging == 1)
            {
                // Create a host-visible staging buffer that contains the raw image data
                VkBuffer       stagingBuffer;
                VkDeviceMemory stagingMemory;

                VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();
                bufferCreateInfo.size = tex2D.GetTotalSize();
                // This buffer is used as a transfer source for the buffer copy
                bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
                bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

                Util.CheckResult(vkCreateBuffer(Device, &bufferCreateInfo, null, &stagingBuffer));

                // Get memory requirements for the staging buffer (alignment, memory type bits)
                vkGetBufferMemoryRequirements(Device, stagingBuffer, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;
                // Get memory type index for a host visible buffer
                memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &stagingMemory));
                Util.CheckResult(vkBindBufferMemory(Device, stagingBuffer, stagingMemory, 0));

                // Copy texture data into staging buffer
                byte *data;
                Util.CheckResult(vkMapMemory(Device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
                byte[] allData = tex2D.GetAllTextureData();
                fixed(byte *tex2DDataPtr = &allData[0])
                {
                    Unsafe.CopyBlock(data, tex2DDataPtr, (uint)allData.Length);
                }

                vkUnmapMemory(Device, stagingMemory);

                // Setup buffer copy regions for each mip level
                NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
                uint offset = 0;

                for (uint i = 0; i < texture.mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = i;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = tex2D.Faces[0].Mipmaps[i].Width;
                    bufferCopyRegion.imageExtent.height = tex2D.Faces[0].Mipmaps[i].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    offset += tex2D.Faces[0].Mipmaps[i].SizeInBytes;
                }

                // Create optimal tiled target image
                VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                imageCreateInfo.imageType   = VkImageType._2d;
                imageCreateInfo.format      = format;
                imageCreateInfo.mipLevels   = texture.mipLevels;
                imageCreateInfo.arrayLayers = 1;
                imageCreateInfo.samples     = VkSampleCountFlags._1;
                imageCreateInfo.tiling      = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                // Set initial layout of the image to undefined
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = texture.width, height = texture.height, depth = 1
                };
                imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;

                Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, out texture.image));

                vkGetImageMemoryRequirements(Device, texture.image, &memReqs);

                memAllocInfo.allocationSize  = memReqs.size;
                memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

                Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, out texture.DeviceMemory));
                Util.CheckResult(vkBindImageMemory(Device, texture.image, texture.DeviceMemory, 0));

                VkCommandBuffer copyCmd = base.createCommandBuffer(VkCommandBufferLevel.Primary, true);

                // Image barrier for optimal image

                // The sub resource range describes the regions of the image we will be transition
                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                // Image only contains color data
                subresourceRange.aspectMask = VkImageAspectFlags.Color;
                // Start at first mip level
                subresourceRange.baseMipLevel = 0;
                // We will transition on all mip levels
                subresourceRange.levelCount = texture.mipLevels;
                // The 2D texture only has one layer
                subresourceRange.layerCount = 1;

                // Optimal image will be used as destination for the copy, so we must transfer from our
                // initial undefined image layout to the transfer destination layout
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                vkCmdCopyBufferToImage(
                    copyCmd,
                    stagingBuffer,
                    texture.image,
                    VkImageLayout.TransferDstOptimal,
                    bufferCopyRegions.Count,
                    bufferCopyRegions.Data);

                // Change texture image layout to shader read after all mip levels have been copied
                texture.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.TransferDstOptimal,
                    texture.imageLayout,
                    subresourceRange);

                flushCommandBuffer(copyCmd, Queue, true);

                // Clean up staging resources
                vkFreeMemory(Device, stagingMemory, null);
                vkDestroyBuffer(Device, stagingBuffer, null);
            }
            else
            {
                throw new NotImplementedException();

                /*
                 * // Prefer using optimal tiling, as linear tiling
                 * // may support only a small set of features
                 * // depending on implementation (e.g. no mip maps, only one layer, etc.)
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = VkImageUsageFlags.Sampled;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Preinitialized;
                 * imageCreateInfo.extent = new VkExtent3D { width = texture.width, height = texture.height, depth = 1 };
                 * Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(Device, mappableImage, &memReqs);
                 * // Set memory allocation size to required memory size
                 * memAllocInfo.allocationSize = memReqs.size;
                 *
                 * // Get memory type that can be mapped to host memory
                 * memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits,  VkMemoryPropertyFlags.HostVisible |  VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(Device, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask =  VkImageAspectFlags.Color;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(Device, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(Device, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(Device, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * texture.image = mappableImage;
                 * texture.DeviceMemory = mappableMemory;
                 * texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
                 *
                 * VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
                 *
                 * // Setup image memory barrier transfer image to shader read layout
                 *
                 * // The sub resource range describes the regions of the image we will be transition
                 * VkImageSubresourceRange subresourceRange = { };
                 * // Image only contains color data
                 * subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                 * // Start at first mip level
                 * subresourceRange.baseMipLevel = 0;
                 * // Only one mip level, most implementations won't support more for linear tiled images
                 * subresourceRange.levelCount = 1;
                 * // The 2D texture only has one layer
                 * subresourceRange.layerCount = 1;
                 *
                 * setImageLayout(
                 *  copyCmd,
                 *  texture.image,
                 *  VK_IMAGE_ASPECT_COLOR_BIT,
                 *  VK_IMAGE_LAYOUT_PREINITIALIZED,
                 *  texture.imageLayout,
                 *  subresourceRange);
                 *
                 * VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
                 */
            }

            // Create sampler
            // In Vulkan textures are accessed by samplers
            // This separates all the sampling information from the
            // texture data
            // This means you could have multiple sampler objects
            // for the same texture with different settings
            // Similar to the samplers available with OpenGL 3.3
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();

            sampler.magFilter    = VkFilter.Linear;
            sampler.minFilter    = VkFilter.Linear;
            sampler.mipmapMode   = VkSamplerMipmapMode.Linear;
            sampler.addressModeU = VkSamplerAddressMode.Repeat;
            sampler.addressModeV = VkSamplerAddressMode.Repeat;
            sampler.addressModeW = VkSamplerAddressMode.Repeat;
            sampler.mipLodBias   = 0.0f;
            sampler.compareOp    = VkCompareOp.Never;
            sampler.minLod       = 0.0f;
            // Set max level-of-detail to mip level count of the texture
            sampler.maxLod = (useStaging == 1) ? (float)texture.mipLevels : 0.0f;
            // Enable anisotropic filtering
            // This feature is optional, so we must check if it's supported on the Device
            if (VulkanDevice.Features.samplerAnisotropy == 1)
            {
                // Use max. level of anisotropy for this example
                sampler.maxAnisotropy    = VulkanDevice.Properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            else
            {
                // The Device does not support anisotropic filtering
                sampler.maxAnisotropy    = 1.0f;
                sampler.anisotropyEnable = False;
            }
            sampler.borderColor = VkBorderColor.FloatOpaqueWhite;
            Util.CheckResult(vkCreateSampler(Device, ref sampler, null, out texture.sampler));

            // Create image view
            // Textures are not directly accessed by the shaders and
            // are abstracted by image views containing additional
            // information and sub resource ranges
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();

            view.viewType   = VkImageViewType._2d;
            view.format     = format;
            view.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            // The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view
            // It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image
            view.subresourceRange.aspectMask     = VkImageAspectFlags.Color;
            view.subresourceRange.baseMipLevel   = 0;
            view.subresourceRange.baseArrayLayer = 0;
            view.subresourceRange.layerCount     = 1;
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            view.subresourceRange.levelCount = (useStaging == 1) ? texture.mipLevels : 1;
            // The view will be based on the texture's image
            view.image = texture.image;
            Util.CheckResult(vkCreateImageView(Device, &view, null, out texture.view));
        }