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

[dxvk] Implement sparse buffer creation

This commit is contained in:
Philip Rebohle 2022-08-20 14:53:41 +02:00
parent bc3affc264
commit f7c255de2a
2 changed files with 88 additions and 28 deletions

View File

@ -16,33 +16,49 @@ namespace dxvk {
m_memAlloc (&memAlloc),
m_memFlags (memFlags),
m_shaderStages (util::shaderStages(createInfo.stages)) {
// Align slices so that we don't violate any alignment
// requirements imposed by the Vulkan device/driver
VkDeviceSize sliceAlignment = computeSliceAlignment();
m_physSliceLength = createInfo.size;
m_physSliceStride = align(createInfo.size, sliceAlignment);
m_physSliceCount = std::max<VkDeviceSize>(1, 256 / m_physSliceStride);
if (!(m_info.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
// Align slices so that we don't violate any alignment
// requirements imposed by the Vulkan device/driver
VkDeviceSize sliceAlignment = computeSliceAlignment();
m_physSliceLength = createInfo.size;
m_physSliceStride = align(createInfo.size, sliceAlignment);
m_physSliceCount = std::max<VkDeviceSize>(1, 256 / m_physSliceStride);
// Limit size of multi-slice buffers to reduce fragmentation
constexpr VkDeviceSize MaxBufferSize = 256 << 10;
// Limit size of multi-slice buffers to reduce fragmentation
constexpr VkDeviceSize MaxBufferSize = 256 << 10;
m_physSliceMaxCount = MaxBufferSize >= m_physSliceStride
? MaxBufferSize / m_physSliceStride
: 1;
m_physSliceMaxCount = MaxBufferSize >= m_physSliceStride
? MaxBufferSize / m_physSliceStride
: 1;
// Allocate the initial set of buffer slices. Only clear
// buffer memory if there is more than one slice, since
// we expect the client api to initialize the first slice.
m_buffer = allocBuffer(m_physSliceCount, m_physSliceCount > 1);
// Allocate the initial set of buffer slices. Only clear
// buffer memory if there is more than one slice, since
// we expect the client api to initialize the first slice.
m_buffer = allocBuffer(m_physSliceCount, m_physSliceCount > 1);
DxvkBufferSliceHandle slice;
slice.handle = m_buffer.buffer;
slice.offset = 0;
slice.length = m_physSliceLength;
slice.mapPtr = m_buffer.memory.mapPtr(0);
m_physSlice.handle = m_buffer.buffer;
m_physSlice.offset = 0;
m_physSlice.length = m_physSliceLength;
m_physSlice.mapPtr = m_buffer.memory.mapPtr(0);
m_physSlice = slice;
m_lazyAlloc = m_physSliceCount > 1;
m_lazyAlloc = m_physSliceCount > 1;
} else {
m_physSliceLength = createInfo.size;
m_physSliceStride = createInfo.size;
m_physSliceCount = 1;
m_physSliceMaxCount = 1;
m_buffer = createSparseBuffer();
m_physSlice.handle = m_buffer.buffer;
m_physSlice.offset = 0;
m_physSlice.length = createInfo.size;
m_physSlice.mapPtr = nullptr;
m_lazyAlloc = false;
m_sparsePageTable = DxvkSparsePageTable(device, this);
}
}
@ -59,17 +75,19 @@ namespace dxvk {
auto vkd = m_device->vkd();
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
info.size = m_physSliceStride * sliceCount;
info.usage = m_info.usage;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.flags = m_info.flags;
info.size = m_physSliceStride * sliceCount;
info.usage = m_info.usage;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
DxvkBufferHandle handle;
if (vkd->vkCreateBuffer(vkd->device(), &info, nullptr, &handle.buffer)) {
throw DxvkError(str::format(
"DxvkBuffer: Failed to create buffer:"
"\n size: ", info.size,
"\n usage: ", info.usage));
"\n flags: ", std::hex, info.flags,
"\n size: ", std::dec, info.size,
"\n usage: ", std::hex, info.usage));
}
// Query memory requirements and whether to use a dedicated allocation
@ -122,6 +140,30 @@ namespace dxvk {
}
DxvkBufferHandle DxvkBuffer::createSparseBuffer() const {
auto vkd = m_device->vkd();
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
info.flags = m_info.flags;
info.size = m_info.size;
info.usage = m_info.usage;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
DxvkBufferHandle handle = { };
if (vkd->vkCreateBuffer(vkd->device(),
&info, nullptr, &handle.buffer) != VK_SUCCESS) {
throw DxvkError(str::format(
"DxvkBuffer: Failed to create buffer:"
"\n flags: ", std::hex, info.flags,
"\n size: ", std::dec, info.size,
"\n usage: ", std::hex, info.usage));
}
return handle;
}
VkDeviceSize DxvkBuffer::computeSliceAlignment() const {
const auto& devInfo = m_device->properties();

View File

@ -8,6 +8,7 @@
#include "dxvk_hash.h"
#include "dxvk_memory.h"
#include "dxvk_resource.h"
#include "dxvk_sparse.h"
namespace dxvk {
@ -18,6 +19,9 @@ namespace dxvk {
* passed to \ref DxvkDevice::createBuffer
*/
struct DxvkBufferCreateInfo {
/// Buffer create flags
VkBufferCreateFlags flags = 0;
/// Size of the buffer, in bytes
VkDeviceSize size;
@ -289,7 +293,17 @@ namespace dxvk {
std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
m_nextSlices.push_back(slice);
}
/**
* \brief Queries sparse page table
* \returns Page table, or \c nullptr for a non-sparse resource
*/
DxvkSparsePageTable* getSparsePageTable() {
return m_info.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT
? &m_sparsePageTable
: nullptr;
}
private:
DxvkDevice* m_device;
@ -302,6 +316,8 @@ namespace dxvk {
DxvkBufferSliceHandle m_physSlice;
uint32_t m_vertexStride = 0;
DxvkSparsePageTable m_sparsePageTable;
alignas(CACHE_LINE_SIZE)
sync::Spinlock m_freeMutex;
@ -331,6 +347,8 @@ namespace dxvk {
VkDeviceSize sliceCount,
bool clear) const;
DxvkBufferHandle createSparseBuffer() const;
VkDeviceSize computeSliceAlignment() const;
};