diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 52c5eb23..948c6004 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -31,16 +31,22 @@ namespace dxvk { DxvkPhysicalBufferSlice DxvkBuffer::allocPhysicalSlice() { - std::unique_lock lock(m_mutex); + std::unique_lock freeLock(m_freeMutex); - // If necessary, create a new buffer - // that we'll allocate slices from. - if (m_slices.size() == 0) { + // If no slices are available, swap the two free lists. + if (m_freeSlices.size() == 0) { + std::unique_lock swapLock(m_swapMutex); + std::swap(m_freeSlices, m_nextSlices); + } + + // If there are still no slices available, create a new + // physical buffer and add all slices to the free list. + if (m_freeSlices.size() == 0) { const Rc buffer = this->allocPhysicalBuffer(m_physSliceCount); for (uint32_t i = 0; i < m_physSliceCount; i++) { - m_slices.push_back(buffer->slice( + m_freeSlices.push_back(buffer->slice( m_physSliceStride * i, m_physSliceLength)); } @@ -49,15 +55,16 @@ namespace dxvk { } // Take the first slice from the queue - DxvkPhysicalBufferSlice result = std::move(m_slices.back()); - m_slices.pop_back(); + DxvkPhysicalBufferSlice result = std::move(m_freeSlices.back()); + m_freeSlices.pop_back(); return result; } void DxvkBuffer::freePhysicalSlice(const DxvkPhysicalBufferSlice& slice) { - std::unique_lock lock(m_mutex); - m_slices.push_back(slice); + // Add slice to a separate free list to reduce lock contention. + std::unique_lock swapLock(m_swapMutex); + m_nextSlices.push_back(slice); } diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index d233667f..50631448 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -140,8 +140,11 @@ namespace dxvk { DxvkPhysicalBufferSlice m_physSlice; uint32_t m_revision = 0; - std::mutex m_mutex; - std::vector m_slices; + std::mutex m_freeMutex; + std::mutex m_swapMutex; + + std::vector m_freeSlices; + std::vector m_nextSlices; VkDeviceSize m_physSliceLength = 0; VkDeviceSize m_physSliceStride = 0;