274 lines
10 KiB
C++
274 lines
10 KiB
C++
/* Copyright (c) 2019-2025, Arm Limited and Contributors
|
|
* Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 the "License";
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "builder_base.h"
|
|
#include "common/vk_common.h"
|
|
#include "core/allocated.h"
|
|
|
|
namespace vkb
|
|
{
|
|
namespace core
|
|
{
|
|
template <vkb::BindingType bindingType>
|
|
class Buffer;
|
|
template <vkb::BindingType bindingType>
|
|
using BufferPtr = std::unique_ptr<Buffer<bindingType>>;
|
|
template <vkb::BindingType bindingType>
|
|
class Device;
|
|
|
|
template <vkb::BindingType bindingType>
|
|
struct BufferBuilder
|
|
: public vkb::allocated::BuilderBase<bindingType,
|
|
BufferBuilder<bindingType>,
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferCreateInfo, VkBufferCreateInfo>::type>
|
|
{
|
|
public:
|
|
using BufferCreateFlagsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferCreateFlags, VkBufferCreateFlags>::type;
|
|
using BufferCreateInfoType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferCreateInfo, VkBufferCreateInfo>::type;
|
|
using BufferUsageFlagsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferUsageFlags, VkBufferUsageFlags>::type;
|
|
using DeviceSizeType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::DeviceSize, VkDeviceSize>::type;
|
|
using SharingModeType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::SharingMode, VkSharingMode>::type;
|
|
|
|
private:
|
|
using ParentType = vkb::allocated::BuilderBase<bindingType, BufferBuilder<bindingType>, BufferCreateInfoType>;
|
|
|
|
public:
|
|
BufferBuilder(DeviceSizeType size);
|
|
|
|
Buffer<bindingType> build(vkb::core::Device<bindingType> &device) const;
|
|
BufferPtr<bindingType> build_unique(vkb::core::Device<bindingType> &device) const;
|
|
BufferBuilder &with_flags(BufferCreateFlagsType flags);
|
|
BufferBuilder &with_usage(BufferUsageFlagsType usage);
|
|
};
|
|
|
|
using BufferBuilderC = BufferBuilder<vkb::BindingType::C>;
|
|
using BufferBuilderCpp = BufferBuilder<vkb::BindingType::Cpp>;
|
|
|
|
template <>
|
|
inline BufferBuilder<vkb::BindingType::Cpp>::BufferBuilder(vk::DeviceSize size) :
|
|
ParentType(BufferCreateInfoType{.size = size})
|
|
{
|
|
}
|
|
|
|
template <>
|
|
inline BufferBuilder<vkb::BindingType::C>::BufferBuilder(VkDeviceSize size) :
|
|
ParentType(VkBufferCreateInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size})
|
|
{}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline Buffer<bindingType> BufferBuilder<bindingType>::build(vkb::core::Device<bindingType> &device) const
|
|
{
|
|
return Buffer<bindingType>{device, *this};
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline BufferPtr<bindingType> BufferBuilder<bindingType>::build_unique(vkb::core::Device<bindingType> &device) const
|
|
{
|
|
return std::make_unique<Buffer<bindingType>>(device, *this);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline BufferBuilder<bindingType> &BufferBuilder<bindingType>::with_flags(BufferCreateFlagsType flags)
|
|
{
|
|
this->create_info.flags = flags;
|
|
return *this;
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline BufferBuilder<bindingType> &BufferBuilder<bindingType>::with_usage(BufferUsageFlagsType usage)
|
|
{
|
|
this->get_create_info().usage = usage;
|
|
return *this;
|
|
}
|
|
|
|
/*=========================================================*/
|
|
|
|
template <vkb::BindingType bindingType>
|
|
class Buffer
|
|
: public vkb::allocated::Allocated<bindingType, typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::Buffer, VkBuffer>::type>
|
|
{
|
|
public:
|
|
using BufferType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::Buffer, VkBuffer>::type;
|
|
using BufferUsageFlagsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferUsageFlags, VkBufferUsageFlags>::type;
|
|
using DeviceSizeType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::DeviceSize, VkDeviceSize>::type;
|
|
|
|
private:
|
|
using ParentType = vkb::allocated::Allocated<bindingType, BufferType>;
|
|
|
|
public:
|
|
static Buffer<bindingType> create_staging_buffer(vkb::core::Device<bindingType> &device, DeviceSizeType size, const void *data);
|
|
|
|
template <typename T>
|
|
static Buffer create_staging_buffer(vkb::core::Device<bindingType> &device, std::vector<T> const &data);
|
|
|
|
template <typename T>
|
|
static Buffer create_staging_buffer(vkb::core::Device<bindingType> &device, const T &data);
|
|
|
|
Buffer() = delete;
|
|
Buffer(const Buffer &) = delete;
|
|
Buffer(Buffer &&other) = default;
|
|
Buffer &operator=(const Buffer &) = delete;
|
|
Buffer &operator=(Buffer &&) = default;
|
|
|
|
/**
|
|
* @brief Creates a buffer using VMA
|
|
* @param device A valid Vulkan device
|
|
* @param size The size in bytes of the buffer
|
|
* @param buffer_usage The usage flags for the VkBuffer
|
|
* @param memory_usage The memory usage of the buffer
|
|
* @param flags The allocation create flags
|
|
* @param queue_family_indices optional queue family indices
|
|
*/
|
|
// [[deprecated("Use the BufferBuilder ctor instead")]]
|
|
Buffer(vkb::core::Device<bindingType> &device,
|
|
DeviceSizeType size,
|
|
BufferUsageFlagsType buffer_usage,
|
|
VmaMemoryUsage memory_usage,
|
|
VmaAllocationCreateFlags flags = VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
|
|
const std::vector<uint32_t> &queue_family_indices = {});
|
|
|
|
Buffer(vkb::core::Device<bindingType> &device, BufferBuilder<bindingType> const &builder);
|
|
|
|
~Buffer();
|
|
|
|
/**
|
|
* @return Return the buffer's device address (note: requires that the buffer has been created with the VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT usage fla)
|
|
*/
|
|
uint64_t get_device_address() const;
|
|
|
|
/**
|
|
* @return The size of the buffer
|
|
*/
|
|
DeviceSizeType get_size() const;
|
|
|
|
private:
|
|
static Buffer<vkb::BindingType::Cpp> create_staging_buffer_impl(vkb::core::DeviceCpp &device, vk::DeviceSize size, const void *data);
|
|
|
|
private:
|
|
vk::DeviceSize size = 0;
|
|
};
|
|
|
|
using BufferC = Buffer<vkb::BindingType::C>;
|
|
using BufferCpp = Buffer<vkb::BindingType::Cpp>;
|
|
|
|
template <vkb::BindingType bindingType>
|
|
template <typename T>
|
|
inline Buffer<bindingType> Buffer<bindingType>::create_staging_buffer(vkb::core::Device<bindingType> &device, const T &data)
|
|
{
|
|
return create_staging_buffer(device, sizeof(T), &data);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline Buffer<bindingType> Buffer<bindingType>::create_staging_buffer(vkb::core::Device<bindingType> &device, DeviceSizeType size, const void *data)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return create_staging_buffer_impl(device, size, data);
|
|
}
|
|
else
|
|
{
|
|
BufferCpp buffer = create_staging_buffer_impl(reinterpret_cast<vkb::core::DeviceCpp &>(device), static_cast<vk::DeviceSize>(size), data);
|
|
return std::move(*reinterpret_cast<BufferC *>(&buffer));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline BufferCpp Buffer<bindingType>::create_staging_buffer_impl(vkb::core::DeviceCpp &device, vk::DeviceSize size, const void *data)
|
|
{
|
|
BufferBuilderCpp builder(size);
|
|
builder.with_vma_flags(VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT)
|
|
.with_usage(vk::BufferUsageFlagBits::eTransferSrc);
|
|
BufferCpp result(device, builder);
|
|
if (data != nullptr)
|
|
{
|
|
result.update(data, size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
template <typename T>
|
|
inline Buffer<bindingType> Buffer<bindingType>::create_staging_buffer(vkb::core::Device<bindingType> &device, std::vector<T> const &data)
|
|
{
|
|
return create_staging_buffer(device, data.size() * sizeof(T), data.data());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline Buffer<bindingType>::Buffer(vkb::core::Device<bindingType> &device,
|
|
DeviceSizeType size,
|
|
BufferUsageFlagsType buffer_usage,
|
|
VmaMemoryUsage memory_usage,
|
|
VmaAllocationCreateFlags flags,
|
|
const std::vector<uint32_t> &queue_family_indices) :
|
|
Buffer(device,
|
|
BufferBuilder<bindingType>(size)
|
|
.with_usage(buffer_usage)
|
|
.with_vma_usage(memory_usage)
|
|
.with_vma_flags(flags)
|
|
.with_queue_families(queue_family_indices)
|
|
.with_implicit_sharing_mode())
|
|
{}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline Buffer<bindingType>::Buffer(vkb::core::Device<bindingType> &device, const BufferBuilder<bindingType> &builder) :
|
|
ParentType(builder.get_allocation_create_info(), nullptr, &device), size(builder.get_create_info().size)
|
|
{
|
|
this->set_handle(this->create_buffer(builder.get_create_info()));
|
|
if (!builder.get_debug_name().empty())
|
|
{
|
|
this->set_debug_name(builder.get_debug_name());
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline Buffer<bindingType>::~Buffer()
|
|
{
|
|
this->destroy_buffer(this->get_handle());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline uint64_t Buffer<bindingType>::get_device_address() const
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return this->get_device().get_handle().getBufferAddressKHR({.buffer = this->get_handle()});
|
|
}
|
|
else
|
|
{
|
|
return static_cast<vk::Device>(this->get_device().get_handle()).getBufferAddressKHR({.buffer = static_cast<vk::Buffer>(this->get_handle())});
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline typename Buffer<bindingType>::DeviceSizeType Buffer<bindingType>::get_size() const
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return size;
|
|
}
|
|
else
|
|
{
|
|
return static_cast<VkDeviceSize>(size);
|
|
}
|
|
}
|
|
|
|
} // namespace core
|
|
} // namespace vkb
|