text: //
  // Copyright (c) 2020 Amer Koleci and contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  //
  
  #include "VulkanTexture.h"
  #include "VulkanGraphicsDevice.h"
  
  namespace Alimer
  {
      VulkanTexture::VulkanTexture(VulkanGraphicsDevice* device, const TextureDescription& desc, VkImage handle_, VkImageLayout layout)
          : Texture(desc)
          , device{ device }
          , layout{ layout }
      {
          if (handle_ != VK_NULL_HANDLE)
          {
              handle = handle_;
              allocation = VK_NULL_HANDLE;
          }
          else
          {
              VkImageCreateInfo createInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
              createInfo.flags = 0u;
              createInfo.imageType = VK_IMAGE_TYPE_2D;
              createInfo.format = VK_FORMAT_R8G8B8A8_UNORM; // GetVkFormat(desc->format);
              createInfo.extent.width = desc.width;
              createInfo.extent.height = desc.height;
              createInfo.extent.depth = desc.depth;
              createInfo.mipLevels = desc.mipLevels;
              createInfo.arrayLayers = desc.arrayLayers;
              createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
              createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
              createInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; // vgpu_vkGetImageUsage(desc->usage, desc->format);
              createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
              createInfo.queueFamilyIndexCount = 0;
              createInfo.pQueueFamilyIndices = nullptr;
              createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  
              VmaAllocationCreateInfo allocCreateInfo = {};
              allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  
              VkResult result = vmaCreateImage(device->GetAllocator(),
                  &createInfo, &allocCreateInfo,
                  &handle, &allocation,
                  nullptr);
  
              if (result != VK_SUCCESS)
              {
                  LOGE("Vulkan: Failed to create image");
              }
          }
      }
  
      VulkanTexture::~VulkanTexture()
      {
          Destroy();
      }
  
      void VulkanTexture::Destroy()
      {
          if (handle != VK_NULL_HANDLE
              && allocation != VK_NULL_HANDLE)
          {
              //unmap();
              //vmaDestroyImage(device->GetAllocator(), handle, allocation);
          }
      }
  
      void VulkanTexture::BackendSetName()
      {
          device->SetObjectName(VK_OBJECT_TYPE_IMAGE, (uint64_t)handle, name);
      }
  
      void VulkanTexture::Barrier(VkCommandBuffer commandBuffer, VkImageLayout newLayout)
      {
          if (layout == newLayout)
              return;
  
          VkImageMemoryBarrier imageMemoryBarrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
          imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
          imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  
          imageMemoryBarrier.oldLayout = layout;
          imageMemoryBarrier.newLayout = newLayout;
          imageMemoryBarrier.image = handle;
          imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
          imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
          imageMemoryBarrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
          imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
          imageMemoryBarrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
  
          // Source layouts (old)
          // Source access mask controls actions that have to be finished on the old layout
          // before it will be transitioned to the new layout
          switch (layout)
          {
          case VK_IMAGE_LAYOUT_UNDEFINED:
              // Image layout is undefined (or does not matter)
              // Only valid as initial layout
              // No flags required, listed only for completeness
              imageMemoryBarrier.srcAccessMask = 0;
              break;
  
          case VK_IMAGE_LAYOUT_PREINITIALIZED:
              // Image is preinitialized
              // Only valid as initial layout for linear images, preserves memory contents
              // Make sure host writes have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
              // Image is a color attachment
              // Make sure any writes to the color buffer have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
              // Image is a depth/stencil attachment
              // Make sure any writes to the depth/stencil buffer have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
              // Image is a transfer source
              // Make sure any reads from the image have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
              // Image is a transfer destination
              // Make sure any writes to the image have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
              // Image is read by a shader
              // Make sure any shader reads from the image have been finished
              imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
              break;
          default:
              // Other source layouts aren't handled (yet)
              break;
          }
  
          // Target layouts (new)
          // Destination access mask controls the dependency for the new image layout
          switch (newLayout)
          {
          case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
              // Image will be used as a transfer destination
              // Make sure any writes to the image have been finished
              imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
              // Image will be used as a transfer source
              // Make sure any reads from the image have been finished
              imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
              // Image will be used as a color attachment
              // Make sure any writes to the color buffer have been finished
              imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
              // Image layout will be used as a depth/stencil attachment
              // Make sure any writes to depth/stencil buffer have been finished
              imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
              break;
  
          case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
              // Image will be read in a shader (sampler, input attachment)
              // Make sure any writes to the image have been finished
              if (imageMemoryBarrier.srcAccessMask == 0)
              {
                  imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
              }
              imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
              break;
          default:
              // Other source layouts aren't handled (yet)
              break;
          }
  
          vkCmdPipelineBarrier(
              commandBuffer,
              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
              0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
  
          layout = newLayout;
      }
  }
  