mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +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);
|
std::memcpy(mappedSr.pData, pSrcData, size);
|
||||||
Unmap(pDstResource, 0);
|
Unmap(pDstResource, 0);
|
||||||
} else {
|
} else {
|
||||||
|
DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size);
|
||||||
|
std::memcpy(dataSlice.ptr(), pSrcData, size);
|
||||||
|
|
||||||
EmitCs([
|
EmitCs([
|
||||||
cDataBuffer = Rc<DxvkDataBuffer>(new DxvkDataBuffer(pSrcData, size)),
|
cDataBuffer = std::move(dataSlice),
|
||||||
cBufferSlice = bufferSlice.subSlice(offset, size)
|
cBufferSlice = bufferSlice.subSlice(offset, size)
|
||||||
] (DxvkContext* ctx) {
|
] (DxvkContext* ctx) {
|
||||||
ctx->updateBuffer(
|
ctx->updateBuffer(
|
||||||
cBufferSlice.buffer(),
|
cBufferSlice.buffer(),
|
||||||
cBufferSlice.offset(),
|
cBufferSlice.offset(),
|
||||||
cBufferSlice.length(),
|
cBufferSlice.length(),
|
||||||
cDataBuffer->data());
|
cDataBuffer.ptr());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -620,10 +623,10 @@ namespace dxvk {
|
|||||||
const VkDeviceSize bytesPerLayer = regionExtent.height * bytesPerRow;
|
const VkDeviceSize bytesPerLayer = regionExtent.height * bytesPerRow;
|
||||||
const VkDeviceSize bytesTotal = regionExtent.depth * bytesPerLayer;
|
const VkDeviceSize bytesTotal = regionExtent.depth * bytesPerLayer;
|
||||||
|
|
||||||
Rc<DxvkDataBuffer> imageDataBuffer = new DxvkDataBuffer(bytesTotal);
|
DxvkDataSlice imageDataBuffer = AllocUpdateBufferSlice(bytesTotal);
|
||||||
|
|
||||||
util::packImageData(
|
util::packImageData(
|
||||||
reinterpret_cast<char*>(imageDataBuffer->data()),
|
reinterpret_cast<char*>(imageDataBuffer.ptr()),
|
||||||
reinterpret_cast<const char*>(pSrcData),
|
reinterpret_cast<const char*>(pSrcData),
|
||||||
regionExtent, formatInfo->elementSize,
|
regionExtent, formatInfo->elementSize,
|
||||||
SrcRowPitch, SrcDepthPitch);
|
SrcRowPitch, SrcDepthPitch);
|
||||||
@ -638,7 +641,7 @@ namespace dxvk {
|
|||||||
cSrcBytesPerLayer = bytesPerLayer
|
cSrcBytesPerLayer = bytesPerLayer
|
||||||
] (DxvkContext* ctx) {
|
] (DxvkContext* ctx) {
|
||||||
ctx->updateImage(cDstImage, cDstLayers,
|
ctx->updateImage(cDstImage, cDstLayers,
|
||||||
cDstOffset, cDstExtent, cSrcData->data(),
|
cDstOffset, cDstExtent, cSrcData.ptr(),
|
||||||
cSrcBytesPerRow, cSrcBytesPerLayer);
|
cSrcBytesPerRow, cSrcBytesPerLayer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2113,4 +2116,27 @@ namespace dxvk {
|
|||||||
return m_device->createSampler(info);
|
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<DxvkDevice> m_device;
|
||||||
Rc<DxvkCsChunk> m_csChunk;
|
Rc<DxvkCsChunk> m_csChunk;
|
||||||
Rc<DxvkSampler> m_defaultSampler;
|
Rc<DxvkSampler> m_defaultSampler;
|
||||||
|
Rc<DxvkDataBuffer> m_updateBuffer;
|
||||||
|
|
||||||
Com<D3D11BlendState> m_defaultBlendState;
|
Com<D3D11BlendState> m_defaultBlendState;
|
||||||
Com<D3D11DepthStencilState> m_defaultDepthStencilState;
|
Com<D3D11DepthStencilState> m_defaultDepthStencilState;
|
||||||
@ -565,6 +566,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
Rc<DxvkSampler> CreateDefaultSampler();
|
Rc<DxvkSampler> CreateDefaultSampler();
|
||||||
|
|
||||||
|
DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
|
||||||
|
|
||||||
template<typename Cmd>
|
template<typename Cmd>
|
||||||
void EmitCs(Cmd&& command) {
|
void EmitCs(Cmd&& command) {
|
||||||
if (!m_csChunk->push(command)) {
|
if (!m_csChunk->push(command)) {
|
||||||
@ -584,6 +587,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
virtual void EmitCsChunk(Rc<DxvkCsChunk>&& chunk) = 0;
|
virtual void EmitCsChunk(Rc<DxvkCsChunk>&& chunk) = 0;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,18 @@ namespace dxvk {
|
|||||||
DxvkDataBuffer:: DxvkDataBuffer() { }
|
DxvkDataBuffer:: DxvkDataBuffer() { }
|
||||||
DxvkDataBuffer::~DxvkDataBuffer() { }
|
DxvkDataBuffer::~DxvkDataBuffer() { }
|
||||||
|
|
||||||
DxvkDataBuffer::DxvkDataBuffer(
|
DxvkDataBuffer::DxvkDataBuffer(size_t size) {
|
||||||
size_t size) {
|
|
||||||
m_data.resize(size);
|
m_data.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DxvkDataBuffer::DxvkDataBuffer(
|
|
||||||
const void* data,
|
DxvkDataSlice DxvkDataBuffer::alloc(size_t n) {
|
||||||
size_t size) {
|
const size_t offset = m_offset;
|
||||||
m_data.resize(size);
|
|
||||||
std::memcpy(m_data.data(), data, size);
|
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 {
|
namespace dxvk {
|
||||||
|
|
||||||
|
class DxvkDataSlice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Data buffer
|
* \brief Data buffer
|
||||||
*
|
*
|
||||||
* Stores immutable data. Used for temporary
|
* Provides a fixed-size buffer with a linear memory
|
||||||
* copies of data that can be transferred to
|
* allocator for arbitrary data. Can be used to copy
|
||||||
* or from DXVK resources.
|
* data to or from resources. Note that allocations
|
||||||
|
* will be aligned to a cache line boundary.
|
||||||
*/
|
*/
|
||||||
class DxvkDataBuffer : public RcObject {
|
class DxvkDataBuffer : public RcObject {
|
||||||
|
friend class DxvkDataSlice;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkDataBuffer();
|
DxvkDataBuffer();
|
||||||
DxvkDataBuffer(
|
DxvkDataBuffer(size_t size);
|
||||||
size_t size);
|
|
||||||
DxvkDataBuffer(
|
|
||||||
const void* data,
|
|
||||||
size_t size);
|
|
||||||
~DxvkDataBuffer();
|
~DxvkDataBuffer();
|
||||||
|
|
||||||
size_t size() const {
|
/**
|
||||||
return m_data.size();
|
* \brief Allocates a slice
|
||||||
}
|
*
|
||||||
|
* If the desired slice length is larger than the
|
||||||
void* data() {
|
* number of bytes left in the buffer, this will
|
||||||
return m_data.data();
|
* 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
|
||||||
const void* data() const {
|
*/
|
||||||
return m_data.data();
|
DxvkDataSlice alloc(size_t n);
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::vector<char> m_data;
|
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 {
|
namespace dxvk {
|
||||||
|
|
||||||
|
constexpr size_t CACHE_LINE_SIZE = 64;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T clamp(T n, T lo, T hi) {
|
T clamp(T n, T lo, T hi) {
|
||||||
if (n < lo) return lo;
|
if (n < lo) return lo;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user