[dxvk] Add helpers to compute more granular image address ranges

This commit is contained in:
Philip Rebohle 2025-03-01 02:09:56 +01:00
parent 2acf4d3c51
commit 1be692801a
3 changed files with 66 additions and 17 deletions

View file

@ -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);
}

View file

@ -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<DxvkImageView> DxvkImage::createView(
const DxvkImageViewKey& info) {
std::unique_lock lock(m_viewMutex);

View file

@ -582,6 +582,31 @@ namespace dxvk {
return bit::uint48_t(reinterpret_cast<uintptr_t>(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
*