예제 #1
0
 public PendingFlushImage(BufferPools.MemoryHandle src, TransferArguments arguments, Image dst,
                          VkBufferImageCopy copyDesc) : base(src, arguments)
 {
     Destination = dst;
     CopyData    = copyDesc;
     Destination.IncreasePins();
 }
예제 #2
0
        void CopyBufferToImage(VkBuffer buffer, VkImage image, int width, int height)
        {
            VkCommandBuffer commandBuffer = BeginSingleTimeCommands();

            VkBufferImageCopy region = new VkBufferImageCopy();

            region.bufferOffset      = 0;
            region.bufferRowLength   = 0;
            region.bufferImageHeight = 0;

            region.imageSubresource.aspectMask     = VkImageAspectFlags.ColorBit;
            region.imageSubresource.mipLevel       = 0;
            region.imageSubresource.baseArrayLayer = 0;
            region.imageSubresource.layerCount     = 1;

            region.imageOffset = new VkOffset3D();
            region.imageExtent = new VkExtent3D {
                width  = width,
                height = height,
                depth  = 1
            };

            commandBuffer.CopyBufferToImage(buffer, image, VkImageLayout.TransferDstOptimal, new VkBufferImageCopy[] { region });

            EndSingleTimeCommand(commandBuffer);
        }
예제 #3
0
 public void CopyBufferToImage(VkBuffer buffer, VkImage image, VkBufferImageCopy copyData)
 {
     unsafe
     {
         var local = copyData;
         VkCommandBuffer.vkCmdCopyBufferToImage(Handle, buffer, image, VkImageLayout.TransferDstOptimal, 1,
                                                &local);
     }
 }
예제 #4
0
        public unsafe void Transfer(Image dest, void *data, ulong count, VkBufferImageCopy copyInfo,
                                    TransferArguments?arguments = null)
        {
            CheckArgs(arguments);
            var handle = Device.BufferPools.Allocate(_transferType, Usage, Flags, count);

            Buffer.MemoryCopy(data, handle.MappedMemory.Handle.ToPointer(), handle.Size, count);
            if (!handle.BackingMemory.MemoryType.HostCoherent)
            {
                handle.MappedMemory.FlushRange(0, count);
            }
            _pendingFlush.Enqueue(new PendingFlushImage(handle, arguments ?? TransferArguments.Null, dest, copyInfo));
            _pendingFlushQueued.Set();
        }
예제 #5
0
파일: Buffer.cs 프로젝트: Svengali/vk.net
        public void CopyTo(CommandBuffer cmd, Image img, VkImageLayout finalLayout = VkImageLayout.ShaderReadOnlyOptimal)
        {
            img.SetLayout(cmd, VkImageAspectFlags.Color,
                          VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
                          VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer);

            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
                imageExtent      = img.CreateInfo.extent,
                imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color)
            };

            vkCmdCopyBufferToImage(cmd.Handle, handle, img.handle, VkImageLayout.TransferDstOptimal, 1, ref bufferCopyRegion);

            img.SetLayout(cmd, VkImageAspectFlags.Color,
                          VkImageLayout.TransferDstOptimal, finalLayout,
                          VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllGraphics);
        }
예제 #6
0
        public unsafe static Texture Create2D(uint w, uint h, VkFormat format, IntPtr tex2DDataPtr, bool dynamic = false)
        {
            var texture = new Texture
            {
                extent    = new VkExtent3D(w, h, 1),
                mipLevels = 1,
                format    = format
            };

            texture.image = Image.Create(w, h, VkImageCreateFlags.None, 1, 1, format, VkSampleCountFlags.Count1, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled);

            ulong totalBytes = texture.image.AllocationSize;

            using (Buffer stagingBuffer = Buffer.CreateStagingBuffer(totalBytes, tex2DDataPtr))
            {
                VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy
                {
                    imageSubresource = new VkImageSubresourceLayers
                    {
                        aspectMask     = VkImageAspectFlags.Color,
                        mipLevel       = 0,
                        baseArrayLayer = 0,
                        layerCount     = 1,
                    },

                    imageExtent  = new VkExtent3D(w, h, 1),
                    bufferOffset = 0
                };

                // The sub resource range describes the regions of the image we will be transition
                var           subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1);
                CommandBuffer copyCmd          = Graphics.BeginPrimaryCmd();
                copyCmd.SetImageLayout(texture.image, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subresourceRange);
                copyCmd.CopyBufferToImage(stagingBuffer, texture.image, VkImageLayout.TransferDstOptimal, ref bufferCopyRegion);
                copyCmd.SetImageLayout(texture.image, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal, texture.imageLayout, subresourceRange);
                Graphics.EndPrimaryCmd(copyCmd);

                // Change texture image layout to shader read after all mip levels have been copied
                texture.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
            }

            texture.imageView = ImageView.Create(texture.image, VkImageViewType.Image2D, format, VkImageAspectFlags.Color, 0, texture.mipLevels);
            texture.sampler   = new Sampler(VkFilter.Linear, VkSamplerMipmapMode.Linear, VkSamplerAddressMode.Repeat, texture.mipLevels, Device.Features.samplerAnisotropy == true);
            texture.UpdateDescriptor();
            return(texture);
        }
예제 #7
0
        public unsafe void CopyBufferToImage(
            Buffer buffer,
            Image image,
            uint mipLevel = 0
            )
        {
            var region = new VkBufferImageCopy
            {
                bufferOffset      = 0,
                bufferRowLength   = image.Width,
                bufferImageHeight = image.Height,
                imageOffset       = new VkOffset3D
                {
                    x = 0,
                    y = 0,
                    z = 0
                },
                imageExtent = new VkExtent3D
                {
                    width  = image.Width,
                    height = image.Height,
                    depth  = 1
                },
                imageSubresource = new VkImageSubresourceLayers
                {
                    aspectMask = GetAspectFlags(
                        image.Handle,
                        image.Format,
                        image.Layout[mipLevel]
                        ),
                    mipLevel       = mipLevel,
                    baseArrayLayer = 0,
                    layerCount     = 1
                }
            };

            VulkanNative.vkCmdCopyBufferToImage(
                _handle,
                buffer.Handle,
                image.Handle,
                image.Layout[mipLevel],
                1,
                &region
                );
        }
예제 #8
0
 public void Download(Image src, uint mipLevel, uint baseArrayLayer, uint layerCount, int x, int y, int z, uint w, uint h, uint d, GpuBuffer dst, ulong dst_off)
 {
     if (locked)
     {
         unsafe
         {
             var bufCopy = new VkBufferImageCopy()
             {
                 bufferOffset      = dst_off,
                 bufferRowLength   = 0,
                 bufferImageHeight = 0,
                 imageSubresource  = new VkImageSubresourceLayers()
                 {
                     aspectMask     = VkImageAspectFlags.ImageAspectColorBit,
                     mipLevel       = mipLevel,
                     baseArrayLayer = baseArrayLayer,
                     layerCount     = layerCount
                 },
                 imageOffset = new VkOffset3D()
                 {
                     x = x,
                     y = y,
                     z = z
                 },
                 imageExtent = new VkExtent3D()
                 {
                     width  = w,
                     height = h,
                     depth  = d
                 }
             };
             vkCmdCopyImageToBuffer(hndl, src.hndl, (VkImageLayout)src.CurrentLayout, dst.hndl, 1, bufCopy.Pointer());
             IsEmpty = false;
         }
     }
     else
     {
         throw new Exception("Command buffer not built.");
     }
 }
예제 #9
0
        public unsafe void SetImageData(MipmapLevel[] imageData)
        {
            this.imageData = imageData;
            this.extent    = new VkExtent3D(imageData[0].Width, imageData[0].Height, 1);
            mipLevels      = (uint)imageData.Length;
            layers         = (uint)imageData[0].ArrayElements.Length;
            faceCount      = (uint)imageData[0].ArrayElements[0].Faces.Length;

            ulong totalSize = 0;

            foreach (var mip in imageData)
            {
                totalSize += mip.TotalSize * layers * faceCount;
            }

            Buffer stagingBuffer = Buffer.CreateStagingBuffer(totalSize, IntPtr.Zero);

            image = Image.Create(width, height, imageCreateFlags, layers * faceCount, mipLevels, format, VkSampleCountFlags.Count1, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled);

            IntPtr mapped = stagingBuffer.Map();

            // Setup buffer copy regions for each face including all of it's miplevels
            Span <VkBufferImageCopy> bufferCopyRegions = stackalloc VkBufferImageCopy[(int)(mipLevels * layers * faceCount)];
            uint offset = 0;
            int  index  = 0;

            for (int layer = 0; layer < layers; layer++)
            {
                for (int face = 0; face < faceCount; face++)
                {
                    for (uint level = 0; level < mipLevels; level++)
                    {
                        var mipLevel     = imageData[level];
                        var layerElement = mipLevel.ArrayElements[layer];
                        var faceElement  = layerElement.Faces[face];

                        Unsafe.CopyBlock((void *)(mapped + (int)offset), Unsafe.AsPointer(ref faceElement.Data[0]), (uint)faceElement.Data.Length);

                        VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy
                        {
                            imageSubresource = new VkImageSubresourceLayers
                            {
                                aspectMask     = VkImageAspectFlags.Color,
                                mipLevel       = level,
                                baseArrayLayer = (uint)(layer * faceCount + face),
                                layerCount     = 1
                            },

                            imageExtent  = new VkExtent3D(mipLevel.Width, mipLevel.Height, mipLevel.Depth),
                            bufferOffset = offset
                        };

                        bufferCopyRegions[index++] = bufferCopyRegion;
                        offset += (uint)faceElement.Data.Length;
                    }
                }
            }


            stagingBuffer.Unmap();

            var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, mipLevels, 0, layers * faceCount);

            CommandBuffer copyCmd = Graphics.BeginPrimaryCmd();

            copyCmd.SetImageLayout(image, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subresourceRange);
            copyCmd.CopyBufferToImage(stagingBuffer, image, VkImageLayout.TransferDstOptimal, bufferCopyRegions);
            copyCmd.SetImageLayout(image, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal, imageLayout, subresourceRange);
            Graphics.EndPrimaryCmd(copyCmd);

            imageLayout = VkImageLayout.ShaderReadOnlyOptimal;

            stagingBuffer.Dispose();

            imageView = ImageView.Create(image, ImageViewType, format, VkImageAspectFlags.Color, 0, mipLevels, 0, layers);
            sampler   = new Sampler(VkFilter.Linear, VkSamplerMipmapMode.Linear, samplerAddressMode, mipLevels, Device.Features.samplerAnisotropy == true, borderColor);

            UpdateDescriptor();
        }
예제 #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.Image2D;
            imageCreateInfo.format = format;
            imageCreateInfo.mipLevels = cubeMap.mipLevels;
            imageCreateInfo.samples = VkSampleCountFlags.Count1;
            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.ImageCube;
            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
파일: ktx.cs 프로젝트: jpbruyere/vke.net
        public static Image Load(Queue staggingQ, CommandPool staggingCmdPool, string ktxPath, VkImageUsageFlags usage = VkImageUsageFlags.Sampled,
                                 VkMemoryPropertyFlags memoryProperty = VkMemoryPropertyFlags.DeviceLocal, bool generateMipmaps = true,
                                 VkImageTiling tiling = VkImageTiling.Optimal)
        {
            Image img = null;

            using (Stream ktxStream = File.Open(ktxPath, FileMode.Open, FileAccess.Read)) {
                using (BinaryReader br = new BinaryReader(ktxStream)) {
                    if (!br.ReadBytes(12).AreEquals(ktxSignature))
                    {
                        throw new KtxException("Not a ktx file: " + ktxPath);
                    }

                    UInt32 endianness            = br.ReadUInt32();
                    UInt32 glType                = br.ReadUInt32();
                    UInt32 glTypeSize            = br.ReadUInt32();
                    UInt32 glFormat              = br.ReadUInt32();
                    UInt32 glInternalFormat      = br.ReadUInt32();
                    UInt32 glBaseInternalFormat  = br.ReadUInt32();
                    UInt32 pixelWidth            = br.ReadUInt32();
                    UInt32 pixelHeight           = br.ReadUInt32();
                    UInt32 pixelDepth            = Math.Max(1, br.ReadUInt32());
                    UInt32 numberOfArrayElements = br.ReadUInt32();             //only for array text, else 0
                    UInt32 numberOfFaces         = br.ReadUInt32();             //only for cube map, else 1
                    UInt32 numberOfMipmapLevels  = Math.Max(1, br.ReadUInt32());
                    UInt32 bytesOfKeyValueData   = br.ReadUInt32();

                    VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat(glInternalFormat);
                    if (vkFormat == VkFormat.Undefined)
                    {
                        vkFormat = GLHelper.vkGetFormatFromOpenGLFormat(glFormat, glType);
                        if (vkFormat == VkFormat.Undefined)
                        {
                            throw new KtxException("Undefined format: " + ktxPath);
                        }
                    }
                    VkFormatProperties   formatProperties = staggingQ.Dev.phy.GetFormatProperties(vkFormat);
                    VkFormatFeatureFlags phyFormatSupport = (tiling == VkImageTiling.Linear) ?
                                                            formatProperties.linearTilingFeatures :
                                                            formatProperties.optimalTilingFeatures;

                    uint requestedMipsLevels = numberOfMipmapLevels;
                    if (numberOfMipmapLevels == 1)
                    {
                        requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag(VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ?
                                              (uint)Math.Floor(Math.Log(Math.Max(pixelWidth, pixelHeight))) + 1 : 1;
                    }

                    if (tiling == VkImageTiling.Optimal)
                    {
                        usage |= VkImageUsageFlags.TransferDst;
                    }
                    if (generateMipmaps)
                    {
                        usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
                    }

                    VkImageCreateFlags createFlags = 0;

                    VkImageType imgType =
                        (pixelWidth == 0) ? throw new KtxException("pixelWidth must be > 0") :
                              (pixelHeight == 0) ? imgType = VkImageType.Image1D :
                                                             (pixelDepth == 1) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D;


                    VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;

                    if (numberOfFaces > 1)
                    {
                        if (imgType != VkImageType.Image2D)
                        {
                            throw new KtxException("cubemap faces must be 2D textures");
                        }
                        createFlags           = VkImageCreateFlags.CubeCompatible;
                        samples               = VkSampleCountFlags.SampleCount1;
                        numberOfArrayElements = numberOfFaces;
                    }
                    else
                    {
                        numberOfFaces = 1;
                        if (numberOfArrayElements == 0)
                        {
                            numberOfArrayElements = 1;
                        }
                    }

                    if (!Image.CheckFormatIsSupported(usage, phyFormatSupport))
                    {
                        throw new Exception($"Unsupported image format: {vkFormat}, {tiling}, {usage}");
                    }

                    img = new Image(staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples,
                                    tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags);

                    byte[] keyValueDatas = br.ReadBytes((int)bytesOfKeyValueData);

                    uint blockW, blockH;
                    bool isCompressed = vkFormat.TryGetCompressedFormatBlockSize(out blockW, out blockH);
                    uint blockSize    = blockW * blockH;

                    if (memoryProperty.HasFlag(VkMemoryPropertyFlags.DeviceLocal))
                    {
                        ulong staggingSize = img.AllocatedDeviceMemorySize;
                        Console.WriteLine($"KtxStream size = {ktxStream.Length}, img Allocation = {img.AllocatedDeviceMemorySize}");

                        using (HostBuffer stagging = new HostBuffer(staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) {
                            stagging.Map();

                            PrimaryCommandBuffer cmd = staggingCmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit);
                            img.SetLayout(cmd, VkImageAspectFlags.Color,
                                          VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
                                          VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer);

                            List <VkBufferImageCopy> buffCopies = new List <VkBufferImageCopy> ();

                            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
                                imageExtent      = img.CreateInfo.extent,
                                imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, img.CreateInfo.arrayLayers, 0)
                            };

                            ulong bufferOffset = 0;
                            uint  imgWidth     = img.CreateInfo.extent.width;
                            uint  imgHeight    = img.CreateInfo.extent.height;

                            for (int mips = 0; mips < numberOfMipmapLevels; mips++)
                            {
                                UInt32 imgSize = br.ReadUInt32();

                                bufferCopyRegion.bufferRowLength   = imgWidth;
                                bufferCopyRegion.bufferImageHeight = imgHeight;

                                if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0))
                                {
                                    bufferCopyRegion.bufferRowLength   += blockW - imgWidth % blockW;
                                    bufferCopyRegion.bufferImageHeight += blockH - imgHeight % blockH;
                                }
                                bufferCopyRegion.bufferOffset = bufferOffset;
                                bufferCopyRegion.imageSubresource.mipLevel = (uint)mips;
                                bufferCopyRegion.imageExtent.width         = imgWidth;
                                bufferCopyRegion.imageExtent.height        = imgHeight;

                                if (createFlags.HasFlag(VkImageCreateFlags.CubeCompatible))
                                {
                                    //TODO:handle compressed formats
                                    for (uint face = 0; face < numberOfFaces; face++)
                                    {
                                        Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                        uint faceOffset = imgSize + (imgSize % 4);                                        //cube padding
                                        bufferOffset += faceOffset;
                                    }
                                    buffCopies.Add(bufferCopyRegion);
                                    bufferCopyRegion.bufferOffset = bufferOffset;
                                }
                                else if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0))
                                {
                                    for (int line = 0; line < imgHeight; line++)
                                    {
                                        Marshal.Copy(br.ReadBytes((int)imgWidth), 0, stagging.MappedData + (int)bufferOffset, (int)imgWidth);
                                        bufferOffset += bufferCopyRegion.bufferRowLength;
                                    }
                                    buffCopies.Add(bufferCopyRegion);
                                }
                                else
                                {
                                    Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                    buffCopies.Add(bufferCopyRegion);
                                    bufferOffset += imgSize;
                                }

                                if (isCompressed && bufferOffset % blockSize > 0)
                                {
                                    bufferOffset += blockSize - bufferOffset % blockSize;
                                }

                                imgWidth  /= 2;
                                imgHeight /= 2;
                            }
                            stagging.Unmap();

                            Vk.vkCmdCopyBufferToImage(cmd.Handle, stagging.handle, img.handle, VkImageLayout.TransferDstOptimal,
                                                      (uint)buffCopies.Count, buffCopies.Pin());
                            buffCopies.Unpin();

                            if (requestedMipsLevels > numberOfMipmapLevels)
                            {
                                img.BuildMipmaps(cmd);
                            }
                            else
                            {
                                img.SetLayout(cmd, VkImageAspectFlags.Color,
                                              VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
                                              VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader);
                            }

                            cmd.End();

                            staggingQ.Submit(cmd);
                            staggingQ.WaitIdle();

                            cmd.Free();
                        }
                    }
                    else
                    {
                    }
                }
            }

            return(img);
        }
예제 #12
0
        public static void CreateTexture(VkDevice device, VkPhysicalDevice physicalDevice, int width, int height, byte[] imageSource, out VkImage image, out VkDeviceMemory memory, VkQueue queue, VkCommandBuffer workCommandBuffer)
        {
            var imageCreateInfo = new VkImageCreateInfo()
            {
                imageType = VkImageType.VK_IMAGE_TYPE_2D,
                format    = VkFormat.VK_FORMAT_B8G8R8A8_UNORM,
                extent    = new VkExtent3D(width, height),
                mipLevels = 1,
                usage     = VkImageUsageFlags.VK_IMAGE_USAGE_TRANSFER_DST_BIT | VkImageUsageFlags.VK_IMAGE_USAGE_SAMPLED_BIT,
            };

            VulkanAPI.vkCreateImage(device, ref imageCreateInfo, out image);
            VkMemoryRequirements requirements;

            VulkanAPI.vkGetImageMemoryRequirements(device, image, out requirements);
            VkMemoryPropertyFlags memoryFlags = VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;

            VulkanAPI.vkAllocateMemory(device, physicalDevice, ref requirements, memoryFlags, out memory);
            VulkanAPI.vkBindImageMemory(device, image, memory, 0);

            // ステージングバッファ経由で転送.
            VkBuffer       staging;
            VkDeviceMemory stagingMemory;
            var            stagingFlags = VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;

            CreateBuffer(device, physicalDevice, imageSource.Length, VkBufferUsageFlags.VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingFlags, out staging, out stagingMemory);
            MappedMemoryStream mappedStream;

            VulkanAPI.vkMapMemory(device, stagingMemory, 0, VkDeviceSize.VK_WHOLE_SIZE, 0, out mappedStream);
            mappedStream.Write(imageSource);
            VulkanAPI.vkUnmapMemory(device, stagingMemory);

            var copyRegion = new VkBufferImageCopy()
            {
                imageExtent       = new VkExtent3D(width, height),
                bufferImageHeight = (uint)height,
                imageSubresource  = new VkImageSubresourceLayers()
                {
                    aspectMask     = VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT,
                    mipLevel       = 0,
                    baseArrayLayer = 0,
                    layerCount     = 1,
                }
            };

            // 一時的なコマンドバッファで転送処理.
            var command = workCommandBuffer;

            VulkanAPI.vkBeginCommandBuffer(command);
            setImageMemoryBarrier(command,
                                  0, VkAccessFlags.VK_ACCESS_TRANSFER_WRITE_BIT,
                                  VkImageLayout.VK_IMAGE_LAYOUT_UNDEFINED, VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                  image, VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT);
            VulkanAPI.vkCmdCopyBufferToImage(command, staging, image, VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, new[] { copyRegion });
            setImageMemoryBarrier(command,
                                  VkAccessFlags.VK_ACCESS_TRANSFER_WRITE_BIT, VkAccessFlags.VK_ACCESS_SHADER_READ_BIT,
                                  VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VkImageLayout.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
                                  image, VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT);
            VulkanAPI.vkEndCommandBuffer(command);

            var submitInfo = new VkSubmitInfo()
            {
                commandBuffers = new[] { command },
            };
            var fenceCreateInfo = new VkFenceCreateInfo()
            {
            };
            VkFence fence;

            VulkanAPI.vkCreateFence(device, fenceCreateInfo, out fence);
            VulkanAPI.vkQueueSubmit(queue, new[] { submitInfo }, fence);

            VulkanAPI.vkWaitForFences(device, new[] { fence }, true, ulong.MaxValue);
            VulkanAPI.vkDestroyFence(device, fence);
            VulkanAPI.vkDestroyBuffer(device, staging);
            VulkanAPI.vkFreeMemory(device, stagingMemory);
        }
예제 #13
0
        internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D)
        {
            ulong    size = (ulong)tex2D.Mipmaps[0].Size;
            VkBuffer stagingBuffer;
            var      bufferCreateInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                pNext = null,
                size  = (ulong)tex2D.Mipmaps[0].Size,
                usage = VkBufferUsageFlags.TransferSrc
            };

            vkCreateBuffer(ctx.Device, &bufferCreateInfo, null, out stagingBuffer);

            vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties);
            vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out VkMemoryRequirements stagingMemReq);
            uint heapIndex = BufferHelper.GetMemoryTypeIndex(stagingMemReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible, memoryProperties);

            VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo()
            {
                sType           = VkStructureType.MemoryAllocateInfo,
                pNext           = null,
                allocationSize  = stagingMemReq.size,
                memoryTypeIndex = heapIndex
            };

            VkDeviceMemory stagingMemory;
            VkResult       result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &stagingMemory);

            result.CheckResult();

            result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0);
            result.CheckResult();

            void *vertexPtr;

            result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)tex2D.Mipmaps[0].Size, 0, &vertexPtr);
            result.CheckResult();

            fixed(byte *dataPtr = &tex2D.Mipmaps[0].Data[0])
            {
                Buffer.MemoryCopy(dataPtr, vertexPtr, size, size);
            }

            vkUnmapMemory(ctx.Device, stagingMemory);

            // Setup buffer copy regions for each mip level.
            var bufferCopyRegions = new VkBufferImageCopy[tex2D.Mipmaps.Length]; // TODO: stackalloc
            int offset            = 0;

            for (int i = 0; i < bufferCopyRegions.Length; i++)
            {
                // TODO: from VulkanCore, doesn't look correct (reassigns bufferCopyRegions in each loop)
                bufferCopyRegions = new[]
                {
                    new VkBufferImageCopy
                    {
                        imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)i, 0, 1),
                        imageExtent      = tex2D.Mipmaps[0].Extent,
                        bufferOffset     = (ulong)offset
                    }
                };
                offset += tex2D.Mipmaps[i].Size;
            }

            // Create optimal tiled target image.
            var createInfo = new VkImageCreateInfo
            {
                sType         = VkStructureType.ImageCreateInfo,
                pNext         = null,
                imageType     = VkImageType.Image2D,
                format        = tex2D.Format,
                mipLevels     = (uint)tex2D.Mipmaps.Length,
                arrayLayers   = 1,
                samples       = VkSampleCountFlags.Count1,
                tiling        = VkImageTiling.Optimal,
                sharingMode   = VkSharingMode.Exclusive,
                initialLayout = VkImageLayout.Undefined,
                extent        = tex2D.Mipmaps[0].Extent,
                usage         = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst
            };

            VkImage image;

            result = vkCreateImage(ctx.Device, &createInfo, null, out image);
            result.CheckResult();

            VkMemoryRequirements imageMemReq;

            vkGetImageMemoryRequirements(ctx.Device, image, out imageMemReq);

            vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties imageMemoryProperties);

            uint imageHeapIndex = BufferHelper.GetMemoryTypeIndex(imageMemReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, imageMemoryProperties);

            var allocInfo = new VkMemoryAllocateInfo
            {
                sType           = VkStructureType.MemoryAllocateInfo,
                pNext           = null,
                allocationSize  = imageMemReq.size,
                memoryTypeIndex = imageHeapIndex,
            };
            VkDeviceMemory memory;

            result = vkAllocateMemory(ctx.Device, &allocInfo, null, &memory);
            result.CheckResult();

            result = vkBindImageMemory(ctx.Device, image, memory, 0);
            result.CheckResult();

            var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, (uint)tex2D.Mipmaps.Length, 0, 1);

            // Copy the data from staging buffers to device local buffers.
            var allocInfo2 = new VkCommandBufferAllocateInfo()
            {
                sType       = VkStructureType.CommandBufferAllocateInfo,
                commandPool = ctx.GraphicsCommandPool,

                level = VkCommandBufferLevel.Primary,
                commandBufferCount = 1,
            };
            VkCommandBuffer cmdBuffer;

            vkAllocateCommandBuffers(ctx.Device, &allocInfo2, &cmdBuffer);

            VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo()
            {
                sType = VkStructureType.CommandBufferBeginInfo,
                flags = VkCommandBufferUsageFlags.OneTimeSubmit,
            };

            vkBeginCommandBuffer(cmdBuffer, &beginInfo);

            VkImageMemoryBarrier imageMemoryBarrier = new VkImageMemoryBarrier
            {
                sType               = VkStructureType.ImageMemoryBarrier,
                pNext               = null,
                image               = image,
                subresourceRange    = subresourceRange,
                srcAccessMask       = 0,
                dstAccessMask       = VkAccessFlags.TransferWrite,
                oldLayout           = VkImageLayout.Undefined,
                newLayout           = VkImageLayout.TransferDstOptimal,
                srcQueueFamilyIndex = QueueFamilyIgnored,
                dstQueueFamilyIndex = QueueFamilyIgnored
            };

            vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier);

            fixed(VkBufferImageCopy *regionsPtr = bufferCopyRegions)
            {
                vkCmdCopyBufferToImage(cmdBuffer, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (uint)bufferCopyRegions.Length, regionsPtr);
            }

            VkImageMemoryBarrier imageMemoryBarrier2 = new VkImageMemoryBarrier
            {
                sType               = VkStructureType.ImageMemoryBarrier,
                pNext               = null,
                image               = image,
                subresourceRange    = subresourceRange,
                srcAccessMask       = VkAccessFlags.TransferWrite,
                dstAccessMask       = VkAccessFlags.ShaderRead,
                oldLayout           = VkImageLayout.TransferDstOptimal,
                newLayout           = VkImageLayout.ShaderReadOnlyOptimal,
                srcQueueFamilyIndex = (uint)QueueFamilyIgnored,
                dstQueueFamilyIndex = (uint)QueueFamilyIgnored
            };

            vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier2);

            vkEndCommandBuffer(cmdBuffer);

            // Submit.
            VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo
            {
                sType = VkStructureType.FenceCreateInfo,
                pNext = null
            };
            VkFence fence;

            result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence);
            result.CheckResult();

            var submitInfo = new VkSubmitInfo
            {
                sType = VkStructureType.SubmitInfo,
                pNext = null,
                commandBufferCount = 1,
                pCommandBuffers    = &cmdBuffer
            };

            vkQueueSubmit(ctx.GraphicsQueue, submitInfo, fence);

            result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue);
            result.CheckResult();

            // Cleanup staging resources.
            vkDestroyFence(ctx.Device, fence, null);
            vkFreeMemory(ctx.Device, stagingMemory, null);
            vkDestroyBuffer(ctx.Device, stagingBuffer, null);

            // Create image view.
            VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo()
            {
                sType            = VkStructureType.ImageViewCreateInfo,
                image            = image,
                viewType         = VkImageViewType.Image2D,
                format           = tex2D.Format,
                subresourceRange = subresourceRange
            };

            VkImageView view;

            vkCreateImageView(ctx.Device, &imageViewCreateInfo, null, out view);

            return(new VulkanImage(ctx, image, memory, view, tex2D.Format));
        }
예제 #14
0
        /// <inheritdoc cref="Copy(GraphicsTexture, GraphicsBuffer)" />
        public void Copy(VulkanGraphicsTexture destination, VulkanGraphicsBuffer source)
        {
            ThrowIfNull(destination, nameof(destination));
            ThrowIfNull(source, nameof(source));

            var vulkanCommandBuffer = VulkanCommandBuffer;
            var vulkanImage         = destination.VulkanImage;

            BeginCopy();

            var vulkanBufferImageCopy = new VkBufferImageCopy {
                imageSubresource = new VkImageSubresourceLayers {
                    aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT,
                    layerCount = 1,
                },
                imageExtent = new VkExtent3D {
                    width  = (uint)destination.Width,
                    height = destination.Height,
                    depth  = destination.Depth,
                },
            };

            vkCmdCopyBufferToImage(vulkanCommandBuffer, source.VulkanBuffer, vulkanImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vulkanBufferImageCopy);

            EndCopy();

            void BeginCopy()
            {
                var vulkanImageMemoryBarrier = new VkImageMemoryBarrier {
                    sType            = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
                    dstAccessMask    = (uint)VK_ACCESS_TRANSFER_WRITE_BIT,
                    oldLayout        = VK_IMAGE_LAYOUT_UNDEFINED,
                    newLayout        = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                    image            = vulkanImage,
                    subresourceRange = new VkImageSubresourceRange {
                        aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT,
                        levelCount = 1,
                        layerCount = 1,
                    },
                };

                vkCmdPipelineBarrier(vulkanCommandBuffer, (uint)VK_PIPELINE_STAGE_HOST_BIT, (uint)VK_PIPELINE_STAGE_TRANSFER_BIT, dependencyFlags: 0, memoryBarrierCount: 0, pMemoryBarriers: null, bufferMemoryBarrierCount: 0, pBufferMemoryBarriers: null, imageMemoryBarrierCount: 1, &vulkanImageMemoryBarrier);
            }

            void EndCopy()
            {
                var vulkanImageMemoryBarrier = new VkImageMemoryBarrier {
                    sType            = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
                    srcAccessMask    = (uint)VK_ACCESS_TRANSFER_WRITE_BIT,
                    dstAccessMask    = (uint)VK_ACCESS_SHADER_READ_BIT,
                    oldLayout        = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                    newLayout        = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
                    image            = vulkanImage,
                    subresourceRange = new VkImageSubresourceRange {
                        aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT,
                        levelCount = 1,
                        layerCount = 1,
                    },
                };

                vkCmdPipelineBarrier(vulkanCommandBuffer, (uint)VK_PIPELINE_STAGE_TRANSFER_BIT, (uint)VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, dependencyFlags: 0, memoryBarrierCount: 0, pMemoryBarriers: null, bufferMemoryBarrierCount: 0, pBufferMemoryBarriers: null, imageMemoryBarrierCount: 1, &vulkanImageMemoryBarrier);
            }
        }
예제 #15
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.Image2D;
                imageCreateInfo.format      = format;
                imageCreateInfo.mipLevels   = texture.mipLevels;
                imageCreateInfo.arrayLayers = 1;
                imageCreateInfo.samples     = VkSampleCountFlags.Count1;
                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.Image2D;
            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));
        }
예제 #16
0
파일: ktx.cs 프로젝트: Svengali/vk.net
        public static Image Load(Queue staggingQ, CommandPool staggingCmdPool, string ktxPath, VkImageUsageFlags usage = VkImageUsageFlags.Sampled,
                                 VkMemoryPropertyFlags memoryProperty = VkMemoryPropertyFlags.DeviceLocal, bool generateMipmaps = true,
                                 VkImageTiling tiling = VkImageTiling.Optimal)
        {
            Image img = null;

            using (Stream ktxStream = File.Open(ktxPath, FileMode.Open, FileAccess.Read)) {
                using (BinaryReader br = new BinaryReader(ktxStream)) {
                    if (!br.ReadBytes(12).AreEquals(ktxSignature))
                    {
                        throw new KtxException("Not a ktx file: " + ktxPath);
                    }

                    UInt32 endianness            = br.ReadUInt32();
                    UInt32 glType                = br.ReadUInt32();
                    UInt32 glTypeSize            = br.ReadUInt32();
                    UInt32 glFormat              = br.ReadUInt32();
                    UInt32 glInternalFormat      = br.ReadUInt32();
                    UInt32 glBaseInternalFormat  = br.ReadUInt32();
                    UInt32 pixelWidth            = br.ReadUInt32();
                    UInt32 pixelHeight           = br.ReadUInt32();
                    UInt32 pixelDepth            = Math.Min(1, br.ReadUInt32());
                    UInt32 numberOfArrayElements = br.ReadUInt32();             //only for array text, else 0
                    UInt32 numberOfFaces         = br.ReadUInt32();             //only for cube map, else
                    UInt32 numberOfMipmapLevels  = Math.Min(1, br.ReadUInt32());
                    UInt32 bytesOfKeyValueData   = br.ReadUInt32();

                    VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat(glInternalFormat);
                    if (vkFormat == VkFormat.Undefined)
                    {
                        vkFormat = GLHelper.vkGetFormatFromOpenGLFormat(glFormat, glType);
                        if (vkFormat == VkFormat.Undefined)
                        {
                            throw new KtxException("Undefined format: " + ktxPath);
                        }
                    }

                    VkFormatFeatureFlags phyFormatSupport = (tiling == VkImageTiling.Linear) ?
                                                            staggingQ.Dev.phy.GetFormatProperties(vkFormat).linearTilingFeatures :
                                                            staggingQ.Dev.phy.GetFormatProperties(vkFormat).optimalTilingFeatures;

                    uint requestedMipsLevels = numberOfMipmapLevels;
                    if (numberOfMipmapLevels == 1)
                    {
                        requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag(VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ?
                                              (uint)Math.Floor(Math.Log(Math.Max(pixelWidth, pixelHeight))) + 1 : 1;
                    }

                    if (tiling == VkImageTiling.Optimal)
                    {
                        usage |= VkImageUsageFlags.TransferDst;
                    }
                    if (generateMipmaps)
                    {
                        usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
                    }

                    VkImageCreateFlags createFlags = 0;

                    VkImageType imgType =
                        (pixelWidth == 0) ? throw new KtxException("pixelWidth must be > 0") :
                              (pixelHeight == 0) ? imgType = VkImageType.Image1D :
                                                             (pixelDepth == 0) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D;


                    VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;

                    if (numberOfFaces > 1)
                    {
                        if (imgType != VkImageType.Image2D)
                        {
                            throw new KtxException("cubemap faces must be 2D textures");
                        }
                        createFlags           = VkImageCreateFlags.CubeCompatible;
                        samples               = VkSampleCountFlags.SampleCount1;
                        numberOfArrayElements = numberOfFaces;
                    }
                    else
                    {
                        numberOfFaces = 1;
                        if (numberOfArrayElements == 0)
                        {
                            numberOfArrayElements = 1;
                        }
                    }

                    if (imgType != VkImageType.Image3D)
                    {
                        pixelDepth = 1;
                    }

                    img = new Image(staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples,
                                    tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags);

                    byte[] keyValueDatas = br.ReadBytes((int)bytesOfKeyValueData);


                    if (memoryProperty.HasFlag(VkMemoryPropertyFlags.DeviceLocal))
                    {
                        ulong staggingSize = img.AllocatedDeviceMemorySize;


                        using (HostBuffer stagging = new HostBuffer(staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) {
                            stagging.Map();

                            CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer();
                            cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit);
                            img.SetLayout(cmd, VkImageAspectFlags.Color,
                                          VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
                                          VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer);

                            List <VkBufferImageCopy> buffCopies = new List <VkBufferImageCopy> ();

                            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
                                imageExtent      = img.CreateInfo.extent,
                                imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, img.CreateInfo.arrayLayers, 0)
                            };

                            ulong bufferOffset = 0;
                            uint  imgWidth     = img.CreateInfo.extent.height;
                            uint  imgHeight    = img.CreateInfo.extent.width;

                            for (int mips = 0; mips < numberOfMipmapLevels; mips++)
                            {
                                UInt32 imgSize = br.ReadUInt32();

                                bufferCopyRegion.bufferImageHeight = imgWidth;
                                bufferCopyRegion.bufferRowLength   = imgHeight;
                                bufferCopyRegion.bufferOffset      = bufferOffset;

                                if (createFlags.HasFlag(VkImageCreateFlags.CubeCompatible))
                                {
                                    IntPtr ptrFace = img.MappedData;
                                    bufferCopyRegion.imageSubresource.layerCount = 1;
                                    for (uint face = 0; face < numberOfFaces; face++)
                                    {
                                        bufferCopyRegion.imageSubresource.baseArrayLayer = face;
                                        Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                        buffCopies.Add(bufferCopyRegion);
                                        uint faceOffset = imgSize + (imgSize % 4);
                                        ptrFace      += (int)faceOffset;                                   //cube padding
                                        bufferOffset += faceOffset;
                                        bufferCopyRegion.bufferOffset = bufferOffset;
                                    }
                                }
                                else
                                {
                                    Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData, (int)imgSize);
                                    buffCopies.Add(bufferCopyRegion);
                                }
                                bufferOffset += imgSize;
                                imgWidth     /= 2;
                                imgHeight    /= 2;
                            }
                            stagging.Unmap();
                            Vk.vkCmdCopyBufferToImage(cmd.Handle, stagging.handle, img.handle, VkImageLayout.TransferDstOptimal,
                                                      (uint)buffCopies.Count, buffCopies.Pin());
                            buffCopies.Unpin();

                            if (requestedMipsLevels > numberOfMipmapLevels)
                            {
                                img.BuildMipmaps(cmd);
                            }
                            else
                            {
                                img.SetLayout(cmd, VkImageAspectFlags.Color,
                                              VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
                                              VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllGraphics);
                            }

                            cmd.End();

                            staggingQ.Submit(cmd);
                            staggingQ.WaitIdle();

                            cmd.Free();
                        }

                        //for (int mips = 0; mips < numberOfMipmapLevels; mips++) {
                        //UInt32 imgSize = br.ReadUInt32 ();

                        /*VkImageBlit imageBlit = new VkImageBlit {
                         *      srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, numberOfArrayElements, (uint)mips - 1),
                         *      srcOffsets_1 = new VkOffset3D((int)pixelWidth >> (mips - 1), (int)pixelHeight >> (mips - 1),1),
                         *      dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, numberOfArrayElements, (uint)mips),
                         *      dstOffsets_1 = new VkOffset3D ((int)pixelWidth >> mips, (int)pixelHeight >> mips, 1),
                         * };*/
                        //for (int layer = 0; layer < numberOfArrayElements; layer++) {
                        //for (int face = 0; face < numberOfFaces; face++) {
                        //for (int slice = 0; slice < pixelDepth; slice++) {

                        /*for (int y = 0; y < pixelHeight; y++) {
                         *      for (int x = 0; x < pixelWidth; x++) {
                         *              //Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
                         *      }
                         * }*/
                        //}
                        //Byte cubePadding[0-3]
                        //}
                        //}
                        //Byte mipPadding[0-3]
                        //}
                    }
                }
            }

            return(img);
        }
예제 #17
0
        /**
         * Load a 2D texture including all mip levels
         *
         * @param filename File to load (supports .ktx and .dds)
         * @param format Vulkan format of the image data stored in the file
         * @param device Vulkan device to create the texture on
         * @param copyQueue Queue used for the texture staging copy commands (must support transfer)
         * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
         * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
         * @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
         *
         */
        public void loadFromFile(
            string filename,
            VkFormat format,
            vksVulkanDevice device,
            VkQueue copyQueue,
            VkImageUsageFlagBits imageUsageFlags = VkImageUsageFlagBits.Sampled,
            VkImageLayout imageLayout            = VkImageLayout.ShaderReadOnlyOptimal,
            bool forceLinear = false)
        {
            KtxFile tex2D;

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

            this.device = device;
            width       = tex2D.Header.PixelWidth;
            height      = tex2D.Header.PixelHeight;
            if (height == 0)
            {
                height = width;
            }
            mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get device properites for the requested texture format
            VkFormatProperties formatProperties;

            vkGetPhysicalDeviceFormatProperties(device.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.)
            bool useStaging = !forceLinear;

            VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo();

            memAllocInfo.sType = MemoryAllocateInfo;
            VkMemoryRequirements memReqs;

            // Use a separate command buffer for texture loading
            VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true);

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

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

                vkCreateBuffer(device.LogicalDevice, &bufferCreateInfo, null, &stagingBuffer);

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

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

                vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &stagingMemory);
                vkBindBufferMemory(device.LogicalDevice, stagingBuffer, stagingMemory, 0);

                // Copy texture data into staging buffer
                IntPtr data;
                vkMapMemory(device.LogicalDevice, stagingMemory, 0, memReqs.size, 0, &data);
                byte[] pixelData = tex2D.GetAllTextureData();
                fixed(byte *pixelDataPtr = &pixelData[0])
                {
                    Unsafe.CopyBlock(data, pixelDataPtr, (uint)pixelData.Length);
                }

                vkUnmapMemory(device.LogicalDevice, stagingMemory);

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

                for (uint i = 0; i < mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlagBits.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 = new VkImageCreateInfo();
                imageCreateInfo.sType         = ImageCreateInfo;
                imageCreateInfo.imageType     = VkImageType._2d;
                imageCreateInfo.format        = format;
                imageCreateInfo.mipLevels     = mipLevels;
                imageCreateInfo.arrayLayers   = 1;
                imageCreateInfo.samples       = VkSampleCountFlagBits._1;
                imageCreateInfo.tiling        = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = width, height = height, depth = 1
                };
                imageCreateInfo.usage = imageUsageFlags;
                // Ensure that the TRANSFER_DST bit is set for staging
                if ((imageCreateInfo.usage & VkImageUsageFlagBits.TransferDst) == 0)
                {
                    imageCreateInfo.usage |= VkImageUsageFlagBits.TransferDst;
                }
                {
                    VkImage vkImage;
                    vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &vkImage);
                    this.image = vkImage;
                }

                vkGetImageMemoryRequirements(device.LogicalDevice, image, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;

                memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits,
                                                                    VkMemoryPropertyFlagBits.DeviceLocal);
                {
                    VkDeviceMemory memory;
                    vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &memory);
                    this.deviceMemory = memory;
                }
                vkBindImageMemory(device.LogicalDevice, image, deviceMemory, 0);

                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                subresourceRange.aspectMask   = VkImageAspectFlagBits.Color;
                subresourceRange.baseMipLevel = 0;
                subresourceRange.levelCount   = mipLevels;
                subresourceRange.layerCount   = 1;

                // Image barrier for optimal image (target)
                // Optimal image will be used as destination for the copy
                Tools.setImageLayout(
                    copyCmd,
                    image,
                    VkImageAspectFlagBits.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                fixed(VkBufferImageCopy *pointer = bufferCopyRegions.ToArray())
                {
                    vkCmdCopyBufferToImage(
                        copyCmd,
                        stagingBuffer,
                        image,
                        VkImageLayout.TransferDstOptimal,
                        (UInt32)bufferCopyRegions.Count,
                        pointer);
                }

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

                device.flushCommandBuffer(copyCmd, copyQueue);

                // Clean up staging resources
                vkFreeMemory(device.LogicalDevice, stagingMemory, null);
                vkDestroyBuffer(device.LogicalDevice, 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.)
                 *
                 * // Check if this support is supported for linear tiling
                 * Debug.Assert((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != 0);
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.extent = new VkExtent3D { width = width, height = height, depth = 1 };
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = imageUsageFlags;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * Util.CheckResult(vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(device.LogicalDevice, 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 = device.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(device.LogicalDevice, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask = VkImageAspectFlags.Color;
                 * subRes.mipLevel = 0;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(device.LogicalDevice, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(device.LogicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(device.LogicalDevice, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * image = mappableImage;
                 * deviceMemory = mappableMemory;
                 * imageLayout = imageLayout;
                 *
                 * // Setup image memory barrier
                 * vks::tools::setImageLayout(copyCmd, image, VkImageAspectFlags.Color, VkImageLayout.Undefined, imageLayout);
                 *
                 * device.flushCommandBuffer(copyCmd, copyQueue);
                 */
            }

            // Create a defaultsampler
            VkSamplerCreateInfo samplerCreateInfo = new VkSamplerCreateInfo();

            samplerCreateInfo.sType        = SamplerCreateInfo;
            samplerCreateInfo.magFilter    = VkFilter.Linear;
            samplerCreateInfo.minFilter    = VkFilter.Linear;
            samplerCreateInfo.mipmapMode   = VkSamplerMipmapMode.Linear;
            samplerCreateInfo.addressModeU = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeV = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeW = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.mipLodBias   = 0.0f;
            samplerCreateInfo.compareOp    = VkCompareOp.Never;
            samplerCreateInfo.minLod       = 0.0f;
            // Max level-of-detail should match mip level count
            samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
            // Enable anisotropic filtering
            samplerCreateInfo.maxAnisotropy    = 8;
            samplerCreateInfo.anisotropyEnable = true;
            samplerCreateInfo.borderColor      = VkBorderColor.FloatOpaqueWhite;
            {
                VkSampler vkSampler;
                vkCreateSampler(device.LogicalDevice, &samplerCreateInfo, null, &vkSampler);
                this.sampler = vkSampler;
            }

            // 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 viewCreateInfo = new VkImageViewCreateInfo();

            viewCreateInfo.sType      = ImageViewCreateInfo;
            viewCreateInfo.viewType   = VkImageViewType._2d;
            viewCreateInfo.format     = format;
            viewCreateInfo.components = new VkComponentMapping {
                r = VkComponentSwizzle.R,
                g = VkComponentSwizzle.G,
                b = VkComponentSwizzle.B,
                a = VkComponentSwizzle.A
            };
            viewCreateInfo.subresourceRange = new VkImageSubresourceRange {
                aspectMask   = VkImageAspectFlagBits.Color,
                baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
            };
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
            viewCreateInfo.image = image;
            {
                VkImageView vkImageView;
                vkCreateImageView(device.LogicalDevice, &viewCreateInfo, null, &vkImageView);
                this.view = vkImageView;
            }

            // Update descriptor image info member that can be used for setting up descriptor sets
            updateDescriptor();
        }
예제 #18
0
        private unsafe void InitializeImage(DataBox[] dataBoxes)
        {
            // Begin copy command buffer
            var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo
            {
                sType              = VkStructureType.CommandBufferAllocateInfo,
                commandPool        = GraphicsDevice.NativeCopyCommandPool,
                commandBufferCount = 1,
                level              = VkCommandBufferLevel.Primary
            };
            VkCommandBuffer commandBuffer;

            lock (GraphicsDevice.QueueLock)
            {
                vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer);
            }

            var beginInfo = new VkCommandBufferBeginInfo {
                sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit
            };

            vkBeginCommandBuffer(commandBuffer, &beginInfo);

            if (dataBoxes != null && dataBoxes.Length > 0)
            {
                // Buffer-to-image copies need to be aligned to the pixel size and 4 (always a power of 2)
                var blockSize     = Format.IsCompressed() ? NativeFormat.BlockSizeInBytes() : TexturePixelSize;
                var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1;

                int totalSize = dataBoxes.Length * alignmentMask;
                for (int i = 0; i < dataBoxes.Length; i++)
                {
                    totalSize += dataBoxes[i].SlicePitch;
                }

                VkBuffer uploadResource;
                int      uploadOffset;
                var      uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset);

                // Upload buffer barrier
                var bufferMemoryBarrier = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize);

                // Image barrier
                var initialBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), VkAccessFlags.None, VkAccessFlags.TransferWrite, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal);
                vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier);

                // Copy data boxes to upload buffer
                var copies = new VkBufferImageCopy[dataBoxes.Length];
                for (int i = 0; i < copies.Length; i++)
                {
                    var slicePitch = dataBoxes[i].SlicePitch;

                    int arraySlice        = i / MipLevels;
                    int mipSlice          = i % MipLevels;
                    var mipMapDescription = GetMipMapDescription(mipSlice);

                    var alignment = ((uploadOffset + alignmentMask) & ~alignmentMask) - uploadOffset;
                    uploadMemory += alignment;
                    uploadOffset += alignment;

                    Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch);

                    // TODO VULKAN: Check if pitches are valid
                    copies[i] = new VkBufferImageCopy
                    {
                        bufferOffset      = (ulong)uploadOffset,
                        imageSubresource  = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)mipSlice, (uint)arraySlice, 1),
                        bufferRowLength   = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize),
                        bufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch),
                        imageOffset       = new Vortice.Mathematics.Point3(0, 0, 0),
                        imageExtent       = new Vortice.Mathematics.Size3(mipMapDescription.Width, mipMapDescription.Height, mipMapDescription.Depth)
                    };

                    uploadMemory += slicePitch;
                    uploadOffset += slicePitch;
                }

                // Copy from upload buffer to image
                fixed(VkBufferImageCopy *copiesPointer = &copies[0])
                {
                    vkCmdCopyBufferToImage(commandBuffer, uploadResource, NativeImage, VkImageLayout.TransferDstOptimal, (uint)copies.Length, copiesPointer);
                }

                IsInitialized = true;
            }

            // Transition to default layout
            var imageMemoryBarrier = new VkImageMemoryBarrier(NativeImage,
                                                              new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue),
                                                              dataBoxes == null || dataBoxes.Length == 0 ? VkAccessFlags.None : VkAccessFlags.TransferWrite, NativeAccessMask,
                                                              dataBoxes == null || dataBoxes.Length == 0 ? VkImageLayout.Undefined : VkImageLayout.TransferDstOptimal, NativeLayout);

            vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier);

            // Close and submit
            vkEndCommandBuffer(commandBuffer);

            var submitInfo = new VkSubmitInfo
            {
                sType = VkStructureType.SubmitInfo,
                commandBufferCount = 1,
                pCommandBuffers    = &commandBuffer,
            };

            lock (GraphicsDevice.QueueLock)
            {
                vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null);
                vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue);
                vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
            }
        }
예제 #19
0
        private void TransferData(Image <Rgba32> tex2D)
        {
            using CommandBuffer copyCmd = device.GetCommandPool().Rent();

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

            copyCmd.Begin();

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


            var pixels    = tex2D.GetPixelSpan();
            var byteCount = (ulong)(pixels.Length * Unsafe.SizeOf <Rgba32>());

            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();

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

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

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

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

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

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

            Util.CheckResult(vkMapMemory(device.device, stagingMemory, 0, memReqs.size, 0, (void **)&data));

            fixed(Rgba32 *pixelDataPtr = &pixels[0])
            {
                Unsafe.CopyBlock(data, pixelDataPtr, (uint)byteCount);
            }

            vkUnmapMemory(device.device, stagingMemory);

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

            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();

            bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
            bufferCopyRegion.imageSubresource.mipLevel       = 0;
            bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
            bufferCopyRegion.imageSubresource.layerCount     = 1;
            bufferCopyRegion.imageExtent.width  = (uint)tex2D.Width;
            bufferCopyRegion.imageExtent.height = (uint)tex2D.Height;
            bufferCopyRegion.imageExtent.depth  = 1;
            bufferCopyRegion.bufferOffset       = offset;

            bufferCopyRegions.Add(bufferCopyRegion);

            VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();

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

            // Image barrier for optimal image (target)
            // Optimal image will be used as destination for the copy
            Tools.setImageLayout(
                copyCmd.vkCmd,
                image,
                VkImageAspectFlags.Color,
                VkImageLayout.Undefined,
                VkImageLayout.TransferDstOptimal,
                subresourceRange);

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

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

            copyCmd.End();
            device.FlushCommandBuffer(copyCmd);

            //device.flushCommandBuffer(copyCmd, copyQueue);

            // Clean up staging resources
            vkFreeMemory(device.device, stagingMemory, null);
            vkDestroyBuffer(device.device, stagingBuffer, null);
        }
예제 #20
0
        private static VkImage LoadTexture(VkDevice device, VkPhysicalDevice physicalDevice, int cmdPoolID, VkQueue queue, string[] paths, uint mipLevels)
        {
            Bitmap[]             bitmaps    = new Bitmap[paths.Length];
            FDataBuffer <byte>[] tempBuffer = new FDataBuffer <byte> [paths.Length];

            uint width = 0, height = 0;

            for (int j = 0; j < paths.Length; j++)
            {
                bitmaps[j] = new Bitmap(System.Drawing.Image.FromFile(paths[j]));

                var data = bitmaps[j].LockBits(new Rectangle(0, 0, bitmaps[j].Width, bitmaps[j].Height), System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                               bitmaps[j].PixelFormat);
                width  = (uint)data.Width;
                height = (uint)data.Height;//TODO add size check


                Span <byte> img = new Span <byte>((void *)data.Scan0, data.Stride * data.Height);

                tempBuffer[j] = new FDataBuffer <byte>(device, physicalDevice, img.Length, VkBufferUsageFlags.TransferSrc,
                                                       VkSharingMode.Exclusive);

                Span <byte> buffer = tempBuffer[j].Map();
                for (int i = 0; i < img.Length; i += 4)
                {
                    buffer[i + 2] = img[i];
                    buffer[i + 1] = img[i + 1];
                    buffer[i]     = img[i + 2];
                    buffer[i + 3] = img[i + 3];
                }
                buffer = tempBuffer[j].UnMap();
            }

            VkImage        texture = VkImage.Null;
            VkDeviceMemory memory  = VkDeviceMemory.Null;

            VkImageCreateInfo createInfo = VkImageCreateInfo.New();

            createInfo.imageType     = VkImageType.Image2D;
            createInfo.extent.width  = width;
            createInfo.extent.height = height;
            createInfo.extent.depth  = 1;
            createInfo.mipLevels     = mipLevels;
            createInfo.arrayLayers   = (uint)paths.Length;
            createInfo.format        = VkFormat.R8g8b8a8Unorm;
            createInfo.tiling        = VkImageTiling.Optimal;
            createInfo.initialLayout = VkImageLayout.Undefined;
            createInfo.usage         = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc;
            createInfo.sharingMode   = VkSharingMode.Exclusive;
            createInfo.samples       = VkSampleCountFlags.Count1;

            Assert(vkCreateImage(device, &createInfo, null, &texture));

            VkMemoryRequirements memoryRequirements;

            vkGetImageMemoryRequirements(device, texture, &memoryRequirements);

            VkPhysicalDeviceMemoryProperties memoryProperties = new VkPhysicalDeviceMemoryProperties();

            vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);

            VkMemoryAllocateInfo allocateInfo = VkMemoryAllocateInfo.New();

            allocateInfo.allocationSize  = memoryRequirements.size;
            allocateInfo.memoryTypeIndex = FDataBuffer <byte> .SelectMemoryType(memoryProperties, memoryRequirements.memoryTypeBits,
                                                                                VkMemoryPropertyFlags.DeviceLocal);

            Assert(vkAllocateMemory(device, &allocateInfo, null, &memory));

            vkBindImageMemory(device, texture, memory, 0);

            VkCommandBufferAllocateInfo pAllocateInfo = VkCommandBufferAllocateInfo.New();

            pAllocateInfo.commandPool        = CommandPoolManager.GetPool(cmdPoolID);
            pAllocateInfo.level              = VkCommandBufferLevel.Primary;
            pAllocateInfo.commandBufferCount = 1;

            VkCommandBuffer cmdBuffer = VkCommandBuffer.Null;

            Assert(vkAllocateCommandBuffers(device, &pAllocateInfo, &cmdBuffer));

            VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New();

            beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit;

            Assert(vkBeginCommandBuffer(cmdBuffer, &beginInfo));

            VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New();

            imageMemoryBarrier.srcAccessMask       = VkAccessFlags.None;
            imageMemoryBarrier.dstAccessMask       = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite;
            imageMemoryBarrier.oldLayout           = VkImageLayout.Undefined;
            imageMemoryBarrier.newLayout           = VkImageLayout.TransferDstOptimal;
            imageMemoryBarrier.srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored;
            imageMemoryBarrier.dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored;
            imageMemoryBarrier.image            = texture;
            imageMemoryBarrier.subresourceRange = new VkImageSubresourceRange()
            {
                baseMipLevel   = 0,
                levelCount     = mipLevels,
                baseArrayLayer = 0,
                layerCount     = (uint)paths.Length,
                aspectMask     = VkImageAspectFlags.Color
            };

            vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion,
                                 0, null, 0, null, 1, &imageMemoryBarrier);

            for (int j = 0; j < tempBuffer.Length; j++)
            {
                VkBufferImageCopy region = new VkBufferImageCopy();
                region.bufferOffset      = 0;
                region.bufferRowLength   = 0;
                region.bufferImageHeight = 0;

                region.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                region.imageSubresource.mipLevel       = 0;
                region.imageSubresource.baseArrayLayer = (uint)j;
                region.imageSubresource.layerCount     = 1;

                region.imageOffset = new VkOffset3D();
                region.imageExtent = new VkExtent3D()
                {
                    width = width, height = height, depth = 1
                };

                vkCmdCopyBufferToImage(cmdBuffer, tempBuffer[j].Buffer, texture, VkImageLayout.TransferDstOptimal, 1, &region);
            }

            imageMemoryBarrier.oldLayout = VkImageLayout.TransferDstOptimal;
            imageMemoryBarrier.newLayout = VkImageLayout.ShaderReadOnlyOptimal;

            vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion,
                                 0, null, 0, null, 1, &imageMemoryBarrier);

            Assert(vkEndCommandBuffer(cmdBuffer));

            VkSubmitInfo submitInfo = VkSubmitInfo.New();

            submitInfo.commandBufferCount = 1;
            submitInfo.pCommandBuffers    = &cmdBuffer;

            Assert(vkQueueSubmit(queue, 1, &submitInfo, VkFence.Null));
            Assert(vkQueueWaitIdle(queue));
            vkFreeCommandBuffers(device, CommandPoolManager.GetPool(cmdPoolID), 1, &cmdBuffer);

            return(texture);
        }
예제 #21
0
        internal static void CopyTextureCore_VkCommandBuffer(
            VkCommandBuffer cb,
            Texture source,
            uint srcX, uint srcY, uint srcZ,
            uint srcMipLevel,
            uint srcBaseArrayLayer,
            Texture destination,
            uint dstX, uint dstY, uint dstZ,
            uint dstMipLevel,
            uint dstBaseArrayLayer,
            uint width, uint height, uint depth,
            uint layerCount)
        {
            VkTexture srcVkTexture = Util.AssertSubtype <Texture, VkTexture>(source);
            VkTexture dstVkTexture = Util.AssertSubtype <Texture, VkTexture>(destination);

            bool sourceIsStaging = (source.Usage & TextureUsage.Staging) == TextureUsage.Staging;
            bool destIsStaging   = (destination.Usage & TextureUsage.Staging) == TextureUsage.Staging;

            if (!sourceIsStaging && !destIsStaging)
            {
                VkImageSubresourceLayers srcSubresource = new VkImageSubresourceLayers
                {
                    aspectMask     = VkImageAspectFlags.Color,
                    layerCount     = layerCount,
                    mipLevel       = srcMipLevel,
                    baseArrayLayer = srcBaseArrayLayer
                };

                VkImageSubresourceLayers dstSubresource = new VkImageSubresourceLayers
                {
                    aspectMask     = VkImageAspectFlags.Color,
                    layerCount     = layerCount,
                    mipLevel       = dstMipLevel,
                    baseArrayLayer = dstBaseArrayLayer
                };

                VkImageCopy region = new VkImageCopy
                {
                    srcOffset = new VkOffset3D {
                        x = (int)srcX, y = (int)srcY, z = (int)srcZ
                    },
                    dstOffset = new VkOffset3D {
                        x = (int)dstX, y = (int)dstY, z = (int)dstZ
                    },
                    srcSubresource = srcSubresource,
                    dstSubresource = dstSubresource,
                    extent         = new VkExtent3D {
                        width = width, height = height, depth = depth
                    }
                };

                srcVkTexture.TransitionImageLayout(
                    cb,
                    srcMipLevel,
                    1,
                    srcBaseArrayLayer,
                    layerCount,
                    VkImageLayout.TransferSrcOptimal);

                dstVkTexture.TransitionImageLayout(
                    cb,
                    dstMipLevel,
                    1,
                    dstBaseArrayLayer,
                    layerCount,
                    VkImageLayout.TransferDstOptimal);

                vkCmdCopyImage(
                    cb,
                    srcVkTexture.OptimalDeviceImage,
                    VkImageLayout.TransferSrcOptimal,
                    dstVkTexture.OptimalDeviceImage,
                    VkImageLayout.TransferDstOptimal,
                    1,
                    ref region);
            }
            else if (sourceIsStaging && !destIsStaging)
            {
                Vulkan.VkBuffer     srcBuffer = srcVkTexture.StagingBuffer;
                VkSubresourceLayout srcLayout = srcVkTexture.GetSubresourceLayout(
                    srcVkTexture.CalculateSubresource(srcMipLevel, srcBaseArrayLayer));
                VkImage dstImage = dstVkTexture.OptimalDeviceImage;
                dstVkTexture.TransitionImageLayout(
                    cb,
                    dstMipLevel,
                    1,
                    dstBaseArrayLayer,
                    layerCount,
                    VkImageLayout.TransferDstOptimal);

                VkImageSubresourceLayers dstSubresource = new VkImageSubresourceLayers
                {
                    aspectMask     = VkImageAspectFlags.Color,
                    layerCount     = layerCount,
                    mipLevel       = dstMipLevel,
                    baseArrayLayer = dstBaseArrayLayer
                };

                Util.GetMipDimensions(srcVkTexture, srcMipLevel, out uint mipWidth, out uint mipHeight, out uint mipDepth);
                uint blockSize         = FormatHelpers.IsCompressedFormat(srcVkTexture.Format) ? 4u : 1u;
                uint bufferRowLength   = Math.Max(mipWidth, blockSize);
                uint bufferImageHeight = Math.Max(mipHeight, blockSize);
                uint compressedX       = srcX / blockSize;
                uint compressedY       = srcY / blockSize;
                uint blockSizeInBytes  = blockSize == 1
                    ? FormatHelpers.GetSizeInBytes(srcVkTexture.Format)
                    : FormatHelpers.GetBlockSizeInBytes(srcVkTexture.Format);
                uint rowPitch   = FormatHelpers.GetRowPitch(bufferRowLength, srcVkTexture.Format);
                uint depthPitch = FormatHelpers.GetDepthPitch(rowPitch, bufferImageHeight, srcVkTexture.Format);

                VkBufferImageCopy regions = new VkBufferImageCopy
                {
                    bufferOffset = srcLayout.offset
                                   + (srcZ * depthPitch)
                                   + (compressedY * rowPitch)
                                   + (compressedX * blockSizeInBytes),
                    bufferRowLength   = bufferRowLength,
                    bufferImageHeight = bufferImageHeight,
                    imageExtent       = new VkExtent3D {
                        width = width, height = height, depth = depth
                    },
                    imageOffset = new VkOffset3D {
                        x = (int)dstX, y = (int)dstY, z = (int)dstZ
                    },
                    imageSubresource = dstSubresource
                };

                vkCmdCopyBufferToImage(cb, srcBuffer, dstImage, VkImageLayout.TransferDstOptimal, 1, ref regions);
            }
            else if (!sourceIsStaging && destIsStaging)
            {
                VkImage srcImage = srcVkTexture.OptimalDeviceImage;
                srcVkTexture.TransitionImageLayout(
                    cb,
                    srcMipLevel,
                    1,
                    srcBaseArrayLayer,
                    layerCount,
                    VkImageLayout.TransferSrcOptimal);

                Vulkan.VkBuffer     dstBuffer = dstVkTexture.StagingBuffer;
                VkSubresourceLayout dstLayout = dstVkTexture.GetSubresourceLayout(
                    dstVkTexture.CalculateSubresource(dstMipLevel, dstBaseArrayLayer));
                VkImageSubresourceLayers srcSubresource = new VkImageSubresourceLayers
                {
                    aspectMask     = VkImageAspectFlags.Color,
                    layerCount     = layerCount,
                    mipLevel       = srcMipLevel,
                    baseArrayLayer = srcBaseArrayLayer
                };

                Util.GetMipDimensions(dstVkTexture, dstMipLevel, out uint mipWidth, out uint mipHeight, out uint mipDepth);
                VkBufferImageCopy region = new VkBufferImageCopy
                {
                    bufferRowLength   = mipWidth,
                    bufferImageHeight = mipHeight,
                    bufferOffset      = dstLayout.offset + (dstX * FormatHelpers.GetSizeInBytes(dstVkTexture.Format)),
                    imageExtent       = new VkExtent3D {
                        width = width, height = height, depth = depth
                    },
                    imageOffset = new VkOffset3D {
                        x = (int)dstX, y = (int)dstY, z = (int)dstZ
                    },
                    imageSubresource = srcSubresource
                };

                vkCmdCopyImageToBuffer(cb, srcImage, VkImageLayout.TransferSrcOptimal, dstBuffer, 1, ref region);
            }
            else
            {
                Debug.Assert(sourceIsStaging && destIsStaging);
                Vulkan.VkBuffer     srcBuffer = srcVkTexture.StagingBuffer;
                VkSubresourceLayout srcLayout = srcVkTexture.GetSubresourceLayout(
                    srcVkTexture.CalculateSubresource(srcMipLevel, srcBaseArrayLayer));
                Vulkan.VkBuffer     dstBuffer = dstVkTexture.StagingBuffer;
                VkSubresourceLayout dstLayout = dstVkTexture.GetSubresourceLayout(
                    dstVkTexture.CalculateSubresource(dstMipLevel, dstBaseArrayLayer));

                uint zLimit = Math.Max(depth, layerCount);
                if (!FormatHelpers.IsCompressedFormat(source.Format))
                {
                    uint pixelSize = FormatHelpers.GetSizeInBytes(srcVkTexture.Format);
                    for (uint zz = 0; zz < zLimit; zz++)
                    {
                        for (uint yy = 0; yy < height; yy++)
                        {
                            VkBufferCopy region = new VkBufferCopy
                            {
                                srcOffset = srcLayout.offset
                                            + srcLayout.depthPitch * (zz + srcZ)
                                            + srcLayout.rowPitch * (yy + srcY)
                                            + pixelSize * srcX,
                                dstOffset = dstLayout.offset
                                            + dstLayout.depthPitch * (zz + dstZ)
                                            + dstLayout.rowPitch * (yy + dstY)
                                            + pixelSize * dstX,
                                size = width * pixelSize,
                            };

                            vkCmdCopyBuffer(cb, srcBuffer, dstBuffer, 1, ref region);
                        }
                    }
                }
                else // IsCompressedFormat
                {
                    uint denseRowSize     = FormatHelpers.GetRowPitch(width, source.Format);
                    uint numRows          = FormatHelpers.GetNumRows(height, source.Format);
                    uint compressedSrcX   = srcX / 4;
                    uint compressedSrcY   = srcY / 4;
                    uint compressedDstX   = dstX / 4;
                    uint compressedDstY   = dstY / 4;
                    uint blockSizeInBytes = FormatHelpers.GetBlockSizeInBytes(source.Format);

                    for (uint zz = 0; zz < zLimit; zz++)
                    {
                        for (uint row = 0; row < numRows; row++)
                        {
                            VkBufferCopy region = new VkBufferCopy
                            {
                                srcOffset = srcLayout.offset
                                            + srcLayout.depthPitch * (zz + srcZ)
                                            + srcLayout.rowPitch * (row + compressedSrcY)
                                            + blockSizeInBytes * compressedSrcX,
                                dstOffset = dstLayout.offset
                                            + dstLayout.depthPitch * (zz + dstZ)
                                            + dstLayout.rowPitch * (row + compressedDstY)
                                            + blockSizeInBytes * compressedDstX,
                                size = denseRowSize,
                            };

                            vkCmdCopyBuffer(cb, srcBuffer, dstBuffer, 1, ref region);
                        }
                    }
                }
            }
        }
예제 #22
0
        void loadTextureArray(string filename, VkFormat format)
        {
            KtxFile tex2DArray;

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

            textureArray.width  = tex2DArray.Header.PixelWidth;
            textureArray.height = tex2DArray.Header.PixelHeight;
            layerCount          = tex2DArray.Header.NumberOfArrayElements;

            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 = tex2DArray.GetTotalSize();
            // This buffer is used as a transfer source for the buffer copy
            bufferCreateInfo.usage       = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
            bufferCreateInfo.sharingMode = VK_SHARING_MODE_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, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

            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 = tex2DArray.GetAllTextureData();
            fixed(byte *texPtr = allTextureData)
            {
                Unsafe.CopyBlock(data, texPtr, (uint)allTextureData.Length);
            }

            vkUnmapMemory(device, stagingMemory);

            // Setup buffer copy regions for array layers
            NativeList <VkBufferImageCopy> bufferCopyRegions;
            IntPtr offset = IntPtr.Zero;

            for (uint layer = 0; layer < layerCount; layer++)
            {
                VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                bufferCopyRegion.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
                bufferCopyRegion.imageSubresource.mipLevel       = 0;
                bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
                bufferCopyRegion.imageSubresource.layerCount     = 1;
                bufferCopyRegion.imageExtent.width  = (uint)(tex2DArray[layer][0].extent().x);
                bufferCopyRegion.imageExtent.height = (uint)(tex2DArray[layer][0].extent().y);
                bufferCopyRegion.imageExtent.depth  = 1;
                bufferCopyRegion.bufferOffset       = offset;

                bufferCopyRegions.push_back(bufferCopyRegion);

                // Increase offset into staging buffer for next level / face
                offset += tex2DArray[layer][0].Count;
            }

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

            imageCreateInfo.imageType     = VK_IMAGE_TYPE_2D;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = 1;
            imageCreateInfo.samples       = VK_SAMPLE_COUNT_1_BIT;
            imageCreateInfo.tiling        = VK_IMAGE_TILING_OPTIMAL;
            imageCreateInfo.usage         = VK_IMAGE_USAGE_SAMPLED_BIT;
            imageCreateInfo.sharingMode   = VK_SHARING_MODE_EXCLUSIVE;
            imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
            imageCreateInfo.extent        = new  { textureArray.width, textureArray.height, 1 };
            imageCreateInfo.usage         = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
            imageCreateInfo.arrayLayers   = layerCount;

            Util.CheckResult(vkCreateImage(device, &imageCreateInfo, null, &textureArray.image));

            vkGetImageMemoryRequirements(device, textureArray.image, &memReqs);

            memAllocInfo.allocationSize  = memReqs.size;
            memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

            Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, &textureArray.deviceMemory));
            Util.CheckResult(vkBindImageMemory(device, textureArray.image, textureArray.deviceMemory, 0));

            VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);

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

            subresourceRange.aspectMask   = VK_IMAGE_ASPECT_COLOR_BIT;
            subresourceRange.baseMipLevel = 0;
            subresourceRange.levelCount   = 1;
            subresourceRange.layerCount   = layerCount;

            vkstools::setImageLayout(
                copyCmd,
                textureArray.image,
                VK_IMAGE_ASPECT_COLOR_BIT,
                VK_IMAGE_LAYOUT_UNDEFINED,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                subresourceRange);

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

            // Change texture image layout to shader read after all faces have been copied
            textureArray.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
            vkstools::setImageLayout(
                copyCmd,
                textureArray.image,
                VK_IMAGE_ASPECT_COLOR_BIT,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                textureArray.imageLayout,
                subresourceRange);

            VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);

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

            sampler.magFilter     = VK_FILTER_LINEAR;
            sampler.minFilter     = VK_FILTER_LINEAR;
            sampler.mipmapMode    = VK_SAMPLER_MIPMAP_MODE_LINEAR;
            sampler.addressModeU  = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
            sampler.addressModeV  = sampler.addressModeU;
            sampler.addressModeW  = sampler.addressModeU;
            sampler.mipLodBias    = 0.0f;
            sampler.maxAnisotropy = 8;
            sampler.compareOp     = VK_COMPARE_OP_NEVER;
            sampler.minLod        = 0.0f;
            sampler.maxLod        = 0.0f;
            sampler.borderColor   = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
            Util.CheckResult(vkCreateSampler(device, &sampler, null, &textureArray.sampler));

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

            view.viewType                    = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
            view.format                      = format;
            view.components                  = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };