From 1be692801abcc60fdac1bbce68055715d32ccefc Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 1 Mar 2025 02:09:56 +0100 Subject: [PATCH] [dxvk] Add helpers to compute more granular image address ranges --- src/dxvk/dxvk_context.cpp | 35 ++++++++++++++++++----------------- src/dxvk/dxvk_image.cpp | 23 +++++++++++++++++++++++ src/dxvk/dxvk_image.h | 25 +++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 1013d5b52..6ebb1b140 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -7942,26 +7942,25 @@ namespace dxvk { uint32_t layerCount = image.info().numLayers; + DxvkAddressRange range; + range.resource = image.getResourceId(); + range.accessOp = accessOp; + if (subresources.levelCount == 1u || subresources.layerCount == layerCount) { - DxvkAddressRange range; - range.resource = image.getResourceId(); - range.accessOp = accessOp; - range.rangeStart = subresources.baseMipLevel * layerCount + subresources.baseArrayLayer; - range.rangeEnd = (subresources.baseMipLevel + subresources.levelCount - 1u) * layerCount - + (subresources.baseArrayLayer + subresources.layerCount - 1u); + range.rangeStart = image.getTrackingAddress( + subresources.baseMipLevel, subresources.baseArrayLayer); + range.rangeEnd = image.getTrackingAddress( + subresources.baseMipLevel + subresources.levelCount, + subresources.baseArrayLayer + subresources.layerCount) - 1u; if (hasWrite) m_barrierTracker.insertRange(range, DxvkAccess::Write); if (hasRead) m_barrierTracker.insertRange(range, DxvkAccess::Read); } else { - DxvkAddressRange range; - range.resource = image.getResourceId(); - range.accessOp = accessOp; - for (uint32_t i = subresources.baseMipLevel; i < subresources.baseMipLevel + subresources.levelCount; i++) { - range.rangeStart = i * layerCount + subresources.baseArrayLayer; - range.rangeEnd = range.rangeStart + subresources.layerCount - 1u; + range.rangeStart = image.getTrackingAddress(i, subresources.baseArrayLayer); + range.rangeEnd = image.getTrackingAddress(i, subresources.baseArrayLayer + subresources.layerCount) - 1u; if (hasWrite) m_barrierTracker.insertRange(range, DxvkAccess::Write); @@ -8223,9 +8222,11 @@ namespace dxvk { DxvkAddressRange range; range.resource = image.getResourceId(); range.accessOp = accessOp; - range.rangeStart = subresources.baseMipLevel * layerCount + subresources.baseArrayLayer; - range.rangeEnd = (subresources.baseMipLevel + subresources.levelCount - 1u) * layerCount - + (subresources.baseArrayLayer + subresources.layerCount - 1u); + range.rangeStart = image.getTrackingAddress( + subresources.baseMipLevel, subresources.baseArrayLayer); + range.rangeEnd = image.getTrackingAddress( + subresources.baseMipLevel + subresources.levelCount, + subresources.baseArrayLayer + subresources.layerCount) - 1u; // Probe all subresources first, only check individual mip levels // if there are overlaps and if we are checking a subset of array @@ -8236,8 +8237,8 @@ namespace dxvk { return dirty; for (uint32_t i = subresources.baseMipLevel; i < subresources.baseMipLevel + subresources.levelCount && !dirty; i++) { - range.rangeStart = i * layerCount + subresources.baseArrayLayer; - range.rangeEnd = range.rangeStart + subresources.layerCount - 1u; + range.rangeStart = image.getTrackingAddress(i, subresources.baseArrayLayer); + range.rangeEnd = image.getTrackingAddress(i, subresources.baseArrayLayer + subresources.layerCount) - 1u; dirty = m_barrierTracker.findRange(range, access); } diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index bc7bc5446..767c0c771 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -114,6 +114,29 @@ namespace dxvk { } + uint64_t DxvkImage::getTrackingAddress(uint32_t mip, uint32_t layer, VkOffset3D coord) const { + // For 2D and 3D images, use morton codes to linearize the address ranges + // of pixel blocks. This helps reduce false positives in common use cases + // where the application copies aligned power-of-two blocks around. + uint64_t base = getTrackingAddress(mip, layer); + + if (likely(m_info.type == VK_IMAGE_TYPE_2D)) + return base + bit::interleave(coord.x, coord.y); + + // For 1D we can simply use the pixel coordinate as-is + if (m_info.type == VK_IMAGE_TYPE_1D) + return base + coord.x; + + // 3D is uncommon, but there are different use cases. Assume that if the + // format is block-compressed, the app will access one layer at a time. + if (formatInfo()->flags.test(DxvkFormatFlag::BlockCompressed)) + return base + bit::interleave(coord.x, coord.y) + (uint64_t(coord.z) << 32u); + + // Otherwise, it may want to copy actual 3D blocks around. + return base + bit::interleave(coord.x, coord.y, coord.z); + } + + Rc DxvkImage::createView( const DxvkImageViewKey& info) { std::unique_lock lock(m_viewMutex); diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 87e3deaf6..b303218d6 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -582,6 +582,31 @@ namespace dxvk { return bit::uint48_t(reinterpret_cast(m_storage.ptr()) / (Align & -Align)); } + /** + * \brief Computes virtual offset of a subresource + * + * Used for hazard tracking. Ignores the aspect mask and + * only takes the mip level and array layer into account. + * \param [in] mip Mip level index + * \param [in] layer Array layer index + */ + uint64_t getTrackingAddress(uint32_t mip, uint32_t layer) const { + // Put layers within the same mip into a contiguous range. This works well + // for not only transfer operations but also most image view use cases. + return uint64_t((m_info.numLayers * mip) + layer) << 48u; + } + + /** + * \brief Computes virtual offset of a specific image region + * + * Used for more granular hazard tracking. This interleaves coordinate + * bits in order to compute a unique address for each pixel. + * \param [in] mip Mip level index + * \param [in] layer Array layer index + * \param [in] coord Pixel coordinate within the subresource + */ + uint64_t getTrackingAddress(uint32_t mip, uint32_t layer, VkOffset3D coord) const; + /** * \brief Creates or retrieves an image view *