1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00
OpenDX/src/dxvk/dxvk_buffer.cpp
Philip Rebohle f762811af0
[dxvk] Use multiple free lists for physical buffer slices
Reduces lock contention and slightly improves performance in games
that rely heavily on the buffer renaming mechanism if the lock
protecting the original free list was contested.
2018-03-19 14:53:59 +01:00

127 lines
3.5 KiB
C++

#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<std::mutex> freeLock(m_freeMutex);
// If no slices are available, swap the two free lists.
if (m_freeSlices.size() == 0) {
std::unique_lock<std::mutex> 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<DxvkPhysicalBuffer> buffer
= this->allocPhysicalBuffer(m_physSliceCount);
for (uint32_t i = 0; i < m_physSliceCount; i++) {
m_freeSlices.push_back(buffer->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<std::mutex> swapLock(m_swapMutex);
m_nextSlices.push_back(slice);
}
Rc<DxvkPhysicalBuffer> 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<vk::DeviceFn>& vkd,
const Rc<DxvkBuffer>& 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<DxvkPhysicalBufferView> DxvkBufferView::createView() {
return new DxvkPhysicalBufferView(
m_vkd, m_buffer->slice(), m_info);
}
DxvkBufferTracker:: DxvkBufferTracker() { }
DxvkBufferTracker::~DxvkBufferTracker() { }
void DxvkBufferTracker::freeBufferSlice(
const Rc<DxvkBuffer>& 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();
}
}