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, DxvkDevice* device,
const DxvkBufferCreateInfo& createInfo, const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) VkMemoryPropertyFlags memoryType)
: m_device (device), : m_device (device),
m_info (createInfo), m_info (createInfo),
m_memFlags(memoryType), m_memFlags (memoryType) {
m_resource(allocateResource()) { // 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) { Rc<DxvkPhysicalBuffer> DxvkBuffer::allocPhysicalBuffer(VkDeviceSize sliceCount) const {
m_resource = resource; TRACE(this, sliceCount);
} return m_device->allocPhysicalBuffer(m_info, sliceCount, m_memFlags);
DxvkPhysicalBufferSlice DxvkBuffer::allocateResource() {
return m_device->allocBufferResource(m_info, m_memFlags)->slice(0);
} }

View File

@ -49,7 +49,7 @@ namespace dxvk {
* \returns Pointer to mapped memory region * \returns Pointer to mapped memory region
*/ */
void* mapPtr(VkDeviceSize offset) const { 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 * \returns \c true if the buffer is in use
*/ */
bool isInUse() const { bool isInUse() const {
return m_resource.resource()->isInUse(); return m_physSlice.resource()->isInUse();
} }
/** /**
@ -72,27 +72,9 @@ namespace dxvk {
* \returns The resource object * \returns The resource object
*/ */
Rc<DxvkResource> resource() const { 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 * \brief Physical buffer slice
* *
@ -101,7 +83,7 @@ namespace dxvk {
* \returns The backing slice * \returns The backing slice
*/ */
DxvkPhysicalBufferSlice slice() const { DxvkPhysicalBufferSlice slice() const {
return m_resource; return m_physSlice;
} }
/** /**
@ -113,16 +95,48 @@ namespace dxvk {
* \returns The sub slice * \returns The sub slice
*/ */
DxvkPhysicalBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const { 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: private:
DxvkDevice* m_device; DxvkDevice* m_device;
DxvkBufferCreateInfo m_info; DxvkBufferCreateInfo m_info;
VkMemoryPropertyFlags m_memFlags; 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, VkDeviceSize sliceCount,
DxvkMemoryAllocator& memAlloc, DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags) VkMemoryPropertyFlags memFlags)
: m_vkd(vkd), : m_vkd (vkd),
m_sliceLength(createInfo.size), m_sliceCount (sliceCount),
m_sliceStride(align(createInfo.size, 256)) { m_sliceLength (createInfo.size),
m_sliceStride (align(createInfo.size, 256)) {
VkBufferCreateInfo info; VkBufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;

View File

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

View File

@ -541,8 +541,7 @@ namespace dxvk {
void DxvkContext::invalidateBuffer(const Rc<DxvkBuffer>& buffer) { void DxvkContext::invalidateBuffer(const Rc<DxvkBuffer>& buffer) {
// Allocate new backing resource // Allocate new backing resource
buffer->renameResource( buffer->rename(buffer->allocPhysicalSlice());
buffer->allocateResource());
// We also need to update all bindings that the buffer // We also need to update all bindings that the buffer
// may be bound to either directly or through views. // 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, const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
VkMemoryPropertyFlags memoryType) { VkMemoryPropertyFlags memoryType) {
return new DxvkPhysicalBuffer(m_vkd, 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] createInfo Buffer create info
* \param [in] sliceCount Buffer slice count
* \param [in] memoryType Memory property flags * \param [in] memoryType Memory property flags
* \returns The buffer resource object * \returns The buffer resource object
*/ */
Rc<DxvkPhysicalBuffer> allocBufferResource( Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
const DxvkBufferCreateInfo& createInfo, const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
VkMemoryPropertyFlags memoryType); VkMemoryPropertyFlags memoryType);
/** /**