diff --git a/src/dxvk/dxvk_barrier.cpp b/src/dxvk/dxvk_barrier.cpp index bcf679f80..6d752f2a7 100644 --- a/src/dxvk/dxvk_barrier.cpp +++ b/src/dxvk/dxvk_barrier.cpp @@ -410,6 +410,96 @@ namespace dxvk { + DxvkBarrierBatch::DxvkBarrierBatch(DxvkCmdBuffer cmdBuffer) + : m_cmdBuffer(cmdBuffer) { } + + + DxvkBarrierBatch::~DxvkBarrierBatch() { + + } + + + void DxvkBarrierBatch::addMemoryBarrier( + const VkMemoryBarrier2& barrier) { + if (unlikely(barrier.dstAccessMask & vk::AccessHostMask)) { + m_hostSrcStages |= barrier.srcStageMask & vk::StageDeviceMask; + m_hostDstAccess |= barrier.dstAccessMask & vk::AccessHostMask; + } + + m_memoryBarrier.srcStageMask |= barrier.srcStageMask & vk::StageDeviceMask; + m_memoryBarrier.srcAccessMask |= barrier.srcAccessMask & vk::AccessWriteMask; + m_memoryBarrier.dstStageMask |= barrier.dstStageMask & vk::StageDeviceMask; + m_memoryBarrier.dstAccessMask |= barrier.dstAccessMask & vk::AccessDeviceMask; + } + + + void DxvkBarrierBatch::addImageBarrier( + const VkImageMemoryBarrier2& barrier) { + if (unlikely(barrier.dstAccessMask & vk::AccessHostMask)) { + m_hostSrcStages |= barrier.srcStageMask & vk::StageDeviceMask; + m_hostDstAccess |= barrier.dstAccessMask & vk::AccessHostMask; + } + + if (barrier.oldLayout != barrier.newLayout || barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex) { + auto& entry = m_imageBarriers.emplace_back(barrier); + + entry.srcStageMask &= vk::StageDeviceMask; + entry.srcAccessMask &= vk::AccessWriteMask; + entry.dstStageMask &= vk::StageDeviceMask; + entry.dstAccessMask &= vk::AccessDeviceMask; + } else { + m_memoryBarrier.srcStageMask |= barrier.srcStageMask & vk::StageDeviceMask; + m_memoryBarrier.srcAccessMask |= barrier.srcAccessMask & vk::AccessWriteMask; + m_memoryBarrier.dstStageMask |= barrier.dstStageMask & vk::StageDeviceMask; + m_memoryBarrier.dstAccessMask |= barrier.dstAccessMask & vk::AccessDeviceMask; + } + } + + + void DxvkBarrierBatch::flush( + const Rc& list) { + VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO }; + + if (m_memoryBarrier.srcStageMask | m_memoryBarrier.dstStageMask) { + depInfo.memoryBarrierCount = 1; + depInfo.pMemoryBarriers = &m_memoryBarrier; + } + + if (!m_imageBarriers.empty()) { + depInfo.imageMemoryBarrierCount = m_imageBarriers.size(); + depInfo.pImageMemoryBarriers = m_imageBarriers.data(); + } + + if (!(depInfo.memoryBarrierCount | depInfo.imageMemoryBarrierCount)) + return; + + list->cmdPipelineBarrier(m_cmdBuffer, &depInfo); + + m_memoryBarrier.srcStageMask = 0u; + m_memoryBarrier.srcAccessMask = 0u; + m_memoryBarrier.dstStageMask = 0u; + m_memoryBarrier.dstAccessMask = 0u; + + m_imageBarriers.clear(); + } + + + void DxvkBarrierBatch::finalize( + const Rc& list) { + if (m_hostDstAccess) { + m_memoryBarrier.srcStageMask |= m_hostSrcStages; + m_memoryBarrier.dstStageMask |= VK_PIPELINE_STAGE_2_HOST_BIT; + m_memoryBarrier.dstAccessMask |= m_hostDstAccess; + + m_hostSrcStages = 0u; + m_hostDstAccess = 0u; + } + + flush(list); + } + + + DxvkBarrierSet:: DxvkBarrierSet(DxvkCmdBuffer cmdBuffer) : m_cmdBuffer(cmdBuffer) { diff --git a/src/dxvk/dxvk_barrier.h b/src/dxvk/dxvk_barrier.h index f4939161c..5cac7d46d 100644 --- a/src/dxvk/dxvk_barrier.h +++ b/src/dxvk/dxvk_barrier.h @@ -200,6 +200,68 @@ namespace dxvk { }; + /** + * \brief Barrier batch + * + * Simple helper class to accumulate barriers that can then + * be recorded into a command buffer in a single step. + */ + class DxvkBarrierBatch { + + public: + + DxvkBarrierBatch(DxvkCmdBuffer cmdBuffer); + ~DxvkBarrierBatch(); + + /** + * \brief Adds a memory barrier + * + * Host read access will only be flushed + * at the end of a command list. + * \param [in] barrier Memory barrier + */ + void addMemoryBarrier( + const VkMemoryBarrier2& barrier); + + /** + * \brief Adds an image barrier + * + * This will automatically turn into a normal memory barrier + * if no queue family ownership transfer or layout transition + * happens. + * \param [in] barrier Memory barrier + */ + void addImageBarrier( + const VkImageMemoryBarrier2& barrier); + + /** + * \brief Flushes batched memory barriers + * \param [in] list Command list + */ + void flush( + const Rc& list); + + /** + * \brief Flushes batched memory and host barriers + * \param [in] list Command list + */ + void finalize( + const Rc& list); + + private: + + DxvkCmdBuffer m_cmdBuffer; + + VkMemoryBarrier2 m_memoryBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 }; + + VkPipelineStageFlags2 m_hostSrcStages = 0u; + VkAccessFlags2 m_hostDstAccess = 0u; + + std::vector m_imageBarriers = { }; + + }; + + /** * \brief Buffer slice for barrier tracking *