diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0293c0f8..cef89760 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1800,6 +1800,30 @@ namespace dxvk { } + void DxvkContext::swapImages( + const Rc& image1, + const Rc& image2) { + Rc dump = new DxvkImageViewDump(m_device->vkd()); + image1->swap(image2, dump); + + // Usage flags are required to be identical + VkImageUsageFlags usage = image1->info().usage; + + if (usage & (VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT)) { + m_flags.set( + DxvkContextFlag::GpDirtyResources, + DxvkContextFlag::CpDirtyResources); + } + + if (usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) + this->spillRenderPass(); + + m_cmd->trackResource(dump); + } + + void DxvkContext::transformImage( const Rc& dstImage, const VkImageSubresourceRange& dstSubresources, diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 2456b20a..29b54a53 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -708,6 +708,21 @@ namespace dxvk { VkResolveModeFlagBitsKHR depthMode, VkResolveModeFlagBitsKHR stencilMode); + /** + * \brief Swaps two images + * + * Exchanges the image handles and backing storage + * of the two images, and recreates all the views. + * Note that the two images must have been created + * with identical properties, including the memory + * properties. + * \param [in] image1 The first image + * \param [in] image2 The second image + */ + void swapImages( + const Rc& image1, + const Rc& image2); + /** * \brief Transforms image subresource layouts * diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index 3634eaf4..7dda7805 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -125,6 +125,20 @@ namespace dxvk { } + void DxvkImage::swap(const Rc& next, const Rc& dump) { + // Technically this could deadlock if two threads + // call this method, but that's undefined behaviour + // anyway so let's not care about it too much. + std::lock_guard lock1(this->m_viewLock); + std::lock_guard lock2(next->m_viewLock); + + std::swap(this->m_image, next->m_image); + + this->recreateViews(dump); + next->recreateViews(dump); + } + + void DxvkImage::addView(DxvkImageView* view) { m_viewList.push_back(view); } @@ -141,6 +155,14 @@ namespace dxvk { } + void DxvkImage::recreateViews(const Rc& dump) { + for (size_t i = 0; i < m_viewList.size(); i++) { + m_viewList[i]->discardViews(dump); + m_viewList[i]->createViews(); + } + } + + DxvkImageView::DxvkImageView( const Rc& vkd, const Rc& image, @@ -205,6 +227,16 @@ namespace dxvk { throw DxvkError(str::format("DxvkImageView: Invalid view type: ", m_info.type)); } } + + + void DxvkImageView::discardViews(const Rc& dump) { + for (uint32_t i = 0; i < ViewCount; i++) { + if (m_views[i]) { + dump->addView(m_views[i]); + m_views[i] = VK_NULL_HANDLE; + } + } + } void DxvkImageView::createView(VkImageViewType type, uint32_t numLayers) { @@ -261,5 +293,22 @@ namespace dxvk { "\n Tiling: ", m_image->info().tiling)); } } + + + DxvkImageViewDump::DxvkImageViewDump(const Rc& vkd) + : m_vkd(vkd) { + + } + + + DxvkImageViewDump::~DxvkImageViewDump() { + for (auto view : m_views) + m_vkd->vkDestroyImageView(m_vkd->device(), view, nullptr); + } + + + void DxvkImageViewDump::addView(VkImageView view) { + m_views.push_back(view); + } } \ No newline at end of file diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index ff6a7771..2f2c313d 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -9,6 +9,7 @@ namespace dxvk { class DxvkImageView; + class DxvkImageViewDump; /** * \brief Image create info @@ -115,6 +116,7 @@ namespace dxvk { * memory type and if created with the linear tiling option. */ class DxvkImage : public DxvkResource { + friend class DxvkContext; friend class DxvkImageView; public: @@ -283,6 +285,16 @@ namespace dxvk { VkDeviceSize memSize() const { return m_image.memory.length(); } + + /** + * \brief Swaps the image with another + * + * \param [in] next The other image + * \param [in] dump Image view dump + */ + void swap( + const Rc& next, + const Rc& dump); private: @@ -298,6 +310,8 @@ namespace dxvk { void addView(DxvkImageView* view); void removeView(DxvkImageView* view); + + void recreateViews(const Rc& dump); }; @@ -481,7 +495,32 @@ namespace dxvk { void createViews(); void createView(VkImageViewType type, uint32_t numLayers); + + void discardViews(const Rc& dump); }; + + + /** + * \brief Image view dump + * + * Takes orphaned image view objects and destroys + * them when they are no longer needed. + */ + class DxvkImageViewDump : public DxvkResource { + + public: + + DxvkImageViewDump(const Rc& vkd); + ~DxvkImageViewDump(); + + void addView(VkImageView view); + + private: + + Rc m_vkd; + std::vector m_views; + + }; } \ No newline at end of file