You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
4.1 KiB
187 lines
4.1 KiB
#include <vk/Buffer.h>
|
|
#include <vk/Context.h>
|
|
|
|
#include <core/Logger.h>
|
|
|
|
#include <stdexcept>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
|
|
namespace vk {
|
|
|
|
|
|
Buffer::Buffer() noexcept {
|
|
}
|
|
|
|
Buffer::Buffer(
|
|
Context& context,
|
|
VkDeviceSize size,
|
|
VkBufferUsageFlags usage
|
|
)
|
|
: m_context(&context)
|
|
{
|
|
assert(*m_context);
|
|
|
|
VkBufferCreateInfo create_info {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = size,
|
|
.usage = usage,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
};
|
|
if(vkCreateBuffer(
|
|
m_context->device(),
|
|
&create_info,
|
|
nullptr,
|
|
&m_buffer
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create buffer");
|
|
}
|
|
|
|
Buffer::Buffer(
|
|
Context& context,
|
|
VkDeviceSize size,
|
|
VkBufferUsageFlags usage,
|
|
VkMemoryPropertyFlags memory_properties
|
|
)
|
|
: Buffer(context, size, usage)
|
|
{
|
|
allocate_and_bind_memory(memory_properties);
|
|
}
|
|
|
|
Buffer::Buffer(Buffer&& other) noexcept
|
|
: m_context(other.m_context)
|
|
, m_buffer(other.m_buffer)
|
|
, m_memory(std::move(other.m_memory))
|
|
{
|
|
other.m_context = nullptr;
|
|
other.m_buffer = VK_NULL_HANDLE;
|
|
}
|
|
|
|
Buffer::~Buffer() noexcept {
|
|
if(is_valid()) {
|
|
logger.warning() << "Buffer deleted before being destroyed";
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
Buffer& Buffer::operator=(Buffer&& other) noexcept {
|
|
if(&other != this) {
|
|
using std::swap;
|
|
swap(m_context, other.m_context);
|
|
swap(m_buffer, other.m_buffer);
|
|
swap(m_memory, other.m_memory);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
VkMemoryRequirements Buffer::memory_requirements() const noexcept {
|
|
assert(is_valid());
|
|
assert(*m_context);
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
vkGetBufferMemoryRequirements(
|
|
m_context->device(),
|
|
m_buffer,
|
|
&memory_requirements
|
|
);
|
|
|
|
return memory_requirements;
|
|
}
|
|
|
|
|
|
void Buffer::bind_memory(const MemoryBlock& memory_block, VkDeviceSize offset) {
|
|
assert(is_valid());
|
|
assert(*m_context);
|
|
assert(memory_block);
|
|
|
|
// m_memory = std::move(memory_block);
|
|
if(vkBindBufferMemory(
|
|
m_context->device(),
|
|
m_buffer,
|
|
memory_block.device_memory(),
|
|
memory_block.offset() + offset
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to bind buffer memory");
|
|
}
|
|
|
|
void Buffer::bind_memory(MemoryBlock&& memory_block) {
|
|
bind_memory(memory_block);
|
|
m_memory = std::move(memory_block);
|
|
}
|
|
|
|
void Buffer::allocate_and_bind_memory(VkMemoryPropertyFlags memory_properties) {
|
|
assert(is_valid());
|
|
assert(*m_context);
|
|
|
|
const auto memory_requirements = this->memory_requirements();
|
|
m_memory = m_context->allocator().allocate(
|
|
memory_requirements.size,
|
|
memory_requirements.memoryTypeBits,
|
|
memory_properties
|
|
);
|
|
|
|
bind_memory(m_memory);
|
|
}
|
|
|
|
|
|
void Buffer::upload(size_t size, void* src_buffer, uint32_t dst_queue_family) {
|
|
assert(is_valid());
|
|
assert(*m_context);
|
|
|
|
const bool use_staging_buffer =
|
|
(m_memory.memory_type_info(*m_context).propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0;
|
|
|
|
if(use_staging_buffer) {
|
|
auto staging_buffer = Buffer(
|
|
*m_context,
|
|
size,
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
|
);
|
|
|
|
void* dst_buffer = staging_buffer.memory().map(*m_context);
|
|
std::memcpy(dst_buffer, src_buffer, size);
|
|
staging_buffer.memory().unmap(*m_context);
|
|
|
|
m_context->copy_buffer(
|
|
m_buffer,
|
|
staging_buffer,
|
|
dst_queue_family,
|
|
size
|
|
);
|
|
|
|
staging_buffer.destroy();
|
|
}
|
|
else {
|
|
void* dst_buffer = m_memory.map(*m_context);
|
|
std::memcpy(dst_buffer, src_buffer, size);
|
|
m_memory.unmap(*m_context);
|
|
}
|
|
}
|
|
|
|
|
|
void Buffer::destroy() noexcept {
|
|
assert(is_valid());
|
|
assert(*m_context);
|
|
|
|
if(m_memory) {
|
|
m_memory.free();
|
|
m_memory = MemoryBlock();
|
|
}
|
|
|
|
vkDestroyBuffer(
|
|
m_context->device(),
|
|
m_buffer,
|
|
nullptr
|
|
);
|
|
|
|
m_context = nullptr;
|
|
m_buffer = VK_NULL_HANDLE;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|