diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 19564e9ae..8f0deaf66 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -9,63 +9,15 @@ namespace dxvk { DxvkBuffer::DxvkBuffer( DxvkDevice* device, const DxvkBufferCreateInfo& createInfo, - DxvkMemoryAllocator& memAlloc, + DxvkMemoryAllocator& allocator, VkMemoryPropertyFlags memFlags) : m_vkd (device->vkd()), - m_info (createInfo), - m_memAlloc (&memAlloc), - m_memFlags (memFlags), - m_shaderStages (util::shaderStages(createInfo.stages)) { - if (!(m_info.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) { - // Align slices so that we don't violate any alignment - // requirements imposed by the Vulkan device/driver - VkDeviceSize sliceAlignment = computeSliceAlignment(device); - m_physSliceLength = createInfo.size; - m_physSliceStride = align(createInfo.size, sliceAlignment); - - // Determine optimal allocation size for the buffer. If the buffer - // is small enough to hit the pool allocator, round its size up to - // a power of two to minimize the amount of internal fragmentation. - VkDeviceSize sliceSize = align(createInfo.size, sliceAlignment); - m_allocationSize = std::max(MinAllocationSize, sliceSize); - - if (m_allocationSize <= DxvkPoolAllocator::MaxSize) - m_allocationSize = (VkDeviceSize(-1) >> bit::lzcnt(m_allocationSize - 1u)) + 1u; - - m_maxAllocationSize = MaxSlicesPerAllocation * sliceSize; - m_maxAllocationSize = std::max(m_maxAllocationSize, MinAllocationSizeLimit); - m_maxAllocationSize = std::min(m_maxAllocationSize, MaxAllocationSize); - - // Allocate the initial set of buffer slices. Only clear - // buffer memory if there is more than one slice, since - // we expect the client api to initialize the first slice. - bool hasMultipleSlices = m_allocationSize >= sliceSize + sliceSize; - - m_buffer = allocBuffer(m_allocationSize, hasMultipleSlices); - - m_physSlice.handle = m_buffer.buffer; - m_physSlice.offset = m_buffer.getBaseOffset(); - m_physSlice.length = m_physSliceLength; - m_physSlice.mapPtr = m_buffer.memory.mapPtr(0); - - m_lazyAlloc = hasMultipleSlices; - } else { - m_physSliceLength = createInfo.size; - m_physSliceStride = createInfo.size; - - m_allocationSize = createInfo.size; - - m_buffer = createSparseBuffer(); - - m_physSlice.handle = m_buffer.buffer; - m_physSlice.offset = 0; - m_physSlice.length = createInfo.size; - m_physSlice.mapPtr = nullptr; - - m_lazyAlloc = false; - - m_sparsePageTable = DxvkSparsePageTable(device, this); - } + m_allocator (&allocator), + m_properties (memFlags), + m_shaderStages (util::shaderStages(createInfo.stages)), + m_info (createInfo) { + // Create and assign actual buffer resource + assignSlice(allocateSlice()); } @@ -75,155 +27,16 @@ namespace dxvk { const DxvkBufferImportInfo& importInfo, VkMemoryPropertyFlags memFlags) : m_vkd (device->vkd()), + m_properties (memFlags), + m_shaderStages (util::shaderStages(createInfo.stages)), m_info (createInfo), - m_import (importInfo), - m_memAlloc (nullptr), - m_memFlags (memFlags), - m_shaderStages (util::shaderStages(createInfo.stages)) { - m_physSliceLength = createInfo.size; - m_physSliceStride = createInfo.size; + m_import (importInfo) { - m_physSlice.handle = importInfo.buffer; - m_physSlice.offset = importInfo.offset; - m_physSlice.length = createInfo.size; - m_physSlice.mapPtr = importInfo.mapPtr; - - m_allocationSize = createInfo.size; - - m_lazyAlloc = false; } DxvkBuffer::~DxvkBuffer() { - for (const auto& buffer : m_buffers) { - if (buffer.buffer != buffer.memory.buffer()) - m_vkd->vkDestroyBuffer(m_vkd->device(), buffer.buffer, nullptr); - } - if (m_buffer.buffer != m_buffer.memory.buffer()) - m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer.buffer, nullptr); - } - - - DxvkBufferHandle DxvkBuffer::allocBuffer(VkDeviceSize allocationSize, bool clear) const { - VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - info.flags = m_info.flags; - info.size = allocationSize; - info.usage = m_info.usage; - info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - DxvkBufferHandle handle; - - // Query memory requirements and whether to use a dedicated allocation - DxvkMemoryRequirements memoryRequirements = { }; - memoryRequirements.tiling = VK_IMAGE_TILING_LINEAR; - memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS }; - memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated }; - - m_memAlloc->getBufferMemoryRequirements(info, memoryRequirements.core); - - // Fill in desired memory properties - DxvkMemoryProperties memoryProperties = { }; - memoryProperties.flags = m_memFlags; - - if (memoryRequirements.dedicated.prefersDedicatedAllocation) { - handle.buffer = createBuffer(info); - - memoryProperties.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO }; - memoryProperties.dedicated.buffer = handle.buffer; - } - - handle.memory = m_memAlloc->alloc(memoryRequirements, memoryProperties); - - if (!handle.buffer && (!handle.memory.buffer() || (handle.memory.getBufferUsage() & info.usage) != info.usage)) - handle.buffer = createBuffer(info); - - if (handle.buffer) { - if (m_vkd->vkBindBufferMemory(m_vkd->device(), handle.buffer, - handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS) - throw DxvkError("DxvkBuffer: Failed to bind device memory"); - } else { - handle.buffer = handle.memory.buffer(); - } - - if (clear && (m_memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) - std::memset(handle.memory.mapPtr(0), 0, info.size); - - return handle; - } - - - DxvkBufferHandle DxvkBuffer::createSparseBuffer() const { - VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - info.flags = m_info.flags; - info.size = m_info.size; - info.usage = m_info.usage; - info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - DxvkBufferHandle handle = { }; - - if (m_vkd->vkCreateBuffer(m_vkd->device(), - &info, nullptr, &handle.buffer) != VK_SUCCESS) { - throw DxvkError(str::format( - "DxvkBuffer: Failed to create buffer:" - "\n flags: ", std::hex, info.flags, - "\n size: ", std::dec, info.size, - "\n usage: ", std::hex, info.usage)); - } - - return handle; - } - - - VkBuffer DxvkBuffer::createBuffer(const VkBufferCreateInfo& info) const { - VkBuffer buffer = VK_NULL_HANDLE; - - if (m_vkd->vkCreateBuffer(m_vkd->device(), &info, nullptr, &buffer)) { - throw DxvkError(str::format( - "DxvkBuffer: Failed to create buffer:" - "\n flags: ", std::hex, info.flags, - "\n size: ", std::dec, info.size, - "\n usage: ", std::hex, info.usage)); - } - - return buffer; - } - - - VkDeviceSize DxvkBuffer::computeSliceAlignment(DxvkDevice* device) const { - const auto& devInfo = device->properties(); - - VkDeviceSize result = sizeof(uint32_t); - - if (m_info.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) { - result = std::max(result, devInfo.core.properties.limits.minUniformBufferOffsetAlignment); - result = std::max(result, devInfo.extRobustness2.robustUniformBufferAccessSizeAlignment); - } - - if (m_info.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) { - result = std::max(result, devInfo.core.properties.limits.minStorageBufferOffsetAlignment); - result = std::max(result, devInfo.extRobustness2.robustStorageBufferAccessSizeAlignment); - } - - if (m_info.usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) { - result = std::max(result, devInfo.core.properties.limits.minTexelBufferOffsetAlignment); - result = std::max(result, VkDeviceSize(16)); - } - - if (m_info.usage & (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - && m_info.size > (devInfo.core.properties.limits.optimalBufferCopyOffsetAlignment / 2)) - result = std::max(result, devInfo.core.properties.limits.optimalBufferCopyOffsetAlignment); - - // For some reason, Warhammer Chaosbane breaks otherwise - if (m_info.usage & (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) - result = std::max(result, VkDeviceSize(256)); - - if (m_memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - result = std::max(result, devInfo.core.properties.limits.nonCoherentAtomSize); - result = std::max(result, VkDeviceSize(64)); - } - - return result; } @@ -304,21 +117,4 @@ namespace dxvk { } } - - DxvkBufferTracker:: DxvkBufferTracker() { } - DxvkBufferTracker::~DxvkBufferTracker() { } - - - void DxvkBufferTracker::reset() { - std::sort(m_entries.begin(), m_entries.end(), - [] (const Entry& a, const Entry& b) { - return a.slice.handle < b.slice.handle; - }); - - for (const auto& e : m_entries) - e.buffer->freeSlice(e.slice); - - m_entries.clear(); - } - } \ No newline at end of file diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 3e597584d..5bce0c566 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -45,16 +45,16 @@ namespace dxvk { */ struct DxvkBufferViewCreateInfo { /// Buffer data format, like image data - VkFormat format; + VkFormat format = VK_FORMAT_UNDEFINED; /// Offset of the buffer region to include in the view - VkDeviceSize rangeOffset; + VkDeviceSize rangeOffset = 0u; /// Size of the buffer region to include in the view - VkDeviceSize rangeLength; + VkDeviceSize rangeLength = 0u; /// Buffer view usage flags - VkBufferUsageFlags usage; + VkBufferUsageFlags usage = 0u; }; @@ -129,36 +129,20 @@ namespace dxvk { */ class DxvkBufferAllocation { friend class DxvkBuffer; - friend class DxvkContext; /* TODO remove */ public: DxvkBufferAllocation() = default; - explicit DxvkBufferAllocation(DxvkBufferSliceHandle slice) - : m_slice(slice) { } - - DxvkBufferAllocation(const DxvkBufferAllocation&) = default; - DxvkBufferAllocation& operator = (const DxvkBufferAllocation&) = default; - - DxvkBufferAllocation(DxvkBufferAllocation&& other) - : m_slice(other.m_slice) { - other.m_slice = DxvkBufferSliceHandle(); - } - - DxvkBufferAllocation& operator = (DxvkBufferAllocation&& other) { - m_slice = other.m_slice; - other.m_slice = DxvkBufferSliceHandle(); - return *this; - } - - ~DxvkBufferAllocation() = default; + DxvkBufferAllocation( + Rc allocation) + : m_allocation(std::move(allocation)) { } /** * \brief Retrieves CPU pointer * \returns Pointer to the mapped buffer slice */ void* mapPtr() const { - return m_slice.mapPtr; + return m_allocation->getBufferInfo().mapPtr; } /** @@ -166,12 +150,20 @@ namespace dxvk { * \returns \c true if the slice is valid */ explicit operator bool () const { - return m_slice.handle != VK_NULL_HANDLE; + return bool(m_allocation); + } + + /** + * \brief Extracts resource allocation + * \returns Underlying resource allocation + */ + Rc extract() { + return std::move(m_allocation); } private: - DxvkBufferSliceHandle m_slice = { }; + Rc m_allocation; }; @@ -189,9 +181,8 @@ namespace dxvk { constexpr static VkDeviceSize MaxAllocationSize = DxvkPageAllocator::PageSize; constexpr static VkDeviceSize MinAllocationSize = DxvkPoolAllocator::MinSize; - constexpr static VkDeviceSize MinAllocationSizeLimit = MaxAllocationSize / 32u; - - constexpr static uint32_t MaxSlicesPerAllocation = 64u; + constexpr static VkDeviceSize MinMappedAllocationSize = DxvkPageAllocator::PageSize / 32u; + constexpr static VkDeviceSize MinMappedSlicesPerAllocation = 3u; public: DxvkBuffer( @@ -224,7 +215,7 @@ namespace dxvk { * \returns Vulkan memory flags */ VkMemoryPropertyFlags memFlags() const { - return m_memFlags; + return m_properties; } /** @@ -237,7 +228,9 @@ namespace dxvk { * \returns Pointer to mapped memory region */ void* mapPtr(VkDeviceSize offset) const { - return reinterpret_cast(m_physSlice.mapPtr) + offset; + return m_bufferInfo.mapPtr + ? reinterpret_cast(m_bufferInfo.mapPtr) + offset + : nullptr; } /** @@ -255,7 +248,12 @@ namespace dxvk { * \returns Buffer slice handle */ DxvkBufferSliceHandle getSliceHandle() const { - return m_physSlice; + DxvkBufferSliceHandle result = { }; + result.handle = m_bufferInfo.buffer; + result.offset = m_bufferInfo.offset; + result.length = m_info.size; + result.mapPtr = mapPtr(0); + return result; } /** @@ -266,9 +264,9 @@ namespace dxvk { * \returns Buffer slice handle */ DxvkBufferSliceHandle getSliceHandle(VkDeviceSize offset, VkDeviceSize length) const { - DxvkBufferSliceHandle result; - result.handle = m_physSlice.handle; - result.offset = m_physSlice.offset + offset; + DxvkBufferSliceHandle result = { }; + result.handle = m_bufferInfo.buffer; + result.offset = m_bufferInfo.offset + offset; result.length = length; result.mapPtr = mapPtr(offset); return result; @@ -282,10 +280,10 @@ namespace dxvk { * \returns Buffer slice descriptor */ DxvkDescriptorInfo getDescriptor(VkDeviceSize offset, VkDeviceSize length) const { - DxvkDescriptorInfo result; - result.buffer.buffer = m_physSlice.handle; - result.buffer.offset = m_physSlice.offset + offset; - result.buffer.range = length; + DxvkDescriptorInfo result = { }; + result.buffer.buffer = m_bufferInfo.buffer; + result.buffer.offset = m_bufferInfo.offset + offset; + result.buffer.range = length; return result; } @@ -296,7 +294,7 @@ namespace dxvk { * \returns The current xfb vertex stride */ uint32_t getXfbVertexStride() const { - return m_vertexStride; + return m_xfbStride; } /** @@ -308,7 +306,7 @@ namespace dxvk { * \param [in] stride Vertex stride */ void setXfbVertexStride(uint32_t stride) { - m_vertexStride = stride; + m_xfbStride = stride; } /** @@ -316,39 +314,13 @@ namespace dxvk { * \returns The new buffer slice */ DxvkBufferAllocation allocateSlice() { - std::unique_lock freeLock(m_freeMutex); - - // If no slices are available, swap the two free lists. - if (unlikely(m_freeSlices.empty())) { - std::unique_lock swapLock(m_swapMutex); - std::swap(m_freeSlices, m_nextSlices); - } + VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + info.flags = m_info.flags; + info.usage = m_info.usage; + info.size = m_info.size; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - // If there are still no slices available, create a new - // backing buffer and add all slices to the free list. - if (unlikely(m_freeSlices.empty())) { - if (likely(!m_lazyAlloc)) { - DxvkBufferHandle handle = allocBuffer(m_allocationSize, true); - - for (uint32_t i = 0; (i + 1) * m_physSliceStride <= m_allocationSize; i++) - pushSlice(handle, i); - - m_buffers.push_back(std::move(handle)); - - if (2u * m_allocationSize <= m_maxAllocationSize) - m_allocationSize *= 2u; - } else { - for (uint32_t i = 1; (i + 1) * m_physSliceStride <= m_allocationSize; i++) - pushSlice(m_buffer, i); - - m_lazyAlloc = false; - } - } - - // Take the first slice from the queue - DxvkBufferAllocation result(m_freeSlices.back()); - m_freeSlices.pop_back(); - return result; + return DxvkBufferAllocation(m_allocator->createBufferResource(info, m_properties)); } /** @@ -359,12 +331,13 @@ namespace dxvk { * not call this directly as this is called implicitly * by the context's \c invalidateBuffer method. * \param [in] slice The new backing resource - * \returns Previous buffer slice + * \returns Previous buffer allocation */ - DxvkBufferAllocation assignSlice(DxvkBufferAllocation&& slice) { - DxvkBufferAllocation result(m_physSlice); - m_physSlice = slice.m_slice; - slice.m_slice = DxvkBufferSliceHandle(); + Rc assignSlice(DxvkBufferAllocation&& slice) { + Rc result = std::move(m_storage); + + m_storage = std::move(slice.m_allocation); + m_bufferInfo = m_storage->getBufferInfo(); return result; } @@ -373,21 +346,7 @@ namespace dxvk { * \returns Current buffer allocation */ DxvkBufferAllocation getAllocation() const { - return DxvkBufferAllocation(m_physSlice); - } - - /** - * \brief Frees a buffer slice - * - * Marks the slice as free so that it can be used for - * subsequent allocations. Called automatically when - * the slice is no longer needed by the GPU. - * \param [in] slice The buffer slice to free - */ - void freeSlice(const DxvkBufferSliceHandle& slice) { - // Add slice to a separate free list to reduce lock contention. - std::unique_lock swapLock(m_swapMutex); - m_nextSlices.emplace_back(slice); + return DxvkBufferAllocation(m_storage); } /** @@ -400,53 +359,19 @@ namespace dxvk { private: - Rc m_vkd; - DxvkBufferCreateInfo m_info; - DxvkBufferImportInfo m_import; - DxvkMemoryAllocator* m_memAlloc; - VkMemoryPropertyFlags m_memFlags; - VkShaderStageFlags m_shaderStages; - - DxvkBufferHandle m_buffer; - DxvkBufferSliceHandle m_physSlice; - uint32_t m_vertexStride = 0; + Rc m_vkd; + DxvkMemoryAllocator* m_allocator = nullptr; + VkMemoryPropertyFlags m_properties = 0u; + VkShaderStageFlags m_shaderStages = 0u; - alignas(CACHE_LINE_SIZE) - sync::Spinlock m_freeMutex; + DxvkBufferCreateInfo m_info = { }; + DxvkBufferImportInfo m_import = { }; - uint32_t m_lazyAlloc = false; - VkDeviceSize m_physSliceLength = 0; - VkDeviceSize m_physSliceStride = 0; + VkDeviceSize m_xfbStride = 0u; - VkDeviceSize m_allocationSize = 0; - VkDeviceSize m_maxAllocationSize = 0; + DxvkResourceBufferInfo m_bufferInfo = { }; - std::vector m_buffers; - std::vector m_freeSlices; - - alignas(CACHE_LINE_SIZE) - sync::Spinlock m_swapMutex; - std::vector m_nextSlices; - - void pushSlice(const DxvkBufferHandle& handle, uint32_t index) { - DxvkBufferSliceHandle slice; - slice.handle = handle.buffer; - slice.offset = handle.getBaseOffset() + m_physSliceStride * index; - slice.length = m_physSliceLength; - slice.mapPtr = handle.memory.mapPtr(m_physSliceStride * index); - m_freeSlices.emplace_back(slice); - } - - DxvkBufferHandle allocBuffer( - VkDeviceSize allocationSize, - bool clear) const; - - DxvkBufferHandle createSparseBuffer() const; - - VkBuffer createBuffer(const VkBufferCreateInfo& info) const; - - VkDeviceSize computeSliceAlignment( - DxvkDevice* device) const; + Rc m_storage; }; @@ -772,48 +697,5 @@ namespace dxvk { const DxvkBufferSliceHandle& slice); }; - - - /** - * \brief Buffer slice tracker - * - * Stores a list of buffer slices that can be - * freed. Useful when buffers have been renamed - * and the original slice is no longer needed. - */ - class DxvkBufferTracker { - - public: - - DxvkBufferTracker(); - ~DxvkBufferTracker(); - - /** - * \brief Add buffer slice for tracking - * - * The slice will be returned to the - * buffer on the next call to \c reset. - * \param [in] buffer The parent buffer - * \param [in] slice The buffer slice - */ - void freeBufferSlice(const Rc& buffer, const DxvkBufferSliceHandle& slice) { - m_entries.push_back({ buffer, slice }); - } - - /** - * \brief Returns tracked buffer slices - */ - void reset(); - - private: - - struct Entry { - Rc buffer; - DxvkBufferSliceHandle slice; - }; - - std::vector m_entries; - - }; - + } \ No newline at end of file diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 3bd3aa953..0e3020e87 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -368,9 +368,6 @@ namespace dxvk { // that are no longer in use m_resources.reset(); - // Return buffer memory slices - m_bufferTracker.reset(); - // Return query and event handles m_gpuQueryTracker.reset(); m_gpuEventTracker.reset(); diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 1934b9a05..7a858db24 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -248,21 +248,6 @@ namespace dxvk { */ void next(); - /** - * \brief Frees buffer slice - * - * After the command buffer execution has finished, - * the given buffer slice will be released to the - * virtual buffer object so that it can be reused. - * \param [in] buffer The virtual buffer object - * \param [in] slice The buffer slice handle - */ - void freeBufferSlice( - const Rc& buffer, - const DxvkBufferSliceHandle& slice) { - m_bufferTracker.freeBufferSlice(buffer, slice); - } - /** * \brief Adds a resource to track * @@ -323,7 +308,7 @@ namespace dxvk { * \brief Notifies resources and signals */ void notifyObjects() { - m_resources.notify(); + m_resources.reset(); m_signalTracker.notify(); } @@ -1048,7 +1033,6 @@ namespace dxvk { DxvkSignalTracker m_signalTracker; DxvkGpuEventTracker m_gpuEventTracker; DxvkGpuQueryTracker m_gpuQueryTracker; - DxvkBufferTracker m_bufferTracker; DxvkStatCounters m_statCounters; DxvkCommandSubmission m_commandSubmission; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b60fa4205..22ef0f5f3 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1830,9 +1830,9 @@ namespace dxvk { const Rc& buffer, DxvkBufferAllocation&& slice) { // Allocate new backing resource - DxvkBufferAllocation prevSlice = buffer->assignSlice(std::move(slice)); - m_cmd->freeBufferSlice(buffer, prevSlice.m_slice); - + Rc prevAllocation = buffer->assignSlice(std::move(slice)); + m_cmd->trackResource(prevAllocation); + // We also need to update all bindings that the buffer // may be bound to either directly or through views. VkBufferUsageFlags usage = buffer->info().usage & diff --git a/src/dxvk/dxvk_lifetime.cpp b/src/dxvk/dxvk_lifetime.cpp index c38e78651..6b43f93e1 100644 --- a/src/dxvk/dxvk_lifetime.cpp +++ b/src/dxvk/dxvk_lifetime.cpp @@ -6,13 +6,9 @@ namespace dxvk { DxvkLifetimeTracker::~DxvkLifetimeTracker() { } - void DxvkLifetimeTracker::notify() { - m_resources.clear(); - } - - void DxvkLifetimeTracker::reset() { m_resources.clear(); + m_allocations.clear(); } } \ No newline at end of file diff --git a/src/dxvk/dxvk_lifetime.h b/src/dxvk/dxvk_lifetime.h index b211d6a1b..cb48dc518 100644 --- a/src/dxvk/dxvk_lifetime.h +++ b/src/dxvk/dxvk_lifetime.h @@ -11,39 +11,38 @@ namespace dxvk { * * Keeps a resource alive and stores access information. */ + template class DxvkLifetime { + static constexpr uintptr_t AccessMask = 0x3u; + static constexpr uintptr_t PointerMask = ~AccessMask; + static_assert(alignof(T) > AccessMask); public: - DxvkLifetime() - : m_resource(nullptr), m_access(DxvkAccess::None) { } + DxvkLifetime() = default; DxvkLifetime( - DxvkResource* resource, + T* resource, DxvkAccess access) - : m_resource(resource), m_access(access) { + : m_ptr(reinterpret_cast(resource) | uintptr_t(access)) { acquire(); } DxvkLifetime(DxvkLifetime&& other) - : m_resource(other.m_resource), m_access(other.m_access) { - other.m_resource = nullptr; - other.m_access = DxvkAccess::None; + : m_ptr(other.m_ptr) { + other.m_ptr = 0u; } DxvkLifetime(const DxvkLifetime& other) - : m_resource(other.m_resource), m_access(other.m_access) { + : m_ptr(other.m_ptr) { acquire(); } DxvkLifetime& operator = (DxvkLifetime&& other) { release(); - m_resource = other.m_resource; - m_access = other.m_access; - - other.m_resource = nullptr; - other.m_access = DxvkAccess::None; + m_ptr = other.m_ptr; + other.m_ptr = 0u; return *this; } @@ -51,8 +50,7 @@ namespace dxvk { other.acquire(); release(); - m_resource = other.m_resource; - m_access = other.m_access; + m_ptr = other.m_ptr; return *this; } @@ -62,17 +60,24 @@ namespace dxvk { private: - DxvkResource* m_resource; - DxvkAccess m_access; + uintptr_t m_ptr = 0u; + + T* ptr() const { + return reinterpret_cast(m_ptr & PointerMask); + } + + DxvkAccess access() const { + return DxvkAccess(m_ptr & AccessMask); + } void acquire() const { - if (m_resource) - m_resource->acquire(m_access); + if (m_ptr) + ptr()->acquire(access()); } void release() const { - if (m_resource) - m_resource->release(m_access); + if (m_ptr) + ptr()->release(access()); } }; @@ -102,6 +107,15 @@ namespace dxvk { m_resources.emplace_back(rc, Access); } + /** + * \brief Adds a resource allocation to track + * \param [in] rc The allocation to track + */ + template + void trackResource(DxvkResourceAllocation* rc) { + m_allocations.emplace_back(rc, Access); + } + /** * \brief Releases resources * @@ -119,7 +133,8 @@ namespace dxvk { private: - std::vector m_resources; + std::vector> m_resources; + std::vector> m_allocations; };