src/core/Texture.cpp
TextureVideo::TextureVideo(uint32_t texWidth, uint32_t texHeight, VulkanDevice *device, VkImageLayout layout,
                           VkFormat format) : Texture() {

    this->device = device;
    width = texWidth;
    height = texHeight;
    mipLevels = 1;




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

    CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
    VkMemoryAllocateInfo memAlloc = Populate::memoryAllocateInfo();
    VkMemoryRequirements memReqs;
    vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);

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

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

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

    VkImageViewCreateInfo viewCreateInfo = {};
    VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo{};

    // Create sampler dependt on image format
    switch (format) {
        case VK_FORMAT_R16_UNORM:
        case VK_FORMAT_R8_UNORM:
        case VK_FORMAT_R16_UINT:
            // Create grayscale texture image
            createDefaultSampler();
            viewCreateInfo.pNext = nullptr;
            break;
        case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
            samplerYcbcrConversionInfo = createYUV420Sampler();
            viewCreateInfo.pNext = &samplerYcbcrConversionInfo;

            // Create YUV sampler
            break;
        default:
            std::cerr << "No texture sampler for that format yet\n";
            break;
    }


    // Create image view
    viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    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.levelCount = 1;
    viewCreateInfo.image = image;

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

    // Use a separate command buffer for texture loading
    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 = 1;
    // Image barrier for optimal image (target)
    // Optimal image will be used as destination for the copy
    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);

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

    device->flushCommandBuffer(copyCmd, device->transferQueue);

    // Update descriptor image info member that can be used for setting up descriptor sets
    updateDescriptor();


}
/**
 * @details before render loop:
1. Create your VkImage with UNDEFINED

1st to Nth frame (aka render loop):
Transition image to GENERAL
Synchronize (likely with VkFence)
Map the image, write it, unmap it (well, the mapping and unmaping can perhaps be outside render loop)
Synchronize (potentially done implicitly)
Transition image to whatever layout you need next
Do your rendering and whatnot
start over at 1.
*/
@details before render loop:
1. Create your VkImage with UNDEFINED

1st to Nth frame (aka render loop):
Transition image to GENERAL
Synchronize (likely with VkFence)
Map the image, write it, unmap it (well, the mapping and unmaping can perhaps be outside render loop)
Synchronize (potentially done implicitly)
Transition image to whatever layout you need next
Do your rendering and whatnot
start over at 1.
@details before render loop : 1 . Create your VkImage with UNDEFINED 1st to Nth frame ( aka render loop ) : Transition image to GENERAL Synchronize ( likely with VkFence ) Map the image write it unmap it ( well the mapping and unmaping can perhaps be outside render loop ) Synchronize ( potentially done implicitly ) Transition image to whatever layout you need next Do your rendering and whatnot start over at 1 .
TextureVideo::TextureVideo(uint32_t texWidth, uint32_t texHeight, VulkanDevice *device, VkImageLayout layout,
                           VkFormat format) : Texture() {
    this->device = device;
    width = texWidth;
    height = texHeight;
    mipLevels = 1;
    VkImageCreateInfo imageCreateInfo = Populate::imageCreateInfo();
    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
    imageCreateInfo.format = format;
    imageCreateInfo.mipLevels = 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 = {width, height, 1};
    imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
    if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
        imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    }
    CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
    VkMemoryAllocateInfo memAlloc = Populate::memoryAllocateInfo();
    VkMemoryRequirements memReqs;
    vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
    memAlloc.allocationSize = memReqs.size;
    memAlloc.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
    CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAlloc, nullptr, &deviceMemory));
    CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
    VkImageViewCreateInfo viewCreateInfo = {};
    VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo{};
    switch (format) {
        case VK_FORMAT_R16_UNORM:
        case VK_FORMAT_R8_UNORM:
        case VK_FORMAT_R16_UINT:
            createDefaultSampler();
            viewCreateInfo.pNext = nullptr;
            break;
        case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
            samplerYcbcrConversionInfo = createYUV420Sampler();
            viewCreateInfo.pNext = &samplerYcbcrConversionInfo;
            break;
        default:
            std::cerr << "No texture sampler for that format yet\n";
            break;
    }
    viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    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.levelCount = 1;
    viewCreateInfo.image = image;
    CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
    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 = 1;
    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);
    Utils::setImageLayout(
            copyCmd,
            image,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            layout,
            subresourceRange,
            VK_PIPELINE_STAGE_TRANSFER_BIT,
            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
    this->imageLayout = layout;
    device->flushCommandBuffer(copyCmd, device->transferQueue);
    updateDescriptor();
}
TextureVideo :: TextureVideo ( uint32_t texWidth , uint32_t texHeight , VulkanDevice * device , VkImageLayout layout , VkFormat format ) : Texture ( ) { this -> device = device ; width = texWidth ; height = texHeight ; mipLevels = 1 ; VkImageCreateInfo imageCreateInfo = Populate :: imageCreateInfo ( ) ; imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ; imageCreateInfo . format = format ; imageCreateInfo . mipLevels = 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 = { width , height , 1 } ; imageCreateInfo . usage = VK_IMAGE_USAGE_SAMPLED_BIT ; if ( ! ( imageCreateInfo . usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT ) ) { imageCreateInfo . usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT ; } CHECK_RESULT ( vkCreateImage ( device -> logicalDevice , & imageCreateInfo , nullptr , & image ) ) ; VkMemoryAllocateInfo memAlloc = Populate :: memoryAllocateInfo ( ) ; VkMemoryRequirements memReqs ; vkGetImageMemoryRequirements ( device -> logicalDevice , image , & memReqs ) ; memAlloc . allocationSize = memReqs . size ; memAlloc . memoryTypeIndex = device -> getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ; CHECK_RESULT ( vkAllocateMemory ( device -> logicalDevice , & memAlloc , nullptr , & deviceMemory ) ) ; CHECK_RESULT ( vkBindImageMemory ( device -> logicalDevice , image , deviceMemory , 0 ) ) ; VkImageViewCreateInfo viewCreateInfo = { } ; VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo { } ; switch ( format ) { case VK_FORMAT_R16_UNORM : case VK_FORMAT_R8_UNORM : case VK_FORMAT_R16_UINT : createDefaultSampler ( ) ; viewCreateInfo . pNext = nullptr ; break ; case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM : samplerYcbcrConversionInfo = createYUV420Sampler ( ) ; viewCreateInfo . pNext = & samplerYcbcrConversionInfo ; break ; default : std :: cerr << " \n " ; break ; } viewCreateInfo . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ; viewCreateInfo . viewType = VK_IMAGE_VIEW_TYPE_2D ; 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 . levelCount = 1 ; viewCreateInfo . image = image ; CHECK_RESULT ( vkCreateImageView ( device -> logicalDevice , & viewCreateInfo , nullptr , & view ) ) ; 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 = 1 ; 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 ) ; Utils :: setImageLayout ( copyCmd , image , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , layout , subresourceRange , VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ) ; this -> imageLayout = layout ; device -> flushCommandBuffer ( copyCmd , device -> transferQueue ) ; updateDescriptor ( ) ; }
@details before render loop:
1.
@details before render loop : 1 .
// Create optimal tiled target image // Ensure that the TRANSFER_DST bit is set for staging // Create sampler dependt on image format // Create grayscale texture image // Create YUV sampler // Create image view // Use a separate command buffer for texture loading // Image barrier for optimal image (target) // Optimal image will be used as destination for the copy // Change texture image layout to shader read after all mip levels have been copied // Update descriptor image info member that can be used for setting up descriptor sets