Added function to create a 2D texture from a buffer
This commit is contained in:
parent
298f7a9415
commit
c9a018ca2e
1 changed files with 184 additions and 0 deletions
|
|
@ -844,6 +844,190 @@ namespace vkTools
|
||||||
texture->descriptor.sampler = texture->sampler;
|
texture->descriptor.sampler = texture->sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a 2D texture from a buffer
|
||||||
|
*
|
||||||
|
* @param buffer Buffer containing texture data to upload
|
||||||
|
* @param bufferSize Size of the buffer in machine units
|
||||||
|
* @param width Width of the texture to create
|
||||||
|
* @param hidth Height of the texture to create
|
||||||
|
* @param format Vulkan format of the image data stored in the file
|
||||||
|
* @param texture Pointer to the texture object to load the image into
|
||||||
|
* @param (Optional) filter Texture filtering for the sampler (defaults to VK_FILTER_LINEAR)
|
||||||
|
* @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||||
|
*/
|
||||||
|
void createTexture(void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t width, uint32_t height, VulkanTexture *texture, VkFilter filter = VK_FILTER_LINEAR, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||||
|
{
|
||||||
|
assert(buffer);
|
||||||
|
|
||||||
|
texture->width = width;
|
||||||
|
texture->height = height;
|
||||||
|
texture->mipLevels = 1;
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo();
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
|
||||||
|
// Use a separate command buffer for texture loading
|
||||||
|
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
|
||||||
|
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
|
||||||
|
|
||||||
|
// Create a host-visible staging buffer that contains the raw image data
|
||||||
|
VkBuffer stagingBuffer;
|
||||||
|
VkDeviceMemory stagingMemory;
|
||||||
|
|
||||||
|
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo();
|
||||||
|
bufferCreateInfo.size = bufferSize;
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkCreateBuffer(vulkanDevice->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||||
|
|
||||||
|
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
||||||
|
vkGetBufferMemoryRequirements(vulkanDevice->logicalDevice, 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);
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||||
|
VK_CHECK_RESULT(vkBindBufferMemory(vulkanDevice->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||||
|
|
||||||
|
// Copy texture data into staging buffer
|
||||||
|
uint8_t *data;
|
||||||
|
VK_CHECK_RESULT(vkMapMemory(vulkanDevice->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||||
|
memcpy(data, buffer, bufferSize);
|
||||||
|
vkUnmapMemory(vulkanDevice->logicalDevice, stagingMemory);
|
||||||
|
|
||||||
|
VkBufferImageCopy bufferCopyRegion = {};
|
||||||
|
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
bufferCopyRegion.imageSubresource.mipLevel = 0;
|
||||||
|
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
|
||||||
|
bufferCopyRegion.imageSubresource.layerCount = 1;
|
||||||
|
bufferCopyRegion.imageExtent.width = width;
|
||||||
|
bufferCopyRegion.imageExtent.height = height;
|
||||||
|
bufferCopyRegion.imageExtent.depth = 1;
|
||||||
|
bufferCopyRegion.bufferOffset = 0;
|
||||||
|
|
||||||
|
// Create optimal tiled target image
|
||||||
|
VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo();
|
||||||
|
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
imageCreateInfo.format = format;
|
||||||
|
imageCreateInfo.mipLevels = texture->mipLevels;
|
||||||
|
imageCreateInfo.arrayLayers = 1;
|
||||||
|
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
imageCreateInfo.extent = { texture->width, texture->height, 1 };
|
||||||
|
imageCreateInfo.usage = imageUsageFlags;
|
||||||
|
// Ensure that the TRANSFER_DST bit is set for staging
|
||||||
|
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
||||||
|
{
|
||||||
|
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
}
|
||||||
|
VK_CHECK_RESULT(vkCreateImage(vulkanDevice->logicalDevice, &imageCreateInfo, nullptr, &texture->image));
|
||||||
|
|
||||||
|
vkGetImageMemoryRequirements(vulkanDevice->logicalDevice, texture->image, &memReqs);
|
||||||
|
|
||||||
|
memAllocInfo.allocationSize = memReqs.size;
|
||||||
|
|
||||||
|
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->logicalDevice, &memAllocInfo, nullptr, &texture->deviceMemory));
|
||||||
|
VK_CHECK_RESULT(vkBindImageMemory(vulkanDevice->logicalDevice, texture->image, texture->deviceMemory, 0));
|
||||||
|
|
||||||
|
VkImageSubresourceRange subresourceRange = {};
|
||||||
|
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
subresourceRange.baseMipLevel = 0;
|
||||||
|
subresourceRange.levelCount = texture->mipLevels;
|
||||||
|
subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
// Image barrier for optimal image (target)
|
||||||
|
// Optimal image will be used as destination for the copy
|
||||||
|
setImageLayout(
|
||||||
|
cmdBuffer,
|
||||||
|
texture->image,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Copy mip levels from staging buffer
|
||||||
|
vkCmdCopyBufferToImage(
|
||||||
|
cmdBuffer,
|
||||||
|
stagingBuffer,
|
||||||
|
texture->image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1,
|
||||||
|
&bufferCopyRegion
|
||||||
|
);
|
||||||
|
|
||||||
|
// Change texture image layout to shader read after all mip levels have been copied
|
||||||
|
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
setImageLayout(
|
||||||
|
cmdBuffer,
|
||||||
|
texture->image,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
texture->imageLayout,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Submit command buffer containing copy and image layout commands
|
||||||
|
VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuffer));
|
||||||
|
|
||||||
|
// Create a fence to make sure that the copies have finished before continuing
|
||||||
|
VkFence copyFence;
|
||||||
|
VkFenceCreateInfo fenceCreateInfo = vkTools::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
||||||
|
VK_CHECK_RESULT(vkCreateFence(vulkanDevice->logicalDevice, &fenceCreateInfo, nullptr, ©Fence));
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo = vkTools::initializers::submitInfo();
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &cmdBuffer;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, copyFence));
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkWaitForFences(vulkanDevice->logicalDevice, 1, ©Fence, VK_TRUE, DEFAULT_FENCE_TIMEOUT));
|
||||||
|
|
||||||
|
vkDestroyFence(vulkanDevice->logicalDevice, copyFence, nullptr);
|
||||||
|
|
||||||
|
// Clean up staging resources
|
||||||
|
vkFreeMemory(vulkanDevice->logicalDevice, stagingMemory, nullptr);
|
||||||
|
vkDestroyBuffer(vulkanDevice->logicalDevice, stagingBuffer, nullptr);
|
||||||
|
|
||||||
|
// Create sampler
|
||||||
|
VkSamplerCreateInfo sampler = {};
|
||||||
|
sampler.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
sampler.magFilter = filter;
|
||||||
|
sampler.minFilter = filter;
|
||||||
|
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
sampler.mipLodBias = 0.0f;
|
||||||
|
sampler.compareOp = VK_COMPARE_OP_NEVER;
|
||||||
|
sampler.minLod = 0.0f;
|
||||||
|
sampler.maxLod = 0.0f;
|
||||||
|
VK_CHECK_RESULT(vkCreateSampler(vulkanDevice->logicalDevice, &sampler, nullptr, &texture->sampler));
|
||||||
|
|
||||||
|
// Create image view
|
||||||
|
VkImageViewCreateInfo view = {};
|
||||||
|
view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
view.pNext = NULL;
|
||||||
|
view.image = VK_NULL_HANDLE;
|
||||||
|
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
view.format = format;
|
||||||
|
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
||||||
|
view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
view.subresourceRange.levelCount = 1;
|
||||||
|
view.image = texture->image;
|
||||||
|
VK_CHECK_RESULT(vkCreateImageView(vulkanDevice->logicalDevice, &view, nullptr, &texture->view));
|
||||||
|
|
||||||
|
// Fill descriptor image info that can be used for setting up descriptor sets
|
||||||
|
texture->descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
texture->descriptor.imageView = texture->view;
|
||||||
|
texture->descriptor.sampler = texture->sampler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free all Vulkan resources used by a texture object
|
* Free all Vulkan resources used by a texture object
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue