From 881fae0f6ff989a2df88580cacefd747e372b9da Mon Sep 17 00:00:00 2001 From: saschawillems Date: Wed, 2 Mar 2016 21:16:40 +0100 Subject: [PATCH] Added texture array loading function to texture loader --- base/vulkanTextureLoader.hpp | 214 +++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/base/vulkanTextureLoader.hpp b/base/vulkanTextureLoader.hpp index 14480fa1..c1f674db 100644 --- a/base/vulkanTextureLoader.hpp +++ b/base/vulkanTextureLoader.hpp @@ -25,6 +25,7 @@ namespace vkTools VkImageView view; uint32_t width, height; uint32_t mipLevels; + uint32_t layerCount; }; class VulkanTextureLoader @@ -551,6 +552,219 @@ namespace vkTools } } + // Load an array texture (single file) + void loadTextureArray(const char* filename, VkFormat format, VulkanTexture *texture) + { + VkFormatProperties formatProperties; + VkResult err; + + gli::texture2DArray tex2DArray(gli::load(filename)); + assert(!tex2DArray.empty()); + + texture->width = tex2DArray.dimensions().x; + texture->height = tex2DArray.dimensions().y; + texture->layerCount = tex2DArray.layers(); + + // Get device properites for the requested texture format + vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); + + VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = format; + imageCreateInfo.extent = { texture->width, texture->height, 1 }; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.flags = 0; + + VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); + VkMemoryRequirements memReqs; + + struct Layer { + VkImage image; + VkDeviceMemory memory; + }; + std::vector arrayLayer; + arrayLayer.resize(texture->layerCount); + + // Allocate command buffer for image copies and layouts + VkCommandBuffer cmdBuffer; + VkCommandBufferAllocateInfo cmdBufAlllocatInfo = + vkTools::initializers::commandBufferAllocateInfo( + cmdPool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, + 1); + err = vkAllocateCommandBuffers(device, &cmdBufAlllocatInfo, &cmdBuffer); + assert(!err); + + VkCommandBufferBeginInfo cmdBufInfo = + vkTools::initializers::commandBufferBeginInfo(); + + err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo); + assert(!err); + + // Load separate cube map faces into linear tiled textures + for (uint32_t i = 0; i < texture->layerCount; ++i) + { + err = vkCreateImage(device, &imageCreateInfo, nullptr, &arrayLayer[i].image); + assert(!err); + + vkGetImageMemoryRequirements(device, arrayLayer[i].image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); + err = vkAllocateMemory(device, &memAllocInfo, nullptr, &arrayLayer[i].memory); + assert(!err); + err = vkBindImageMemory(device, arrayLayer[i].image, arrayLayer[i].memory, 0); + assert(!err); + + VkImageSubresource subRes = {}; + subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkSubresourceLayout subResLayout; + void *data; + + vkGetImageSubresourceLayout(device, arrayLayer[i].image, &subRes, &subResLayout); + assert(!err); + err = vkMapMemory(device, arrayLayer[i].memory, 0, memReqs.size, 0, &data); + assert(!err); + memcpy(data, tex2DArray[i].data(), tex2DArray[i].size()); + vkUnmapMemory(device, arrayLayer[i].memory); + + // Image barrier for linear image (base) + // Linear image will be used as a source for the copy + vkTools::setImageLayout( + cmdBuffer, + arrayLayer[i].image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + } + + // Transfer cube map faces to optimal tiling + + // Setup texture as blit target with optimal tiling + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageCreateInfo.arrayLayers = texture->layerCount; + + err = vkCreateImage(device, &imageCreateInfo, nullptr, &texture->image); + assert(!err); + + vkGetImageMemoryRequirements(device, texture->image, &memReqs); + + memAllocInfo.allocationSize = memReqs.size; + + getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); + err = vkAllocateMemory(device, &memAllocInfo, nullptr, &texture->deviceMemory); + assert(!err); + err = vkBindImageMemory(device, texture->image, texture->deviceMemory, 0); + assert(!err); + + // Image barrier for optimal image (target) + // Optimal image will be used as destination for the copy + vkTools::setImageLayout( + cmdBuffer, + texture->image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + // Copy cube map faces one by one + for (uint32_t i = 0; i < texture->layerCount; ++i) + { + // Copy region for image blit + VkImageCopy copyRegion = {}; + + copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.srcSubresource.baseArrayLayer = 0; + copyRegion.srcSubresource.mipLevel = 0; + copyRegion.srcSubresource.layerCount = 1; + copyRegion.srcOffset = { 0, 0, 0 }; + + copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.dstSubresource.baseArrayLayer = i; + copyRegion.dstSubresource.mipLevel = 0; + copyRegion.dstSubresource.layerCount = 1; + copyRegion.dstOffset = { 0, 0, 0 }; + + copyRegion.extent.width = texture->width; + copyRegion.extent.height = texture->height; + copyRegion.extent.depth = 1; + + // Put image copy into command buffer + vkCmdCopyImage( + cmdBuffer, + arrayLayer[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©Region); + + // Change texture image layout to shader read after the copy + texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkTools::setImageLayout( + cmdBuffer, + texture->image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + texture->imageLayout); + } + + err = vkEndCommandBuffer(cmdBuffer); + assert(!err); + + VkFence nullFence = { VK_NULL_HANDLE }; + + // Submit command buffer to graphis queue + VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffer; + + err = vkQueueSubmit(queue, 1, &submitInfo, nullFence); + assert(!err); + + err = vkQueueWaitIdle(queue); + assert(!err); + + // Create sampler + VkSamplerCreateInfo sampler = vkTools::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; + err = vkCreateSampler(device, &sampler, nullptr, &texture->sampler); + assert(!err); + + // Create image view + VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); + view.image = VK_NULL_HANDLE; + 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 }; + view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + view.subresourceRange.layerCount = texture->layerCount; + view.image = texture->image; + err = vkCreateImageView(device, &view, nullptr, &texture->view); + assert(!err); + + // Cleanup + for (auto& layer : arrayLayer) + { + vkDestroyImage(device, layer.image, nullptr); + vkFreeMemory(device, layer.memory, nullptr); + } + } + + };