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; }
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)); } }
// 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(); }
// 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(); }
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); }
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); }
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)); }
// 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(); }
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); }
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); }
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); }
// 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, ©Region); copyRegion.size = indexBufferSize; vkCmdCopyBuffer( copyCmd, indexStaging_buffer, model_indices_buffer, 1, ©Region); 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())); } }
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)); }