From 3057f6a51b50d3928284902304f06ce24a8a2fe1 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 21 Aug 2022 15:50:55 +0200 Subject: [PATCH] [dxvk] Add structures for sparse binding operations --- src/dxvk/dxvk_sparse.cpp | 61 ++++++++++++++++++++ src/dxvk/dxvk_sparse.h | 117 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/dxvk/dxvk_sparse.cpp b/src/dxvk/dxvk_sparse.cpp index 9b0e2eaa5..e521a49f1 100644 --- a/src/dxvk/dxvk_sparse.cpp +++ b/src/dxvk/dxvk_sparse.cpp @@ -335,4 +335,65 @@ namespace dxvk { } } + + VkBuffer DxvkSparsePageTable::getBufferHandle() const { + return m_buffer ? m_buffer->getSliceHandle().handle : VK_NULL_HANDLE; + } + + + VkImage DxvkSparsePageTable::getImageHandle() const { + return m_image ? m_image->handle() : VK_NULL_HANDLE; + } + + + uint32_t DxvkSparsePageTable::computePageIndex( + uint32_t subresource, + VkOffset3D regionOffset, + VkExtent3D regionExtent, + VkBool32 regionIsLinear, + uint32_t pageIndex) const { + auto subresourceInfo = getSubresourceProperties(subresource); + + // The mip tail is always linear + if (subresourceInfo.isMipTail) + return m_properties.mipTailPageIndex + pageIndex; + + // Compute offset into the given subresource + VkOffset3D pageOffset = regionOffset; + + if (!regionIsLinear) { + pageOffset.x += (pageIndex % regionExtent.width); + pageOffset.y += (pageIndex / regionExtent.width) % regionExtent.height; + pageOffset.z += (pageIndex / regionExtent.width) / regionExtent.height; + pageIndex = 0; + } + + uint32_t result = subresourceInfo.pageIndex + pageOffset.x + + subresourceInfo.pageCount.width * (pageOffset.y + + subresourceInfo.pageCount.height * pageOffset.z); + + return result + pageIndex; + } + + + DxvkSparseMapping DxvkSparsePageTable::getMapping( + uint32_t page) { + return page < m_mappings.size() + ? m_mappings[page] + : DxvkSparseMapping(); + } + + + void DxvkSparsePageTable::updateMapping( + DxvkCommandList* cmd, + uint32_t page, + DxvkSparseMapping&& mapping) { + if (m_mappings[page] != page) { + if (m_mappings[page]) + cmd->trackResource(m_mappings[page].m_page); + + m_mappings[page] = std::move(mapping); + } + } + } diff --git a/src/dxvk/dxvk_sparse.h b/src/dxvk/dxvk_sparse.h index c0585fa3b..f68aeb06a 100644 --- a/src/dxvk/dxvk_sparse.h +++ b/src/dxvk/dxvk_sparse.h @@ -9,8 +9,10 @@ namespace dxvk { class DxvkDevice; class DxvkBuffer; class DxvkImage; + class DxvkPagedResource; class DxvkSparsePage; class DxvkSparsePageAllocator; + class DxvkSparsePageTable; constexpr static VkDeviceSize SparseMemoryPageSize = 1ull << 16; @@ -112,6 +114,55 @@ namespace dxvk { }; + /** + * \brief Sparse binding flags + */ + enum class DxvkSparseBindFlag : uint32_t { + SkipSynchronization, + }; + + using DxvkSparseBindFlags = Flags; + + + /** + * \brief Sparse page binding mode + */ + enum class DxvkSparseBindMode : uint32_t { + Null, ///< Unbind the given resource page + Bind, ///< Bind to given allocator page + Copy, ///< Copy bindig from source resource + }; + + + /** + * \brief Sparse page binding info for a given page + * + * Stores the resource page index as well as the index + * of the allocator page that should be bound to that + * resource page. + */ + struct DxvkSparseBind { + DxvkSparseBindMode mode; + uint32_t dstPage; + uint32_t srcPage; + }; + + + /** + * \brief Sparse binding info + * + * Stores the resource to change page bindings for, the + * allocator from which pages will be allocated, and + * a list of page bidnings + */ + struct DxvkSparseBindInfo { + Rc dstResource; + Rc srcResource; + Rc srcAllocator; + std::vector binds; + }; + + /** * \brief Sparse memory page * @@ -153,6 +204,7 @@ namespace dxvk { */ class DxvkSparseMapping { friend DxvkSparsePageAllocator; + friend DxvkSparsePageTable; public: DxvkSparseMapping(); @@ -165,8 +217,15 @@ namespace dxvk { ~DxvkSparseMapping(); - Rc getPage() const { - return m_page; + /** + * \brief Queries memory handle + * \returns Memory information + */ + DxvkSparsePageHandle getHandle() const { + if (m_page == nullptr) + return DxvkSparsePageHandle(); + + return m_page->getHandle(); } bool operator == (const DxvkSparseMapping& other) const { @@ -286,6 +345,18 @@ namespace dxvk { return m_buffer || m_image; } + /** + * \brief Queries buffer handle + * \returns Buffer handle + */ + VkBuffer getBufferHandle() const; + + /** + * \brief Queries image handle + * \returns Image handle + */ + VkImage getImageHandle() const; + /** * \brief Counts total number of pages in the resources * @@ -340,6 +411,48 @@ namespace dxvk { : DxvkSparsePageInfo(); } + /** + * \brief Computes page index within a given image region + * + * \param [in] subresource Subresource index + * \param [in] regionOffset Region offset, in pages + * \param [in] regionExtent Region extent, in pages + * \param [in] regionIsLinear Whether to use the region extent + * \param [in] pageIndex Page within the given region + * \returns Page index. The returned number may be out + * of bounds if the given region is invalid. + */ + uint32_t computePageIndex( + uint32_t subresource, + VkOffset3D regionOffset, + VkExtent3D regionExtent, + VkBool32 regionIsLinear, + uint32_t pageIndex) const; + + /** + * \brief Queries page mapping + * + * \param [in] page Page index + * \returns Current page mapping + */ + DxvkSparseMapping getMapping( + uint32_t page); + + /** + * \brief Changes a page mapping + * + * Updates the given page mapping in the table, and ensures + * that the previously mapped page does not get destroyed + * prematurely by tracking it in the given command list. + * \param [in] cmd Command list + * \param [in] page Page index + * \param [in] mapping New mapping + */ + void updateMapping( + DxvkCommandList* cmd, + uint32_t page, + DxvkSparseMapping&& mapping); + private: const DxvkBuffer* m_buffer = nullptr;