mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-01 07:24:12 +01:00
[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:
parent
9acc4a1a82
commit
a87ae8aba4
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
50
src/dxvk/dxvk_buffer_res.cpp
Normal file
50
src/dxvk/dxvk_buffer_res.cpp
Normal 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
194
src/dxvk/dxvk_buffer_res.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user