1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-18 02:52:10 +01:00

[dxvk] Optimized buffer renaming

Helps applications which frequently update buffers
through either Map()/Unmap() or UpdateSubresource.
This commit is contained in:
Philip Rebohle 2018-01-19 00:20:05 +01:00
parent ec0ff35b96
commit a0acbeec72
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 99 additions and 44 deletions

View File

@ -7,21 +7,50 @@ namespace dxvk {
DxvkDevice* device,
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType)
: m_device (device),
m_info (createInfo),
m_memFlags(memoryType),
m_resource(allocateResource()) {
: m_device (device),
m_info (createInfo),
m_memFlags (memoryType) {
// Initialize a single backing bufer with one slice
m_physBuffers[0] = this->allocPhysicalBuffer(1);
m_physSlice = this->allocPhysicalSlice();
}
void DxvkBuffer::rename(
const DxvkPhysicalBufferSlice& slice) {
m_physSlice = slice;
}
DxvkPhysicalBufferSlice DxvkBuffer::allocPhysicalSlice() {
if (m_physSliceId >= m_physBuffers[m_physBufferId]->sliceCount()) {
m_physBufferId = (m_physBufferId + 1) % m_physBuffers.size();
m_physSliceId = 0;
if ((m_physBuffers[m_physBufferId] == nullptr)
|| (m_physBuffers[m_physBufferId]->sliceCount() < m_physSliceCount)) {
// Make sure that all buffers have the same size. If we don't do this,
// one of the physical buffers may grow indefinitely while the others
// remain small, depending on the usage pattern of the application.
m_physBuffers[m_physBufferId] = this->allocPhysicalBuffer(m_physSliceCount);
} else if (m_physBuffers[m_physBufferId]->isInUse()) {
// Allocate a new physical buffer if the current one is still in use.
// This also indicates that the buffer gets updated frequently, so we
// will double the size of the physical buffers to accomodate for it.
if (m_physBufferId == 0)
m_physSliceCount *= 2;
m_physBuffers[m_physBufferId] = this->allocPhysicalBuffer(m_physSliceCount);
}
}
return m_physBuffers[m_physBufferId]->slice(m_physSliceId++);
}
void DxvkBuffer::renameResource(const DxvkPhysicalBufferSlice& resource) {
m_resource = resource;
}
DxvkPhysicalBufferSlice DxvkBuffer::allocateResource() {
return m_device->allocBufferResource(m_info, m_memFlags)->slice(0);
Rc<DxvkPhysicalBuffer> DxvkBuffer::allocPhysicalBuffer(VkDeviceSize sliceCount) const {
TRACE(this, sliceCount);
return m_device->allocPhysicalBuffer(m_info, sliceCount, m_memFlags);
}

View File

@ -49,7 +49,7 @@ namespace dxvk {
* \returns Pointer to mapped memory region
*/
void* mapPtr(VkDeviceSize offset) const {
return m_resource.mapPtr(offset);
return m_physSlice.mapPtr(offset);
}
/**
@ -62,7 +62,7 @@ namespace dxvk {
* \returns \c true if the buffer is in use
*/
bool isInUse() const {
return m_resource.resource()->isInUse();
return m_physSlice.resource()->isInUse();
}
/**
@ -72,27 +72,9 @@ namespace dxvk {
* \returns The resource object
*/
Rc<DxvkResource> resource() const {
return m_resource.resource();
return m_physSlice.resource();
}
/**
* \brief Replaces backing resource
*
* Replaces the underlying buffer and implicitly marks
* any buffer views using this resource as dirty. Do
* not call this directly as this is called implicitly
* by the context's \c invalidateBuffer method.
* \param [in] resource The new backing resource
*/
void renameResource(
const DxvkPhysicalBufferSlice& resource);
/**
* \brief Allocates new backing resource
* \returns The new buffer
*/
DxvkPhysicalBufferSlice allocateResource();
/**
* \brief Physical buffer slice
*
@ -101,7 +83,7 @@ namespace dxvk {
* \returns The backing slice
*/
DxvkPhysicalBufferSlice slice() const {
return m_resource;
return m_physSlice;
}
/**
@ -113,16 +95,48 @@ namespace dxvk {
* \returns The sub slice
*/
DxvkPhysicalBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
return m_resource.subSlice(offset, length);
return m_physSlice.subSlice(offset, length);
}
/**
* \brief Replaces backing resource
*
* Replaces the underlying buffer and implicitly marks
* any buffer views using this resource as dirty. Do
* not call this directly as this is called implicitly
* by the context's \c invalidateBuffer method.
* \param [in] slice The new backing resource
*/
void rename(
const DxvkPhysicalBufferSlice& slice);
/**
* \brief Allocates new physical resource
*
* This method must not be called from multiple threads
* simultaneously, but it can be called in parallel with
* \ref rename and other methods of this class.
* \returns The new backing buffer slice
*/
DxvkPhysicalBufferSlice allocPhysicalSlice();
private:
DxvkDevice* m_device;
DxvkBufferCreateInfo m_info;
VkMemoryPropertyFlags m_memFlags;
DxvkPhysicalBufferSlice m_physSlice;
DxvkPhysicalBufferSlice m_resource;
// TODO maybe align this to a cache line in order
// to avoid false sharing once CSMT is implemented
VkDeviceSize m_physBufferId = 0;
VkDeviceSize m_physSliceId = 0;
VkDeviceSize m_physSliceCount = 1;
std::array<Rc<DxvkPhysicalBuffer>, 2> m_physBuffers;
Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
VkDeviceSize sliceCount) const;
};

View File

@ -8,9 +8,10 @@ namespace dxvk {
VkDeviceSize sliceCount,
DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags)
: m_vkd(vkd),
m_sliceLength(createInfo.size),
m_sliceStride(align(createInfo.size, 256)) {
: m_vkd (vkd),
m_sliceCount (sliceCount),
m_sliceLength (createInfo.size),
m_sliceStride (align(createInfo.size, 256)) {
VkBufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;

View File

@ -78,6 +78,14 @@ namespace dxvk {
return m_handle;
}
/**
* \brief Number of slices
* \returns Total slice count
*/
VkDeviceSize sliceCount() const {
return m_sliceCount;
}
/**
* \brief Map pointer
*
@ -108,6 +116,7 @@ namespace dxvk {
DxvkMemory m_memory;
VkBuffer m_handle;
VkDeviceSize m_sliceCount;
VkDeviceSize m_sliceLength;
VkDeviceSize m_sliceStride;

View File

@ -541,8 +541,7 @@ namespace dxvk {
void DxvkContext::invalidateBuffer(const Rc<DxvkBuffer>& buffer) {
// Allocate new backing resource
buffer->renameResource(
buffer->allocateResource());
buffer->rename(buffer->allocPhysicalSlice());
// We also need to update all bindings that the buffer
// may be bound to either directly or through views.

View File

@ -37,11 +37,12 @@ namespace dxvk {
}
Rc<DxvkPhysicalBuffer> DxvkDevice::allocBufferResource(
Rc<DxvkPhysicalBuffer> DxvkDevice::allocPhysicalBuffer(
const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
VkMemoryPropertyFlags memoryType) {
return new DxvkPhysicalBuffer(m_vkd,
createInfo, 1, *m_memory, memoryType);
createInfo, sliceCount, *m_memory, memoryType);
}

View File

@ -101,14 +101,16 @@ namespace dxvk {
}
/**
* \brief Allocates buffer resource
* \brief Allocates a physical buffer
*
* \param [in] createInfo Buffer create info
* \param [in] sliceCount Buffer slice count
* \param [in] memoryType Memory property flags
* \returns The buffer resource object
*/
Rc<DxvkPhysicalBuffer> allocBufferResource(
Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
VkMemoryPropertyFlags memoryType);
/**