Esempio n. 1
0
        /**
         * Create a buffer on the device
         *
         * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
         * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
         * @param size Size of the buffer in byes
         * @param buffer Pointer to the buffer handle acquired by the function
         * @param memory Pointer to the memory handle acquired by the function
         * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
         *
         * @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied
         */
        public VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, ulong size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = null)
        {
            // Create the buffer handle
            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo(usageFlags, size);

            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;
            Util.CheckResult(vkCreateBuffer(LogicalDevice, &bufferCreateInfo, null, buffer));

            // Create the memory backing up the buffer handle
            VkMemoryRequirements memReqs;
            VkMemoryAllocateInfo memAlloc = Initializers.memoryAllocateInfo();

            vkGetBufferMemoryRequirements(LogicalDevice, *buffer, &memReqs);
            memAlloc.allocationSize = memReqs.size;
            // Find a memory type index that fits the properties of the buffer
            memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
            Util.CheckResult(vkAllocateMemory(LogicalDevice, &memAlloc, null, memory));

            // If a pointer to the buffer data has been passed, map the buffer and copy over the data
            if (data != null)
            {
                void *mapped;
                Util.CheckResult(vkMapMemory(LogicalDevice, *memory, 0, size, 0, &mapped));
                Unsafe.CopyBlock(mapped, data, (uint)size);
                // If host coherency hasn't been requested, do a manual flush to make writes visible
                if ((memoryPropertyFlags & VkMemoryPropertyFlags.HostCoherent) == 0)
                {
                    VkMappedMemoryRange mappedRange = Initializers.mappedMemoryRange();
                    mappedRange.memory = *memory;
                    mappedRange.offset = 0;
                    mappedRange.size   = size;
                    vkFlushMappedMemoryRanges(LogicalDevice, 1, &mappedRange);
                }
                vkUnmapMemory(LogicalDevice, *memory);
            }

            // Attach the memory to the buffer object
            Util.CheckResult(vkBindBufferMemory(LogicalDevice, *buffer, *memory, 0));

            return(VkResult.Success);
        }
Esempio n. 2
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 FromTextureAsset(
            TextureAsset asset,
            GraphicsDevice device,
            VkImageUsageFlags imageUsageFlags = VkImageUsageFlags.Sampled,
            VkImageLayout imageLayout         = VkImageLayout.ShaderReadOnlyOptimal)
        {
            VkFormat format = VkFormat.Undefined;

            KtxFile tex2D = asset.GetTexture();

            format = GlFormatToVulkanFormat.vkGetFormatFromOpenGLInternalFormat(tex2D.Header.GlInternalFormat, tex2D.Header.GlFormat, tex2D.Header.GlType);

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

            this.imageLayout = imageLayout;
            this.format      = format;
            this.device      = device;

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

            vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, out formatProperties);

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

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

            imageCreateInfo.imageType     = VkImageType.Image2D;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = mipLevels;
            imageCreateInfo.arrayLayers   = 1;
            imageCreateInfo.samples       = VkSampleCountFlags.Count1;
            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 & VkImageUsageFlags.TransferDst) == 0)
            {
                imageCreateInfo.usage |= VkImageUsageFlags.TransferDst;
            }
            Util.CheckResult(vkCreateImage(device.device, &imageCreateInfo, null, out image));

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

            memAllocInfo.allocationSize = memReqs.size;

            memory = device.memoryAllocator.Allocate(memReqs.size, memReqs.alignment, memReqs.memoryTypeBits, false);
            Util.CheckResult(vkBindImageMemory(device.device, image, memory.vkDeviceMemory, memory.offset));

            //memAllocInfo.memoryTypeIndex = device.vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);
            //Util.CheckResult(vkAllocateMemory(device.device, &memAllocInfo, null, out deviceMemory));
            //Util.CheckResult(vkBindImageMemory(device.device, image, deviceMemory, 0));

            TransferDataKtx(tex2D);

            CreateSampler();

            CreateView();

            // Update descriptor image info member that can be used for setting up descriptor sets
            UpdateDescriptor();
        }
Esempio n. 3
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);
        }