src/core/Texture.cpp
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, VulkanDevice *device, VkQueue copyQueue,
                                  VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout) {
    ktxTexture *ktxTexture;
    ktxResult result = loadKTXFile(filename, &ktxTexture);
    assert(result == KTX_SUCCESS);

    this->device = device;
    width = ktxTexture->baseWidth;
    height = ktxTexture->baseHeight;
    layerCount = ktxTexture->numLayers;
    mipLevels = ktxTexture->numLevels;

    ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
    ktx_size_t ktxTextureSize = ktxTexture_GetDataSize(ktxTexture);

    VkMemoryAllocateInfo memAllocInfo = Populate::memoryAllocateInfo();
    VkMemoryRequirements memReqs;

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

    VkBufferCreateInfo bufferCreateInfo = Populate::bufferCreateInfo();
    bufferCreateInfo.size = ktxTextureSize;
    // 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;


    (vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &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, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
                                                                                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);


    CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));

    CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));

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

    CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **) &data));
    memcpy(data, ktxTextureData, ktxTextureSize);
    vkUnmapMemory(device->logicalDevice, stagingMemory);

    // Setup buffer copy regions for each layer including all of its miplevels
    std::vector<VkBufferImageCopy> bufferCopyRegions;

    for (uint32_t layer = 0; layer < layerCount; layer++) {
        for (uint32_t level = 0; level < mipLevels; level++) {
            ktx_size_t offset;
            KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, level, layer, 0, &offset);
            assert(result == KTX_SUCCESS);

            VkBufferImageCopy bufferCopyRegion = {};
            bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            bufferCopyRegion.imageSubresource.mipLevel = level;
            bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
            bufferCopyRegion.imageSubresource.layerCount = 1;
            bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> level;
            bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> level;
            bufferCopyRegion.imageExtent.depth = 1;
            bufferCopyRegion.bufferOffset = offset;

            bufferCopyRegions.push_back(bufferCopyRegion);
        }
    }

    // Create optimal tiled target image
    VkImageCreateInfo imageCreateInfo = Populate::imageCreateInfo();
    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
    imageCreateInfo.format = format;
    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 = {width, 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;
    }
    imageCreateInfo.arrayLayers = layerCount;
    imageCreateInfo.mipLevels = mipLevels;


    CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));

    vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);

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


    CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));

    CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));

    // Use a separate command buffer for texture loading
    VkCommandBuffer copyCmd = device->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 = mipLevels;
    subresourceRange.layerCount = layerCount;

    Utils::setImageLayout(
            copyCmd,
            image,
            VK_IMAGE_LAYOUT_UNDEFINED,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            subresourceRange,
            VK_PIPELINE_STAGE_HOST_BIT,
            VK_PIPELINE_STAGE_TRANSFER_BIT);

    // Copy the layers and mip levels from the staging buffer to the optimal tiled image
    vkCmdCopyBufferToImage(
            copyCmd,
            stagingBuffer,
            image,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            static_cast<uint32_t>(bufferCopyRegions.size()),
            bufferCopyRegions.data());

    // Change texture image layout to shader read after all faces have been copied
    this->imageLayout = imageLayout;
    Utils::setImageLayout(
            copyCmd,
            image,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            imageLayout,
            subresourceRange,
            VK_PIPELINE_STAGE_TRANSFER_BIT,
            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);

    device->flushCommandBuffer(copyCmd, copyQueue);

    // Create sampler
    VkSamplerCreateInfo samplerCreateInfo = Populate::samplerCreateInfo();
    samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
    samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
    samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
    samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
    samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
    samplerCreateInfo.mipLodBias = 0.0f;
    samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy
                                      ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
    samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
    samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
    samplerCreateInfo.minLod = 0.0f;
    samplerCreateInfo.maxLod = (float) mipLevels;
    samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;

    CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));

    // Create image view
    VkImageViewCreateInfo viewCreateInfo = Populate::imageViewCreateInfo();
    viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
    viewCreateInfo.format = format;
    viewCreateInfo.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
                                 VK_COMPONENT_SWIZZLE_A};
    viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
    viewCreateInfo.subresourceRange.layerCount = layerCount;
    viewCreateInfo.subresourceRange.levelCount = mipLevels;
    viewCreateInfo.image = image;

    (vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));

    // Clean up staging resources
    ktxTexture_Destroy(ktxTexture);
    vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
    vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);

    // Update descriptor image info member that can be used for setting up descriptor sets
    updateDescriptor();
}
/**
* Load a 2D texture array including all mip levels
*
* @param filename File to load (supports .ktx)
* @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)
*
*/
Load a 2D texture array including all mip levels
Load a 2D texture array including all mip levels
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, VulkanDevice *device, VkQueue copyQueue,
                                  VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout) {
    ktxTexture *ktxTexture;
    ktxResult result = loadKTXFile(filename, &ktxTexture);
    assert(result == KTX_SUCCESS);
    this->device = device;
    width = ktxTexture->baseWidth;
    height = ktxTexture->baseHeight;
    layerCount = ktxTexture->numLayers;
    mipLevels = ktxTexture->numLevels;
    ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
    ktx_size_t ktxTextureSize = ktxTexture_GetDataSize(ktxTexture);
    VkMemoryAllocateInfo memAllocInfo = Populate::memoryAllocateInfo();
    VkMemoryRequirements memReqs;
    VkBuffer stagingBuffer;
    VkDeviceMemory stagingMemory;
    VkBufferCreateInfo bufferCreateInfo = Populate::bufferCreateInfo();
    bufferCreateInfo.size = ktxTextureSize;
    bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
    bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    (vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
    vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
    memAllocInfo.allocationSize = memReqs.size;
    memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
                                                                                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
    CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
    CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
    uint8_t *data;
    CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **) &data));
    memcpy(data, ktxTextureData, ktxTextureSize);
    vkUnmapMemory(device->logicalDevice, stagingMemory);
    std::vector<VkBufferImageCopy> bufferCopyRegions;
    for (uint32_t layer = 0; layer < layerCount; layer++) {
        for (uint32_t level = 0; level < mipLevels; level++) {
            ktx_size_t offset;
            KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, level, layer, 0, &offset);
            assert(result == KTX_SUCCESS);
            VkBufferImageCopy bufferCopyRegion = {};
            bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            bufferCopyRegion.imageSubresource.mipLevel = level;
            bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
            bufferCopyRegion.imageSubresource.layerCount = 1;
            bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> level;
            bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> level;
            bufferCopyRegion.imageExtent.depth = 1;
            bufferCopyRegion.bufferOffset = offset;
            bufferCopyRegions.push_back(bufferCopyRegion);
        }
    }
    VkImageCreateInfo imageCreateInfo = Populate::imageCreateInfo();
    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
    imageCreateInfo.format = format;
    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 = {width, height, 1};
    imageCreateInfo.usage = imageUsageFlags;
    if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
        imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    }
    imageCreateInfo.arrayLayers = layerCount;
    imageCreateInfo.mipLevels = mipLevels;
    CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
    vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
    memAllocInfo.allocationSize = memReqs.size;
    memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
    CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
    CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
    VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
    VkImageSubresourceRange subresourceRange = {};
    subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    subresourceRange.baseMipLevel = 0;
    subresourceRange.levelCount = mipLevels;
    subresourceRange.layerCount = layerCount;
    Utils::setImageLayout(
            copyCmd,
            image,
            VK_IMAGE_LAYOUT_UNDEFINED,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            subresourceRange,
            VK_PIPELINE_STAGE_HOST_BIT,
            VK_PIPELINE_STAGE_TRANSFER_BIT);
    vkCmdCopyBufferToImage(
            copyCmd,
            stagingBuffer,
            image,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            static_cast<uint32_t>(bufferCopyRegions.size()),
            bufferCopyRegions.data());
    this->imageLayout = imageLayout;
    Utils::setImageLayout(
            copyCmd,
            image,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            imageLayout,
            subresourceRange,
            VK_PIPELINE_STAGE_TRANSFER_BIT,
            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
    device->flushCommandBuffer(copyCmd, copyQueue);
    VkSamplerCreateInfo samplerCreateInfo = Populate::samplerCreateInfo();
    samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
    samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
    samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
    samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
    samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
    samplerCreateInfo.mipLodBias = 0.0f;
    samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy
                                      ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
    samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
    samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
    samplerCreateInfo.minLod = 0.0f;
    samplerCreateInfo.maxLod = (float) mipLevels;
    samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
    CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
    VkImageViewCreateInfo viewCreateInfo = Populate::imageViewCreateInfo();
    viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
    viewCreateInfo.format = format;
    viewCreateInfo.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
                                 VK_COMPONENT_SWIZZLE_A};
    viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
    viewCreateInfo.subresourceRange.layerCount = layerCount;
    viewCreateInfo.subresourceRange.levelCount = mipLevels;
    viewCreateInfo.image = image;
    (vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
    ktxTexture_Destroy(ktxTexture);
    vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
    vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
    updateDescriptor();
}
void Texture2DArray :: loadFromFile ( std :: string filename , VkFormat format , VulkanDevice * device , VkQueue copyQueue , VkImageUsageFlags imageUsageFlags , VkImageLayout imageLayout ) { ktxTexture * ktxTexture ; ktxResult result = loadKTXFile ( filename , & ktxTexture ) ; assert ( result == KTX_SUCCESS ) ; this -> device = device ; width = ktxTexture -> baseWidth ; height = ktxTexture -> baseHeight ; layerCount = ktxTexture -> numLayers ; mipLevels = ktxTexture -> numLevels ; ktx_uint8_t * ktxTextureData = ktxTexture_GetData ( ktxTexture ) ; ktx_size_t ktxTextureSize = ktxTexture_GetDataSize ( ktxTexture ) ; VkMemoryAllocateInfo memAllocInfo = Populate :: memoryAllocateInfo ( ) ; VkMemoryRequirements memReqs ; VkBuffer stagingBuffer ; VkDeviceMemory stagingMemory ; VkBufferCreateInfo bufferCreateInfo = Populate :: bufferCreateInfo ( ) ; bufferCreateInfo . size = ktxTextureSize ; bufferCreateInfo . usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT ; bufferCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ; ( vkCreateBuffer ( device -> logicalDevice , & bufferCreateInfo , nullptr , & stagingBuffer ) ) ; vkGetBufferMemoryRequirements ( device -> logicalDevice , stagingBuffer , & memReqs ) ; memAllocInfo . allocationSize = memReqs . size ; memAllocInfo . memoryTypeIndex = device -> getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) ; CHECK_RESULT ( vkAllocateMemory ( device -> logicalDevice , & memAllocInfo , nullptr , & stagingMemory ) ) ; CHECK_RESULT ( vkBindBufferMemory ( device -> logicalDevice , stagingBuffer , stagingMemory , 0 ) ) ; uint8_t * data ; CHECK_RESULT ( vkMapMemory ( device -> logicalDevice , stagingMemory , 0 , memReqs . size , 0 , ( void * * ) & data ) ) ; memcpy ( data , ktxTextureData , ktxTextureSize ) ; vkUnmapMemory ( device -> logicalDevice , stagingMemory ) ; std :: vector < VkBufferImageCopy > bufferCopyRegions ; for ( uint32_t layer = 0 ; layer < layerCount ; layer ++ ) { for ( uint32_t level = 0 ; level < mipLevels ; level ++ ) { ktx_size_t offset ; KTX_error_code result = ktxTexture_GetImageOffset ( ktxTexture , level , layer , 0 , & offset ) ; assert ( result == KTX_SUCCESS ) ; VkBufferImageCopy bufferCopyRegion = { } ; bufferCopyRegion . imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ; bufferCopyRegion . imageSubresource . mipLevel = level ; bufferCopyRegion . imageSubresource . baseArrayLayer = layer ; bufferCopyRegion . imageSubresource . layerCount = 1 ; bufferCopyRegion . imageExtent . width = ktxTexture -> baseWidth >> level ; bufferCopyRegion . imageExtent . height = ktxTexture -> baseHeight >> level ; bufferCopyRegion . imageExtent . depth = 1 ; bufferCopyRegion . bufferOffset = offset ; bufferCopyRegions . push_back ( bufferCopyRegion ) ; } } VkImageCreateInfo imageCreateInfo = Populate :: imageCreateInfo ( ) ; imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ; imageCreateInfo . format = format ; 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 = { width , height , 1 } ; imageCreateInfo . usage = imageUsageFlags ; if ( ! ( imageCreateInfo . usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT ) ) { imageCreateInfo . usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT ; } imageCreateInfo . arrayLayers = layerCount ; imageCreateInfo . mipLevels = mipLevels ; CHECK_RESULT ( vkCreateImage ( device -> logicalDevice , & imageCreateInfo , nullptr , & image ) ) ; vkGetImageMemoryRequirements ( device -> logicalDevice , image , & memReqs ) ; memAllocInfo . allocationSize = memReqs . size ; memAllocInfo . memoryTypeIndex = device -> getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ; CHECK_RESULT ( vkAllocateMemory ( device -> logicalDevice , & memAllocInfo , nullptr , & deviceMemory ) ) ; CHECK_RESULT ( vkBindImageMemory ( device -> logicalDevice , image , deviceMemory , 0 ) ) ; VkCommandBuffer copyCmd = device -> createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ; VkImageSubresourceRange subresourceRange = { } ; subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ; subresourceRange . baseMipLevel = 0 ; subresourceRange . levelCount = mipLevels ; subresourceRange . layerCount = layerCount ; Utils :: setImageLayout ( copyCmd , image , VK_IMAGE_LAYOUT_UNDEFINED , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , subresourceRange , VK_PIPELINE_STAGE_HOST_BIT , VK_PIPELINE_STAGE_TRANSFER_BIT ) ; vkCmdCopyBufferToImage ( copyCmd , stagingBuffer , image , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , static_cast < uint32_t > ( bufferCopyRegions . size ( ) ) , bufferCopyRegions . data ( ) ) ; this -> imageLayout = imageLayout ; Utils :: setImageLayout ( copyCmd , image , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , imageLayout , subresourceRange , VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ) ; device -> flushCommandBuffer ( copyCmd , copyQueue ) ; VkSamplerCreateInfo samplerCreateInfo = Populate :: samplerCreateInfo ( ) ; samplerCreateInfo . magFilter = VK_FILTER_LINEAR ; samplerCreateInfo . minFilter = VK_FILTER_LINEAR ; samplerCreateInfo . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ; samplerCreateInfo . addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ; samplerCreateInfo . addressModeV = samplerCreateInfo . addressModeU ; samplerCreateInfo . addressModeW = samplerCreateInfo . addressModeU ; samplerCreateInfo . mipLodBias = 0.0f ; samplerCreateInfo . maxAnisotropy = device -> enabledFeatures . samplerAnisotropy ? device -> properties . limits . maxSamplerAnisotropy : 1.0f ; samplerCreateInfo . anisotropyEnable = device -> enabledFeatures . samplerAnisotropy ; samplerCreateInfo . compareOp = VK_COMPARE_OP_NEVER ; samplerCreateInfo . minLod = 0.0f ; samplerCreateInfo . maxLod = ( float ) mipLevels ; samplerCreateInfo . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ; CHECK_RESULT ( vkCreateSampler ( device -> logicalDevice , & samplerCreateInfo , nullptr , & sampler ) ) ; VkImageViewCreateInfo viewCreateInfo = Populate :: imageViewCreateInfo ( ) ; viewCreateInfo . viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY ; viewCreateInfo . format = format ; viewCreateInfo . components = { VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_B , VK_COMPONENT_SWIZZLE_A } ; viewCreateInfo . subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ; viewCreateInfo . subresourceRange . layerCount = layerCount ; viewCreateInfo . subresourceRange . levelCount = mipLevels ; viewCreateInfo . image = image ; ( vkCreateImageView ( device -> logicalDevice , & viewCreateInfo , nullptr , & view ) ) ; ktxTexture_Destroy ( ktxTexture ) ; vkFreeMemory ( device -> logicalDevice , stagingMemory , nullptr ) ; vkDestroyBuffer ( device -> logicalDevice , stagingBuffer , nullptr ) ; updateDescriptor ( ) ; }
Load a 2D texture array including all mip levels
Load a 2D texture array including all mip levels
// Create a host-visible staging buffer that contains the raw image data // This buffer is used as a transfer source for the buffer copy // Get memory requirements for the staging buffer (alignment, memory type bits) // Get memory type index for a host visible buffer // Copy texture data into staging buffer // Setup buffer copy regions for each layer including all of its miplevels // Create optimal tiled target image // Ensure that the TRANSFER_DST bit is set for staging // Use a separate command buffer for texture loading // Image barrier for optimal image (target) // Set initial layout for all array layers (faces) of the optimal (target) tiled texture // Copy the layers and mip levels from the staging buffer to the optimal tiled image // Change texture image layout to shader read after all faces have been copied // Create sampler // Create image view // Clean up staging resources // Update descriptor image info member that can be used for setting up descriptor sets