mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
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.
127 lines
3.5 KiB
C++
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();
|
|
}
|
|
|
|
} |