text: /*
   ***********************************************************************************************************************
   *
   *  Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All Rights Reserved.
   *
   *  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.
   *
   **********************************************************************************************************************/
  /**
  ***********************************************************************************************************************
  * @file  barrier_filter_layer.cpp
  * @brief Implementation of the Barrier Filter Layer.
  ***********************************************************************************************************************
  */
  
  #include "barrier_filter_layer.h"
  
  #include "include/vk_conv.h"
  #include "include/vk_cmdbuffer.h"
  #include "include/vk_device.h"
  #include "include/vk_dispatch.h"
  
  namespace vk
  {
  
  // =====================================================================================================================
  BarrierFilterLayer::BarrierFilterLayer()
  {
  }
  
  // =====================================================================================================================
  BarrierFilterLayer::~BarrierFilterLayer()
  {
  }
  
  namespace entry
  {
  
  namespace barrier_filter_layer
  {
  
  // =====================================================================================================================
  VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(
      VkCommandBuffer                             cmdBuffer,
      VkPipelineStageFlags                        srcStageMask,
      VkPipelineStageFlags                        dstStageMask,
      VkDependencyFlags                           dependencyFlags,
      uint32_t                                    memoryBarrierCount,
      const VkMemoryBarrier*                      pMemoryBarriers,
      uint32_t                                    bufferMemoryBarrierCount,
      const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
      uint32_t                                    imageMemoryBarrierCount,
      const VkImageMemoryBarrier*                 pImageMemoryBarriers)
  {
      CmdBuffer*          pCmdBuffer    = ApiCmdBuffer::ObjectFromHandle(cmdBuffer);
      BarrierFilterLayer* pLayer        = pCmdBuffer->VkDevice()->GetBarrierFilterLayer();
      const uint32_t      filterOptions = pCmdBuffer->VkDevice()->GetRuntimeSettings().barrierFilterOptions;
  
      {
          uint32_t memoryCount = memoryBarrierCount;
          uint32_t bufferCount = bufferMemoryBarrierCount;
          uint32_t imageCount  = imageMemoryBarrierCount;
  
          VkMemoryBarrier*       pMemory  = nullptr;
          VkBufferMemoryBarrier* pBuffers = nullptr;
          VkImageMemoryBarrier*  pImages  = nullptr;
  
          VirtualStackFrame virtStackFrame(pCmdBuffer->GetStackAllocator());
  
          if (memoryCount > 0)
          {
              pMemory = virtStackFrame.AllocArray<VkMemoryBarrier>(memoryCount);
  
              if (pMemory != nullptr)
              {
                  // Reset the count and loop through to filter out memory barriers deemed unnecessary
                  memoryCount = 0;
  
                  for (uint32_t i = 0; i < memoryBarrierCount; ++i)
                  {
                      if (((filterOptions & SkipDuplicateResourceBarriers) == 0) ||
                          (pMemoryBarriers[i].srcAccessMask != pMemoryBarriers[i].dstAccessMask))
                      {
                          pMemory[memoryCount++] = pMemoryBarriers[i];
                      }
                  }
              }
          }
  
          if (bufferCount > 0)
          {
              pBuffers = virtStackFrame.AllocArray<VkBufferMemoryBarrier>(bufferCount);
  
              if (pBuffers != nullptr)
              {
                  // Reset the count and loop through to filter out buffer memory barriers deemed unnecessary
                  bufferCount = 0;
  
                  for (uint32_t i = 0; i < bufferMemoryBarrierCount; ++i)
                  {
                      if (((filterOptions & SkipDuplicateResourceBarriers) == 0) ||
                          (pBufferMemoryBarriers[i].srcAccessMask != pBufferMemoryBarriers[i].dstAccessMask) ||
                          (pBufferMemoryBarriers[i].srcQueueFamilyIndex != pBufferMemoryBarriers[i].dstQueueFamilyIndex))
                      {
                          pBuffers[bufferCount++] = pBufferMemoryBarriers[i];
                      }
                  }
              }
          }
  
          if (imageCount > 0)
          {
              pImages = virtStackFrame.AllocArray<VkImageMemoryBarrier>(imageCount);
  
              if (pImages != nullptr)
              {
                  // Reset the count and loop through to filter out image memory barriers deemed unnecessary
                  imageCount = 0;
  
                  for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i)
                  {
                      if ((((filterOptions & SkipImageLayoutUndefined) == 0) ||
                           (pImageMemoryBarriers[i].oldLayout != VK_IMAGE_LAYOUT_UNDEFINED) ||
                           (pImageMemoryBarriers[i].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)) &&
                          (((filterOptions & SkipDuplicateResourceBarriers) == 0) ||
                           (pImageMemoryBarriers[i].oldLayout != pImageMemoryBarriers[i].newLayout) ||
                           (pImageMemoryBarriers[i].srcAccessMask != pImageMemoryBarriers[i].dstAccessMask) ||
                           (pImageMemoryBarriers[i].srcQueueFamilyIndex != pImageMemoryBarriers[i].dstQueueFamilyIndex)))
                      {
                          pImages[imageCount++] = pImageMemoryBarriers[i];
                      }
                  }
              }
          }
  
          const uint32_t resourceBarrierCount = memoryCount + bufferCount + imageCount;
  
          if ((resourceBarrierCount > 0) || ((filterOptions & SkipStrayExecutionDependencies) == 0))
          {
              pLayer->GetNextLayer()->GetEntryPoints().vkCmdPipelineBarrier(
                  cmdBuffer,
                  srcStageMask,
                  dstStageMask,
                  dependencyFlags,
                  memoryCount,
                  (pMemory != nullptr) ? pMemory : pMemoryBarriers,
                  bufferCount,
                  (pBuffers != nullptr) ? pBuffers : pBufferMemoryBarriers,
                  imageCount,
                  (pImages != nullptr) ? pImages : pImageMemoryBarriers);
          }
  
          if (pMemory != nullptr)
          {
              virtStackFrame.FreeArray(pMemory);
          }
  
          if (pBuffers != nullptr)
          {
              virtStackFrame.FreeArray(pBuffers);
          }
  
          if (pImages != nullptr)
          {
              virtStackFrame.FreeArray(pImages);
          }
      }
  }
  
  // =====================================================================================================================
  VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(
      VkDevice                                    device,
      const VkImageCreateInfo*                    pCreateInfo,
      const VkAllocationCallbacks*                pAllocator,
      VkImage*                                    pImage)
  {
      VkImageCreateInfo createInfo = *pCreateInfo;
  
      createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  
      Device* pDevice = ApiDevice::ObjectFromHandle(device);
  
      return pDevice->GetBarrierFilterLayer()->GetNextLayer()->GetEntryPoints().vkCreateImage(device,
                                                                                              &createInfo,
                                                                                              pAllocator,
                                                                                              pImage);
  }
  
  } // namespace barrier_filter_layer
  
  } // entry
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
  #define BARRIER_FILTER_LAYER_OVERRIDE_ALIAS(entry_name, func_name) \
      pDispatchTable->OverrideEntryPoints()->entry_name = vk::entry::barrier_filter_layer::func_name
  
  #define BARRIER_FILTER_LAYER_OVERRIDE_ENTRY(entry_name) \
      BARRIER_FILTER_LAYER_OVERRIDE_ALIAS(entry_name, entry_name)
  
  // =====================================================================================================================
  void BarrierFilterLayer::OverrideDispatchTable(
      DispatchTable* pDispatchTable)
  {
      // Save current device dispatch table to use as the next layer.
      m_nextLayer = *pDispatchTable;
  
      const RuntimeSettings& settings = pDispatchTable->GetDevice()->GetRuntimeSettings();
  
      // It is not useful to add this layer without any filter options set.
      VK_ASSERT(settings.barrierFilterOptions != BarrierFilterDisabled);
  
      if (settings.barrierFilterOptions & (SkipStrayExecutionDependencies |
                                           SkipImageLayoutUndefined       |
                                           SkipDuplicateResourceBarriers  |
                                           SkipWithAppProfile             |
                                           SkipWithAppProfileRegen        |
                                           SkipWithIntDevOverlay))
      {
          BARRIER_FILTER_LAYER_OVERRIDE_ENTRY(vkCmdPipelineBarrier);
      }
  
      if (settings.barrierFilterOptions & ForceImageSharingModeExclusive)
      {
          BARRIER_FILTER_LAYER_OVERRIDE_ENTRY(vkCreateImage);
      }
  
  }
  
  } // namespace vk
  