diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index c2ab3b5b8..2fda77b7c 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2460,6 +2460,97 @@ namespace dxvk { } + void DxvkContext::updatePageTable( + const DxvkSparseBindInfo& bindInfo, + DxvkSparseBindFlags flags) { + // Split command buffers here so that we execute + // the sparse binding operation at the right time + if (!flags.test(DxvkSparseBindFlag::SkipSynchronization)) + this->splitCommands(); + + DxvkSparsePageAllocator* srcAllocator = bindInfo.srcAllocator.ptr(); + DxvkSparsePageTable* dstPageTable = bindInfo.dstResource->getSparsePageTable(); + DxvkSparsePageTable* srcPageTable = nullptr; + + if (bindInfo.srcResource != nullptr) + srcPageTable = bindInfo.srcResource->getSparsePageTable(); + + // In order to support copies properly, we need to buffer the new + // mappings first before we apply them to the destination resource. + size_t bindCount = bindInfo.binds.size(); + std::vector mappings(bindCount); + + for (size_t i = 0; i < bindCount; i++) { + DxvkSparseBind bind = bindInfo.binds[i]; + + switch (bind.mode) { + case DxvkSparseBindMode::Null: + // The mapping array is already default-initialized + // so we don't actually need to do anything here + break; + + case DxvkSparseBindMode::Bind: + mappings[i] = srcAllocator->acquirePage(bind.srcPage); + break; + + case DxvkSparseBindMode::Copy: + mappings[i] = srcPageTable->getMapping(bind.srcPage); + break; + } + } + + // Process the actual page table updates here and resolve + // our internal structures to Vulkan resource and memory + // handles. The rest will be done at submission time. + for (size_t i = 0; i < bindCount; i++) { + DxvkSparseBind bind = bindInfo.binds[i]; + DxvkSparseMapping mapping = std::move(mappings[i]); + + DxvkSparsePageInfo pageInfo = dstPageTable->getPageInfo(bind.dstPage); + + switch (pageInfo.type) { + case DxvkSparsePageType::None: + break; + + case DxvkSparsePageType::Buffer: { + DxvkSparseBufferBindKey key; + key.buffer = dstPageTable->getBufferHandle(); + key.offset = pageInfo.buffer.offset; + key.size = pageInfo.buffer.length; + + m_cmd->bindBufferMemory(key, mapping.getHandle()); + } break; + + case DxvkSparsePageType::Image: { + DxvkSparseImageBindKey key; + key.image = dstPageTable->getImageHandle(); + key.subresource = pageInfo.image.subresource; + key.offset = pageInfo.image.offset; + key.extent = pageInfo.image.extent; + + m_cmd->bindImageMemory(key, mapping.getHandle()); + } break; + + case DxvkSparsePageType::ImageMipTail: { + DxvkSparseImageOpaqueBindKey key; + key.image = dstPageTable->getImageHandle(); + key.offset = pageInfo.mipTail.resourceOffset; + key.size = pageInfo.mipTail.resourceLength; + key.flags = 0; + + m_cmd->bindImageOpaqueMemory(key, mapping.getHandle()); + } break; + } + + // Update the page table mapping for tracking purposes + if (pageInfo.type != DxvkSparsePageType::None) + dstPageTable->updateMapping(m_cmd.ptr(), bind.dstPage, std::move(mapping)); + } + + m_cmd->trackResource(bindInfo.dstResource); + } + + void DxvkContext::signalGpuEvent(const Rc& event) { this->spillRenderPass(true); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index d18c7e5f0..952f1aae6 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1170,7 +1170,18 @@ namespace dxvk { */ void setBarrierControl( DxvkBarrierControlFlags control); - + + /** + * \brief Updates page table for a given sparse resource + * + * Note that this is a very high overhead operation. + * \param [in] bindInfo Sparse bind info + * \param [in] flags Sparse bind flags + */ + void updatePageTable( + const DxvkSparseBindInfo& bindInfo, + DxvkSparseBindFlags flags); + /** * \brief Launches a Cuda kernel *