mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 20:52:10 +01:00
[d3d11] Sub-allocate from larger update buffers for UpdateSubresources
Reduces the allocation overhead when applications frequently call UpdateSubresources to update small buffers and textures.
This commit is contained in:
parent
226afa96c9
commit
e198bd2d55
@ -569,15 +569,18 @@ namespace dxvk {
|
||||
std::memcpy(mappedSr.pData, pSrcData, size);
|
||||
Unmap(pDstResource, 0);
|
||||
} else {
|
||||
DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size);
|
||||
std::memcpy(dataSlice.ptr(), pSrcData, size);
|
||||
|
||||
EmitCs([
|
||||
cDataBuffer = Rc<DxvkDataBuffer>(new DxvkDataBuffer(pSrcData, size)),
|
||||
cDataBuffer = std::move(dataSlice),
|
||||
cBufferSlice = bufferSlice.subSlice(offset, size)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->updateBuffer(
|
||||
cBufferSlice.buffer(),
|
||||
cBufferSlice.offset(),
|
||||
cBufferSlice.length(),
|
||||
cDataBuffer->data());
|
||||
cDataBuffer.ptr());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -620,10 +623,10 @@ namespace dxvk {
|
||||
const VkDeviceSize bytesPerLayer = regionExtent.height * bytesPerRow;
|
||||
const VkDeviceSize bytesTotal = regionExtent.depth * bytesPerLayer;
|
||||
|
||||
Rc<DxvkDataBuffer> imageDataBuffer = new DxvkDataBuffer(bytesTotal);
|
||||
DxvkDataSlice imageDataBuffer = AllocUpdateBufferSlice(bytesTotal);
|
||||
|
||||
util::packImageData(
|
||||
reinterpret_cast<char*>(imageDataBuffer->data()),
|
||||
reinterpret_cast<char*>(imageDataBuffer.ptr()),
|
||||
reinterpret_cast<const char*>(pSrcData),
|
||||
regionExtent, formatInfo->elementSize,
|
||||
SrcRowPitch, SrcDepthPitch);
|
||||
@ -638,7 +641,7 @@ namespace dxvk {
|
||||
cSrcBytesPerLayer = bytesPerLayer
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->updateImage(cDstImage, cDstLayers,
|
||||
cDstOffset, cDstExtent, cSrcData->data(),
|
||||
cDstOffset, cDstExtent, cSrcData.ptr(),
|
||||
cSrcBytesPerRow, cSrcBytesPerLayer);
|
||||
});
|
||||
}
|
||||
@ -2113,4 +2116,27 @@ namespace dxvk {
|
||||
return m_device->createSampler(info);
|
||||
}
|
||||
|
||||
|
||||
DxvkDataSlice D3D11DeviceContext::AllocUpdateBufferSlice(size_t Size) {
|
||||
constexpr size_t UpdateBufferSize = 4 * 1024 * 1024;
|
||||
|
||||
if (Size >= UpdateBufferSize) {
|
||||
Rc<DxvkDataBuffer> buffer = new DxvkDataBuffer(Size);
|
||||
return buffer->alloc(Size);
|
||||
} else {
|
||||
if (m_updateBuffer == nullptr)
|
||||
m_updateBuffer = new DxvkDataBuffer(Size);
|
||||
|
||||
DxvkDataSlice slice = m_updateBuffer->alloc(Size);
|
||||
|
||||
if (slice.ptr() == nullptr) {
|
||||
m_updateBuffer = new DxvkDataBuffer(Size);
|
||||
slice = m_updateBuffer->alloc(Size);
|
||||
}
|
||||
|
||||
return slice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -520,6 +520,7 @@ namespace dxvk {
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkCsChunk> m_csChunk;
|
||||
Rc<DxvkSampler> m_defaultSampler;
|
||||
Rc<DxvkDataBuffer> m_updateBuffer;
|
||||
|
||||
Com<D3D11BlendState> m_defaultBlendState;
|
||||
Com<D3D11DepthStencilState> m_defaultDepthStencilState;
|
||||
@ -565,6 +566,8 @@ namespace dxvk {
|
||||
|
||||
Rc<DxvkSampler> CreateDefaultSampler();
|
||||
|
||||
DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
|
||||
|
||||
template<typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
if (!m_csChunk->push(command)) {
|
||||
@ -584,6 +587,7 @@ namespace dxvk {
|
||||
|
||||
virtual void EmitCsChunk(Rc<DxvkCsChunk>&& chunk) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -7,16 +7,18 @@ namespace dxvk {
|
||||
DxvkDataBuffer:: DxvkDataBuffer() { }
|
||||
DxvkDataBuffer::~DxvkDataBuffer() { }
|
||||
|
||||
DxvkDataBuffer::DxvkDataBuffer(
|
||||
size_t size) {
|
||||
DxvkDataBuffer::DxvkDataBuffer(size_t size) {
|
||||
m_data.resize(size);
|
||||
}
|
||||
|
||||
DxvkDataBuffer::DxvkDataBuffer(
|
||||
const void* data,
|
||||
size_t size) {
|
||||
m_data.resize(size);
|
||||
std::memcpy(m_data.data(), data, size);
|
||||
|
||||
DxvkDataSlice DxvkDataBuffer::alloc(size_t n) {
|
||||
const size_t offset = m_offset;
|
||||
|
||||
if (offset + n <= m_data.size()) {
|
||||
m_offset += align(n, CACHE_LINE_SIZE);
|
||||
return DxvkDataSlice(this, offset, n);
|
||||
} return DxvkDataSlice();
|
||||
}
|
||||
|
||||
}
|
@ -4,41 +4,78 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkDataSlice;
|
||||
|
||||
/**
|
||||
* \brief Data buffer
|
||||
*
|
||||
* Stores immutable data. Used for temporary
|
||||
* copies of data that can be transferred to
|
||||
* or from DXVK resources.
|
||||
* Provides a fixed-size buffer with a linear memory
|
||||
* allocator for arbitrary data. Can be used to copy
|
||||
* data to or from resources. Note that allocations
|
||||
* will be aligned to a cache line boundary.
|
||||
*/
|
||||
class DxvkDataBuffer : public RcObject {
|
||||
|
||||
friend class DxvkDataSlice;
|
||||
public:
|
||||
|
||||
DxvkDataBuffer();
|
||||
DxvkDataBuffer(
|
||||
size_t size);
|
||||
DxvkDataBuffer(
|
||||
const void* data,
|
||||
size_t size);
|
||||
DxvkDataBuffer(size_t size);
|
||||
~DxvkDataBuffer();
|
||||
|
||||
size_t size() const {
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
void* data() {
|
||||
return m_data.data();
|
||||
}
|
||||
|
||||
const void* data() const {
|
||||
return m_data.data();
|
||||
}
|
||||
/**
|
||||
* \brief Allocates a slice
|
||||
*
|
||||
* If the desired slice length is larger than the
|
||||
* number of bytes left in the buffer, this will
|
||||
* fail and the returned slice points to \c nullptr.
|
||||
* \param [in] n Number of bytes to allocate
|
||||
* \returns The slice, or an empty slice on failure
|
||||
*/
|
||||
DxvkDataSlice alloc(size_t n);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<char> m_data;
|
||||
size_t m_offset = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Data buffer slice
|
||||
*
|
||||
* A slice of a \ref DxvkDataBuffer which stores
|
||||
* a strong reference to the backing buffer object.
|
||||
*/
|
||||
class DxvkDataSlice {
|
||||
|
||||
public:
|
||||
|
||||
DxvkDataSlice() { }
|
||||
DxvkDataSlice(
|
||||
const Rc<DxvkDataBuffer>& buffer,
|
||||
size_t offset,
|
||||
size_t length)
|
||||
: m_buffer(buffer),
|
||||
m_offset(offset),
|
||||
m_length(length) { }
|
||||
|
||||
void* ptr() const {
|
||||
return m_buffer != nullptr
|
||||
? m_buffer->m_data.data() + m_offset
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
size_t offset() const { return m_offset; }
|
||||
size_t length() const { return m_length; }
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkDataBuffer> m_buffer;
|
||||
size_t m_offset = 0;
|
||||
size_t m_length = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr size_t CACHE_LINE_SIZE = 64;
|
||||
|
||||
template<typename T>
|
||||
T clamp(T n, T lo, T hi) {
|
||||
if (n < lo) return lo;
|
||||
|
Loading…
x
Reference in New Issue
Block a user