mirror of https://github.com/doitsujin/dxvk
94 lines
2.3 KiB
C++
94 lines
2.3 KiB
C++
#include "dxvk_device.h"
|
|
#include "dxvk_staging.h"
|
|
|
|
namespace dxvk {
|
|
|
|
DxvkStagingBuffer::DxvkStagingBuffer(
|
|
const Rc<DxvkBuffer>& buffer)
|
|
: m_buffer(buffer), m_bufferSize(buffer->info().size){
|
|
|
|
}
|
|
|
|
|
|
DxvkStagingBuffer::~DxvkStagingBuffer() {
|
|
|
|
}
|
|
|
|
|
|
VkDeviceSize DxvkStagingBuffer::size() const {
|
|
return m_bufferSize;
|
|
}
|
|
|
|
|
|
VkDeviceSize DxvkStagingBuffer::freeBytes() const {
|
|
return m_bufferSize >= m_bufferOffset
|
|
? m_bufferSize - m_bufferOffset
|
|
: VkDeviceSize(0);
|
|
}
|
|
|
|
|
|
bool DxvkStagingBuffer::alloc(
|
|
VkDeviceSize size,
|
|
DxvkStagingBufferSlice& slice) {
|
|
if (m_bufferOffset + size > m_bufferSize)
|
|
return false;
|
|
|
|
auto physicalSlice = m_buffer->subSlice(m_bufferOffset, size);
|
|
slice.buffer = physicalSlice.handle();
|
|
slice.offset = physicalSlice.offset();
|
|
slice.mapPtr = physicalSlice.mapPtr(0);
|
|
|
|
m_bufferOffset = align(m_bufferOffset + size, 64);
|
|
return true;
|
|
}
|
|
|
|
|
|
void DxvkStagingBuffer::reset() {
|
|
m_bufferOffset = 0;
|
|
}
|
|
|
|
|
|
DxvkStagingAlloc::DxvkStagingAlloc(DxvkDevice* device)
|
|
: m_device(device) { }
|
|
|
|
|
|
DxvkStagingAlloc::~DxvkStagingAlloc() {
|
|
this->reset();
|
|
}
|
|
|
|
|
|
DxvkStagingBufferSlice DxvkStagingAlloc::alloc(VkDeviceSize size) {
|
|
Rc<DxvkStagingBuffer> selectedBuffer;
|
|
|
|
// Try a worst-fit allocation strategy on the existing staging
|
|
// buffers first. This should keep the amount of wasted space
|
|
// small, especially if there are large allocations.
|
|
for (const auto& buf : m_stagingBuffers) {
|
|
if (selectedBuffer == nullptr || (buf->freeBytes() > selectedBuffer->freeBytes()))
|
|
selectedBuffer = buf;
|
|
}
|
|
|
|
// If we have no suitable buffer, allocate one from the device
|
|
// that is *at least* as large as the amount of data we need
|
|
// to upload. Usually it will be bigger.
|
|
DxvkStagingBufferSlice slice;
|
|
|
|
if ((selectedBuffer == nullptr) || (!selectedBuffer->alloc(size, slice))) {
|
|
selectedBuffer = m_device->allocStagingBuffer(size);
|
|
selectedBuffer->alloc(size, slice);
|
|
m_stagingBuffers.push_back(selectedBuffer);
|
|
}
|
|
|
|
return slice;
|
|
}
|
|
|
|
|
|
void DxvkStagingAlloc::reset() {
|
|
for (const auto& buf : m_stagingBuffers)
|
|
m_device->recycleStagingBuffer(buf);
|
|
|
|
m_stagingBuffers.resize(0);
|
|
}
|
|
|
|
}
|