/* 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 class Buffer; template using BufferPtr = std::unique_ptr>; template class Device; template struct BufferBuilder : public vkb::allocated::BuilderBase, typename std::conditional::type> { public: using BufferCreateFlagsType = typename std::conditional::type; using BufferCreateInfoType = typename std::conditional::type; using BufferUsageFlagsType = typename std::conditional::type; using DeviceSizeType = typename std::conditional::type; using SharingModeType = typename std::conditional::type; private: using ParentType = vkb::allocated::BuilderBase, BufferCreateInfoType>; public: BufferBuilder(DeviceSizeType size); Buffer build(vkb::core::Device &device) const; BufferPtr build_unique(vkb::core::Device &device) const; BufferBuilder &with_flags(BufferCreateFlagsType flags); BufferBuilder &with_usage(BufferUsageFlagsType usage); }; using BufferBuilderC = BufferBuilder; using BufferBuilderCpp = BufferBuilder; template <> inline BufferBuilder::BufferBuilder(vk::DeviceSize size) : ParentType(BufferCreateInfoType{.size = size}) { } template <> inline BufferBuilder::BufferBuilder(VkDeviceSize size) : ParentType(VkBufferCreateInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size}) {} template inline Buffer BufferBuilder::build(vkb::core::Device &device) const { return Buffer{device, *this}; } template inline BufferPtr BufferBuilder::build_unique(vkb::core::Device &device) const { return std::make_unique>(device, *this); } template inline BufferBuilder &BufferBuilder::with_flags(BufferCreateFlagsType flags) { this->create_info.flags = flags; return *this; } template inline BufferBuilder &BufferBuilder::with_usage(BufferUsageFlagsType usage) { this->get_create_info().usage = usage; return *this; } /*=========================================================*/ template class Buffer : public vkb::allocated::Allocated::type> { public: using BufferType = typename std::conditional::type; using BufferUsageFlagsType = typename std::conditional::type; using DeviceSizeType = typename std::conditional::type; private: using ParentType = vkb::allocated::Allocated; public: static Buffer create_staging_buffer(vkb::core::Device &device, DeviceSizeType size, const void *data); template static Buffer create_staging_buffer(vkb::core::Device &device, std::vector const &data); template static Buffer create_staging_buffer(vkb::core::Device &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 &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 &queue_family_indices = {}); Buffer(vkb::core::Device &device, BufferBuilder 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 create_staging_buffer_impl(vkb::core::DeviceCpp &device, vk::DeviceSize size, const void *data); private: vk::DeviceSize size = 0; }; using BufferC = Buffer; using BufferCpp = Buffer; template template inline Buffer Buffer::create_staging_buffer(vkb::core::Device &device, const T &data) { return create_staging_buffer(device, sizeof(T), &data); } template inline Buffer Buffer::create_staging_buffer(vkb::core::Device &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(device), static_cast(size), data); return std::move(*reinterpret_cast(&buffer)); } } template inline BufferCpp Buffer::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 template inline Buffer Buffer::create_staging_buffer(vkb::core::Device &device, std::vector const &data) { return create_staging_buffer(device, data.size() * sizeof(T), data.data()); } template inline Buffer::Buffer(vkb::core::Device &device, DeviceSizeType size, BufferUsageFlagsType buffer_usage, VmaMemoryUsage memory_usage, VmaAllocationCreateFlags flags, const std::vector &queue_family_indices) : Buffer(device, BufferBuilder(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 inline Buffer::Buffer(vkb::core::Device &device, const BufferBuilder &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 inline Buffer::~Buffer() { this->destroy_buffer(this->get_handle()); } template inline uint64_t Buffer::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(this->get_device().get_handle()).getBufferAddressKHR({.buffer = static_cast(this->get_handle())}); } } template inline typename Buffer::DeviceSizeType Buffer::get_size() const { if constexpr (bindingType == vkb::BindingType::Cpp) { return size; } else { return static_cast(size); } } } // namespace core } // namespace vkb