From cc61e38b9c6bf07a94abf488a3a56c9bf226625f Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 9 Jan 2019 16:17:54 +0100 Subject: [PATCH] [dxvk] Reimplement DxvkBufferView Instead of recreating the buffer view every single time the underlying buffer gets invalidated, this keeps all buffer views around until the object itself gets destroyed. --- src/dxvk/dxvk_buffer.cpp | 56 ++++++++++++++++++++++++++---- src/dxvk/dxvk_buffer.h | 71 +++++++++++++++++++-------------------- src/dxvk/dxvk_context.cpp | 4 +-- 3 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index c316b0688..7e58586fb 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -81,20 +81,64 @@ namespace dxvk { const Rc& buffer, const DxvkBufferViewCreateInfo& info) : m_vkd(vkd), m_info(info), m_buffer(buffer), - m_physView(this->createView()), - m_revision(m_buffer->m_revision) { + m_bufferSlice (m_buffer->getSliceHandle()), + m_bufferView (createBufferView(m_bufferSlice)) { } DxvkBufferView::~DxvkBufferView() { - + if (m_views.empty()) { + m_vkd->vkDestroyBufferView( + m_vkd->device(), m_bufferView, nullptr); + } else { + for (const auto& pair : m_views) { + m_vkd->vkDestroyBufferView( + m_vkd->device(), pair.second, nullptr); + } + } } - Rc DxvkBufferView::createView() { - return new DxvkPhysicalBufferView( - m_vkd, m_buffer->slice(), m_info); + VkBufferView DxvkBufferView::createBufferView( + const DxvkBufferSliceHandle& slice) { + VkBufferViewCreateInfo viewInfo; + viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + viewInfo.pNext = nullptr; + viewInfo.flags = 0; + viewInfo.buffer = slice.handle; + viewInfo.format = m_info.format; + viewInfo.offset = slice.offset; + viewInfo.range = slice.length; + + VkBufferView result = VK_NULL_HANDLE; + + if (m_vkd->vkCreateBufferView(m_vkd->device(), + &viewInfo, nullptr, &result) != VK_SUCCESS) { + throw DxvkError(str::format( + "DxvkBufferView: Failed to create buffer view:", + "\n Offset: ", viewInfo.offset, + "\n Range: ", viewInfo.range, + "\n Format: ", viewInfo.format)); + } + + return result; + } + + + void DxvkBufferView::updateBufferView() { + if (m_views.empty()) + m_views.insert({ m_bufferSlice, m_bufferView }); + + m_bufferSlice = m_buffer->getSliceHandle(); + auto entry = m_views.find(m_bufferSlice); + + if (entry != m_views.end()) { + m_bufferView = entry->second; + } else { + m_bufferView = createBufferView(m_bufferSlice); + m_views.insert({ m_bufferSlice, m_bufferView }); + } } diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index ad37ceb6d..3704fe76d 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -1,9 +1,10 @@ #pragma once -#include +#include #include #include "dxvk_buffer_res.h" +#include "dxvk_hash.h" namespace dxvk { @@ -19,6 +20,20 @@ namespace dxvk { VkDeviceSize offset; VkDeviceSize length; void* mapPtr; + + bool eq(const DxvkBufferSliceHandle& other) const { + return handle == other.handle + && offset == other.offset + && length == other.length; + } + + size_t hash() const { + DxvkHashState result; + result.add(std::hash()(handle)); + result.add(std::hash()(offset)); + result.add(std::hash()(length)); + return result; + } }; @@ -185,7 +200,6 @@ namespace dxvk { DxvkPhysicalBufferSlice rename(const DxvkPhysicalBufferSlice& slice) { DxvkPhysicalBufferSlice prevSlice = std::move(m_physSlice); m_physSlice = slice; - m_revision += 1; return prevSlice; } @@ -235,7 +249,6 @@ namespace dxvk { VkMemoryPropertyFlags m_memFlags; DxvkPhysicalBufferSlice m_physSlice; - uint32_t m_revision = 0; uint32_t m_vertexStride = 0; sync::Spinlock m_freeMutex; @@ -253,9 +266,6 @@ namespace dxvk { Rc allocPhysicalBuffer( VkDeviceSize sliceCount) const; - void lock(); - void unlock(); - }; @@ -437,7 +447,7 @@ namespace dxvk { * contents like formatted pixel data. These * buffer views are used as texel buffers. */ - class DxvkBufferView : public RcObject { + class DxvkBufferView : public DxvkResource { public: @@ -453,7 +463,7 @@ namespace dxvk { * \returns Buffer view handle */ VkBufferView handle() const { - return m_physView->handle(); + return m_bufferView; } /** @@ -493,20 +503,12 @@ namespace dxvk { return m_buffer->info(); } - /** - * \brief Backing resource - * \returns Backing resource - */ - Rc viewResource() const { - return m_physView; - } - /** * \brief Backing buffer resource * \returns Backing buffer resource */ Rc bufferResource() const { - return m_physView->bufferResource(); + return m_buffer->resource(); } /** @@ -529,14 +531,6 @@ namespace dxvk { m_info.rangeLength); } - /** - * \brief Underlying buffer slice - * \returns Slice backing the view - */ - DxvkPhysicalBufferSlice physicalSlice() const { - return m_physView->slice(); - } - /** * \brief Updates the buffer view * @@ -546,23 +540,28 @@ namespace dxvk { * prior to using the buffer view handle. */ void updateView() { - if (m_revision != m_buffer->m_revision) { - m_physView = this->createView(); - m_revision = m_buffer->m_revision; - } + if (!m_bufferSlice.eq(m_buffer->getSliceHandle())) + this->updateBufferView(); } private: - Rc m_vkd; - DxvkBufferViewCreateInfo m_info; + Rc m_vkd; + DxvkBufferViewCreateInfo m_info; + Rc m_buffer; + + DxvkBufferSliceHandle m_bufferSlice; + VkBufferView m_bufferView; + + std::unordered_map< + DxvkBufferSliceHandle, + VkBufferView, + DxvkHash, DxvkEq> m_views; - Rc m_buffer; - Rc m_physView; + VkBufferView createBufferView( + const DxvkBufferSliceHandle& slice); - uint32_t m_revision = 0; - - Rc createView(); + void updateBufferView(); }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index f3165e0f9..7432ea6df 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -346,7 +346,7 @@ namespace dxvk { bufferView->bufferInfo().stages, bufferView->bufferInfo().access); - m_cmd->trackResource(bufferView->viewResource()); + m_cmd->trackResource(bufferView); m_cmd->trackResource(bufferView->bufferResource()); } @@ -2766,7 +2766,7 @@ namespace dxvk { res.bufferView->updateView(); m_descInfos[i].texelBuffer = res.bufferView->handle(); - m_cmd->trackResource(res.bufferView->viewResource()); + m_cmd->trackResource(res.bufferView); m_cmd->trackResource(res.bufferView->bufferResource()); } else { updatePipelineState |= bindMask.setUnbound(i);