[dxvk] Added DxvkPhysicalBuffer to back virtual buffers

This is the first step to optimizing buffer updates for applications
that frequently invalidate buffers. The goal is to reduce the number
of buffer allocations per frame and reduce the cost of invalidation.
This commit is contained in:
Philip Rebohle 2018-01-18 15:52:57 +01:00
parent 9acc4a1a82
commit a87ae8aba4
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 255 additions and 122 deletions

View File

@ -3,44 +3,6 @@
namespace dxvk {
DxvkBufferResource::DxvkBufferResource(
const Rc<vk::DeviceFn>& vkd,
const DxvkBufferCreateInfo& createInfo,
DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags)
: m_vkd(vkd) {
VkBufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.size = createInfo.size;
info.usage = createInfo.usage;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.queueFamilyIndexCount = 0;
info.pQueueFamilyIndices = nullptr;
if (m_vkd->vkCreateBuffer(m_vkd->device(),
&info, nullptr, &m_buffer) != VK_SUCCESS)
throw DxvkError("DxvkBuffer::DxvkBuffer: Failed to create buffer");
VkMemoryRequirements memReq;
m_vkd->vkGetBufferMemoryRequirements(
m_vkd->device(), m_buffer, &memReq);
m_memory = memAlloc.alloc(memReq, memFlags);
if (m_vkd->vkBindBufferMemory(m_vkd->device(),
m_buffer, m_memory.memory(), m_memory.offset()) != VK_SUCCESS)
throw DxvkError("DxvkBuffer::DxvkBuffer: Failed to bind device memory");
}
DxvkBufferResource::~DxvkBufferResource() {
if (m_buffer != VK_NULL_HANDLE)
m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer, nullptr);
}
DxvkBuffer::DxvkBuffer(
DxvkDevice* device,
const DxvkBufferCreateInfo& createInfo,
@ -54,12 +16,12 @@ namespace dxvk {
void DxvkBuffer::renameResource(
const Rc<DxvkBufferResource>& resource) {
const Rc<DxvkPhysicalBuffer>& resource) {
m_resource = resource;
}
Rc<DxvkBufferResource> DxvkBuffer::allocateResource() {
Rc<DxvkPhysicalBuffer> DxvkBuffer::allocateResource() {
return m_device->allocBufferResource(m_info, m_memFlags);
}

View File

@ -1,83 +1,9 @@
#pragma once
#include "dxvk_format.h"
#include "dxvk_memory.h"
#include "dxvk_resource.h"
#include "dxvk_buffer_res.h"
namespace dxvk {
/**
* \brief Buffer create info
*
* The properties of a buffer that are
* passed to \ref DxvkDevice::createBuffer
*/
struct DxvkBufferCreateInfo {
/// Size of the buffer, in bytes
VkDeviceSize size;
/// Buffer usage flags
VkBufferUsageFlags usage;
/// Pipeline stages that can access
/// the contents of the buffer.
VkPipelineStageFlags stages;
/// Allowed access patterns
VkAccessFlags access;
};
/**
* \brief Buffer view create info
*
* The properties of a buffer view that
* are to \ref DxvkDevice::createBufferView
*/
struct DxvkBufferViewCreateInfo {
/// Buffer data format, like image data
VkFormat format;
/// Offset of the buffer region to include in the view
VkDeviceSize rangeOffset;
/// Size of the buffer region to include in the view
VkDeviceSize rangeLength;
};
/**
* \brief Physical buffer resource
*/
class DxvkBufferResource : public DxvkResource {
public:
DxvkBufferResource(
const Rc<vk::DeviceFn>& vkd,
const DxvkBufferCreateInfo& createInfo,
DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags);
~DxvkBufferResource();
VkBuffer handle() const {
return m_buffer;
}
void* mapPtr(VkDeviceSize offset) const {
return m_memory.mapPtr(offset);
}
private:
Rc<vk::DeviceFn> m_vkd;
DxvkMemory m_memory;
VkBuffer m_buffer;
};
/**
* \brief Virtual buffer resource
*
@ -167,13 +93,13 @@ namespace dxvk {
* \param [in] resource The new backing resource
*/
void renameResource(
const Rc<DxvkBufferResource>& resource);
const Rc<DxvkPhysicalBuffer>& resource);
/**
* \brief Allocates new backing resource
* \returns The new buffer
*/
Rc<DxvkBufferResource> allocateResource();
Rc<DxvkPhysicalBuffer> allocateResource();
private:
@ -181,7 +107,7 @@ namespace dxvk {
DxvkBufferCreateInfo m_info;
VkMemoryPropertyFlags m_memFlags;
Rc<DxvkBufferResource> m_resource;
Rc<DxvkPhysicalBuffer> m_resource;
};

View File

@ -0,0 +1,50 @@
#include "dxvk_buffer_res.h"
namespace dxvk {
DxvkPhysicalBuffer::DxvkPhysicalBuffer(
const Rc<vk::DeviceFn>& vkd,
const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags)
: m_vkd(vkd),
m_sliceLength(createInfo.size),
m_sliceStride(align(createInfo.size, 256)) {
VkBufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.size = m_sliceStride * sliceCount;
info.usage = createInfo.usage;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.queueFamilyIndexCount = 0;
info.pQueueFamilyIndices = nullptr;
if (m_vkd->vkCreateBuffer(m_vkd->device(),
&info, nullptr, &m_handle) != VK_SUCCESS)
throw DxvkError("DxvkPhysicalBuffer: Failed to create buffer");
VkMemoryRequirements memReq;
m_vkd->vkGetBufferMemoryRequirements(
m_vkd->device(), m_handle, &memReq);
m_memory = memAlloc.alloc(memReq, memFlags);
if (m_vkd->vkBindBufferMemory(m_vkd->device(),
m_handle, m_memory.memory(), m_memory.offset()) != VK_SUCCESS)
throw DxvkError("DxvkPhysicalBuffer: Failed to bind device memory");
}
DxvkPhysicalBuffer::~DxvkPhysicalBuffer() {
if (m_handle != VK_NULL_HANDLE)
m_vkd->vkDestroyBuffer(m_vkd->device(), m_handle, nullptr);
}
DxvkPhysicalBufferSlice DxvkPhysicalBuffer::slice(uint32_t id) {
return DxvkPhysicalBufferSlice(this, id * m_sliceStride, m_sliceLength);
}
}

194
src/dxvk/dxvk_buffer_res.h Normal file
View File

@ -0,0 +1,194 @@
#pragma once
#include "dxvk_format.h"
#include "dxvk_memory.h"
#include "dxvk_resource.h"
namespace dxvk {
/**
* \brief Buffer create info
*
* The properties of a buffer that are
* passed to \ref DxvkDevice::createBuffer
*/
struct DxvkBufferCreateInfo {
/// Size of the buffer, in bytes
VkDeviceSize size;
/// Buffer usage flags
VkBufferUsageFlags usage;
/// Pipeline stages that can access
/// the contents of the buffer.
VkPipelineStageFlags stages;
/// Allowed access patterns
VkAccessFlags access;
};
/**
* \brief Buffer view create info
*
* The properties of a buffer view that
* are to \ref DxvkDevice::createBufferView
*/
struct DxvkBufferViewCreateInfo {
/// Buffer data format, like image data
VkFormat format;
/// Offset of the buffer region to include in the view
VkDeviceSize rangeOffset;
/// Size of the buffer region to include in the view
VkDeviceSize rangeLength;
};
class DxvkPhysicalBuffer;
class DxvkPhysicalBufferSlice;
/**
* \brief Physical buffer
*
* A physical buffer is used as a backing resource for
* a virtual buffer. See \ref DxvkBuffer as for why
* this separation is necessary.
*/
class DxvkPhysicalBuffer : public DxvkResource {
public:
DxvkPhysicalBuffer(
const Rc<vk::DeviceFn>& vkd,
const DxvkBufferCreateInfo& createInfo,
VkDeviceSize sliceCount,
DxvkMemoryAllocator& memAlloc,
VkMemoryPropertyFlags memFlags);
~DxvkPhysicalBuffer();
/**
* \brief Vulkan buffer handle
* \returns Vulkan buffer handle
*/
VkBuffer handle() const {
return m_handle;
}
/**
* \brief Map pointer
*
* Retrieves a pointer into the mapped memory region
* of the buffer, relative to the start of the buffer.
* \param [in] offset Offset into the buffer
* \returns Pointer into the mapped memory region
*/
void* mapPtr(VkDeviceSize offset) const {
return m_memory.mapPtr(offset);
}
/**
* \brief Retrieves a physical buffer slice
*
* Returns the buffer object and the offset of the
* given slice. Slices are always aligned to the
* highest required alignment of the device, so
* that they can be used for any purpose.
* \param [in] id Slice index
* \returns The physical slice
*/
DxvkPhysicalBufferSlice slice(uint32_t id);
private:
Rc<vk::DeviceFn> m_vkd;
DxvkMemory m_memory;
VkBuffer m_handle;
VkDeviceSize m_sliceLength;
VkDeviceSize m_sliceStride;
};
/**
* \brief Physical buffer slice
*
* A slice into a physical buffer, which stores
* the buffer and the offset into the buffer.
*/
class DxvkPhysicalBufferSlice {
public:
DxvkPhysicalBufferSlice() { }
DxvkPhysicalBufferSlice(
const Rc<DxvkPhysicalBuffer>& buffer,
VkDeviceSize offset,
VkDeviceSize length)
: m_buffer(buffer),
m_offset(offset),
m_length(length) { }
/**
* \brief Buffer handle
* \returns Buffer handle
*/
VkBuffer handle() const {
return m_buffer->handle();
}
/**
* \brief Slice offset
*
* Offset of the slice into
* the underlying buffer.
* \returns Slice offset
*/
VkDeviceSize offset() const {
return m_offset;
}
/**
* \brief Slice length
*
* Number of bytes in the slice.
* \returns Slice length, in bytes
*/
VkDeviceSize length() const {
return m_length;
}
/**
* \brief Map pointer
*
* Retrieves a pointer into the mapped memory
* region of the underlying buffer, relative
* to the slice's offset.
* \param [in] offset Offset into the slice
* \returns Pointer to the mapped memory region
*/
void* mapPtr(VkDeviceSize offset) const {
return m_buffer->mapPtr(m_offset + offset);
}
/**
* \brief The buffer resource
* \returns Buffer resource
*/
Rc<DxvkResource> resource() const {
return m_buffer;
}
private:
Rc<DxvkPhysicalBuffer> m_buffer;
VkDeviceSize m_offset;
VkDeviceSize m_length;
};
}

View File

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

View File

@ -107,7 +107,7 @@ namespace dxvk {
* \param [in] memoryType Memory property flags
* \returns The buffer resource object
*/
Rc<DxvkBufferResource> allocBufferResource(
Rc<DxvkPhysicalBuffer> allocBufferResource(
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType);

View File

@ -7,6 +7,7 @@ dxvk_src = files([
'dxvk_adapter.cpp',
'dxvk_barrier.cpp',
'dxvk_buffer.cpp',
'dxvk_buffer_res.cpp',
'dxvk_cmdlist.cpp',
'dxvk_compute.cpp',
'dxvk_context.cpp',