#include "dxvk_buffer.h" #include "dxvk_device.h" namespace dxvk { DxvkBuffer::DxvkBuffer( DxvkDevice* device, const DxvkBufferCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) : m_device (device), m_info (createInfo), m_memFlags (memoryType) { // Align physical buffer slices to 256 bytes, which guarantees // that we don't violate any Vulkan alignment requirements m_physSliceLength = createInfo.size; m_physSliceStride = align(createInfo.size, 256); // Allocate a single buffer slice m_physSlice = this->allocPhysicalBuffer(1) ->slice(0, m_physSliceStride); } DxvkPhysicalBufferSlice DxvkBuffer::rename(const DxvkPhysicalBufferSlice& slice) { DxvkPhysicalBufferSlice prevSlice = std::move(m_physSlice); m_physSlice = slice; m_revision += 1; return prevSlice; } DxvkPhysicalBufferSlice DxvkBuffer::allocPhysicalSlice() { std::unique_lock freeLock(m_freeMutex); // 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) { std::unique_lock swapLock(m_swapMutex); m_physBuffer = this->allocPhysicalBuffer(m_physSliceCount); for (uint32_t i = 0; i < m_physSliceCount; i++) { m_freeSlices.push_back(m_physBuffer->slice( m_physSliceStride * i, m_physSliceLength)); } m_physSliceCount *= 2; } // Take the first slice from the queue DxvkPhysicalBufferSlice result = std::move(m_freeSlices.back()); m_freeSlices.pop_back(); return result; } void DxvkBuffer::freePhysicalSlice(const DxvkPhysicalBufferSlice& slice) { // Add slice to a separate free list to reduce lock contention. std::unique_lock swapLock(m_swapMutex); // Discard slices allocated from other physical buffers. // This may make descriptor set binding more efficient. if (m_physBuffer->handle() == slice.handle()) m_nextSlices.push_back(slice); } Rc DxvkBuffer::allocPhysicalBuffer(VkDeviceSize sliceCount) const { DxvkBufferCreateInfo createInfo = m_info; createInfo.size = sliceCount * m_physSliceStride; return m_device->allocPhysicalBuffer(createInfo, m_memFlags); } DxvkBufferView::DxvkBufferView( const Rc& vkd, 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) { } DxvkBufferView::~DxvkBufferView() { } void DxvkBufferView::updateView() { if (m_revision != m_buffer->m_revision) { m_physView = this->createView(); m_revision = m_buffer->m_revision; } } Rc DxvkBufferView::createView() { return new DxvkPhysicalBufferView( m_vkd, m_buffer->slice(), m_info); } DxvkBufferTracker:: DxvkBufferTracker() { } DxvkBufferTracker::~DxvkBufferTracker() { } void DxvkBufferTracker::freeBufferSlice( const Rc& buffer, const DxvkPhysicalBufferSlice& slice) { m_entries.push_back({ buffer, slice }); } void DxvkBufferTracker::reset() { for (const auto& e : m_entries) e.buffer->freePhysicalSlice(e.slice); m_entries.clear(); } }