From e757747a8e17811d50a806b0bc7a73a8240746e1 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Sat, 10 Feb 2024 17:18:23 -0800 Subject: [PATCH] Allocated base classes --- framework/CMakeLists.txt | 13 +- framework/api_vulkan_sample.cpp | 23 +- framework/buffer_pool.h | 4 +- framework/core/acceleration_structure.cpp | 6 +- framework/core/acceleration_structure.h | 9 +- framework/core/allocated.cpp | 112 +++++ framework/core/allocated.h | 426 ++++++++++++++++++ framework/core/buffer.cpp | 156 ++----- framework/core/buffer.h | 147 +++--- framework/core/command_buffer.h | 4 +- framework/core/device.cpp | 115 +---- framework/core/device.h | 14 +- framework/core/hpp_allocated.h | 99 ++++ framework/core/hpp_buffer.cpp | 151 ++----- framework/core/hpp_buffer.h | 119 ++--- framework/core/hpp_device.cpp | 63 +-- framework/core/hpp_device.h | 6 +- framework/core/hpp_image.cpp | 137 ++---- framework/core/hpp_image.h | 135 ++++-- framework/core/image.cpp | 169 +++---- framework/core/image.h | 167 ++++--- framework/core/image_view.h | 4 +- framework/core/render_pass.h | 10 +- framework/core/sampler.h | 4 +- framework/core/scratch_buffer.cpp | 74 --- framework/core/scratch_buffer.h | 71 --- framework/core/shader_binding_table.cpp | 80 ---- framework/core/shader_binding_table.h | 69 --- framework/core/vulkan_resource.h | 63 ++- framework/gltf_loader.cpp | 46 +- framework/gui.cpp | 32 +- framework/hpp_api_vulkan_sample.cpp | 14 +- framework/hpp_buffer_pool.h | 4 +- framework/hpp_gui.cpp | 35 +- framework/rendering/hpp_render_context.cpp | 13 +- framework/rendering/hpp_render_context.h | 4 +- framework/rendering/hpp_render_target.cpp | 10 +- framework/rendering/render_context.cpp | 14 +- framework/rendering/render_context.h | 4 +- framework/rendering/render_target.cpp | 12 +- .../scene_graph/components/hpp_image.cpp | 24 +- framework/scene_graph/components/image.cpp | 24 +- samples/api/compute_nbody/compute_nbody.cpp | 5 +- .../hpp_compute_nbody/hpp_compute_nbody.cpp | 11 +- .../hpp_texture_mipmap_generation.cpp | 5 +- samples/api/instancing/instancing.cpp | 5 +- .../api/oit_linked_lists/oit_linked_lists.cpp | 13 +- .../conservative_rasterization.cpp | 9 +- .../fragment_shading_rate_dynamic.cpp | 48 +- .../ray_tracing_basic/ray_tracing_basic.cpp | 180 ++------ .../ray_tracing_basic/ray_tracing_basic.h | 54 +-- .../ray_tracing_extended.cpp | 32 +- .../ray_tracing_reflection.cpp | 20 +- .../synchronization_2/synchronization_2.cpp | 5 +- .../multi_draw_indirect.cpp | 28 +- third_party/CMakeLists.txt | 2 +- 56 files changed, 1490 insertions(+), 1613 deletions(-) create mode 100644 framework/core/allocated.cpp create mode 100644 framework/core/allocated.h create mode 100644 framework/core/hpp_allocated.h delete mode 100644 framework/core/scratch_buffer.cpp delete mode 100644 framework/core/scratch_buffer.h delete mode 100644 framework/core/shader_binding_table.cpp delete mode 100644 framework/core/shader_binding_table.h diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 11354050db..e5809e6489 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2023, Arm Limited and Contributors +# Copyright (c) 2019-2024, Arm Limited and Contributors # # SPDX-License-Identifier: Apache-2.0 # @@ -78,7 +78,7 @@ set(COMMON_FILES common/ktx_common.h common/vk_common.h common/vk_initializers.h - common/glm_common.h + common/glm_common.h common/resource_caching.h common/logging.h common/helpers.h @@ -242,6 +242,7 @@ set(CORE_FILES core/command_pool.h core/swapchain.h core/command_buffer.h + core/allocated.h core/buffer.h core/image.h core/image_view.h @@ -251,9 +252,8 @@ set(CORE_FILES core/framebuffer.h core/render_pass.h core/query_pool.h - core/scratch_buffer.h core/acceleration_structure.h - core/shader_binding_table.h + core/hpp_allocated.h core/hpp_buffer.h core/hpp_command_buffer.h core/hpp_command_pool.h @@ -293,6 +293,7 @@ set(CORE_FILES core/command_pool.cpp core/swapchain.cpp core/command_buffer.cpp + core/allocated.cpp core/buffer.cpp core/image.cpp core/image_view.cpp @@ -302,9 +303,7 @@ set(CORE_FILES core/framebuffer.cpp core/render_pass.cpp core/query_pool.cpp - core/scratch_buffer.cpp core/acceleration_structure.cpp - core/shader_binding_table.cpp core/vulkan_resource.cpp core/hpp_buffer.cpp core/hpp_command_buffer.cpp @@ -387,7 +386,7 @@ set(LINUX_D2D_FILES platform/unix/direct_window.h # Source Files platform/unix/unix_d2d_platform.cpp - platform/unix/direct_window.cpp) + platform/unix/direct_window.cpp) source_group("\\" FILES ${FRAMEWORK_FILES}) source_group("common\\" FILES ${COMMON_FILES}) diff --git a/framework/api_vulkan_sample.cpp b/framework/api_vulkan_sample.cpp index 8c5a0ee30d..c44552299c 100644 --- a/framework/api_vulkan_sample.cpp +++ b/framework/api_vulkan_sample.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -1000,12 +1000,7 @@ Texture ApiVulkanSample::load_texture(const std::string &file, vkb::sg::Image::C VkCommandBuffer command_buffer = device->create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkb::core::Buffer stage_buffer{*device, - texture.image->get_data().size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::Buffer stage_buffer = vkb::core::Buffer::create_staging_buffer(*device, texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector bufferCopyRegions; @@ -1096,12 +1091,7 @@ Texture ApiVulkanSample::load_texture_array(const std::string &file, vkb::sg::Im VkCommandBuffer command_buffer = device->create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkb::core::Buffer stage_buffer{*device, - texture.image->get_data().size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::Buffer stage_buffer = vkb::core::Buffer::create_staging_buffer(*device, texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector buffer_copy_regions; @@ -1195,12 +1185,7 @@ Texture ApiVulkanSample::load_texture_cubemap(const std::string &file, vkb::sg:: VkCommandBuffer command_buffer = device->create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkb::core::Buffer stage_buffer{*device, - texture.image->get_data().size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::Buffer stage_buffer = vkb::core::Buffer::create_staging_buffer(*device, texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector buffer_copy_regions; diff --git a/framework/buffer_pool.h b/framework/buffer_pool.h index ab0cd2ee20..44e5ef3be2 100644 --- a/framework/buffer_pool.h +++ b/framework/buffer_pool.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -127,7 +127,7 @@ class BufferBlock class BufferPool { public: - BufferPool(Device &device, VkDeviceSize block_size, VkBufferUsageFlags usage, VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU); + BufferPool(Device &device, VkDeviceSize block_size, VkBufferUsageFlags usage, VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_AUTO); BufferBlock &request_buffer_block(VkDeviceSize minimum_size, bool minimal = false); diff --git a/framework/core/acceleration_structure.cpp b/framework/core/acceleration_structure.cpp index 2911ba81c5..61c0b11fb9 100644 --- a/framework/core/acceleration_structure.cpp +++ b/framework/core/acceleration_structure.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, Sascha Willems +/* Copyright (c) 2021-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -23,7 +23,7 @@ namespace vkb { namespace core { -AccelerationStructure::AccelerationStructure(Device & device, +AccelerationStructure::AccelerationStructure(Device &device, VkAccelerationStructureTypeKHR type) : device{device}, type{type} @@ -202,7 +202,7 @@ void AccelerationStructure::build(VkQueue queue, VkBuildAccelerationStructureFla device_address = vkGetAccelerationStructureDeviceAddressKHR(device.get_handle(), &acceleration_device_address_info); // Create a scratch buffer as a temporary storage for the acceleration structure build - scratch_buffer = std::make_unique(device, build_sizes_info.buildScratchSize); + scratch_buffer = std::make_unique(vkb::core::Buffer::create_scratch_buffer(device, build_sizes_info.buildScratchSize)); build_geometry_info.scratchData.deviceAddress = scratch_buffer->get_device_address(); build_geometry_info.dstAccelerationStructure = handle; diff --git a/framework/core/acceleration_structure.h b/framework/core/acceleration_structure.h index 7d65b6f149..61fbcf8621 100644 --- a/framework/core/acceleration_structure.h +++ b/framework/core/acceleration_structure.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, Sascha Willems +/* Copyright (c) 2021-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -20,7 +20,6 @@ #include "common/helpers.h" #include "common/vk_common.h" #include "core/buffer.h" -#include "core/scratch_buffer.h" namespace vkb { @@ -39,7 +38,7 @@ class AccelerationStructure * @param device A valid Vulkan device * @param type The type of the acceleration structure (top- or bottom-level) */ - AccelerationStructure(Device & device, + AccelerationStructure(Device &device, VkAccelerationStructureTypeKHR type); ~AccelerationStructure(); @@ -54,7 +53,7 @@ class AccelerationStructure * @param max_vertex Index of the last vertex in the geometry * @param vertex_stride Stride of the vertex structure * @param transform_offset Offset of this geometry in the transform data buffer - * @param vertex_format Format of the vertex structure + * @param vertex_format Format of the vertex structure * @param flags Ray tracing geometry flags * @param vertex_buffer_data_address set this if don't want the vertex_buffer data_address * @param index_buffer_data_address set this if don't want the index_buffer data_address @@ -149,7 +148,7 @@ class AccelerationStructure bool updated = false; }; - std::unique_ptr scratch_buffer; + std::unique_ptr scratch_buffer; std::map geometries{}; diff --git a/framework/core/allocated.cpp b/framework/core/allocated.cpp new file mode 100644 index 0000000000..2eae5cd238 --- /dev/null +++ b/framework/core/allocated.cpp @@ -0,0 +1,112 @@ +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024, Bradley Austin Davis. 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. + */ + +#include "allocated.h" + +namespace vkb +{ + +namespace allocated +{ + +VmaAllocator &get_memory_allocator() +{ + static VmaAllocator memory_allocator = VK_NULL_HANDLE; + return memory_allocator; +} + +void init(const VmaAllocatorCreateInfo &create_info) +{ + VkResult result = vmaCreateAllocator(&create_info, &get_memory_allocator()); + if (result != VK_SUCCESS) + { + throw VulkanException{result, "Cannot create allocator"}; + } +} + +void shutdown() +{ + auto &allocator = get_memory_allocator(); + if (allocator != VK_NULL_HANDLE) + { + VmaTotalStatistics stats; + vmaCalculateStatistics(allocator, &stats); + LOGI("Total device memory leaked: {} bytes.", stats.total.statistics.allocationBytes); + vmaDestroyAllocator(allocator); + allocator = VK_NULL_HANDLE; + } +} + +[[nodiscard]] std::pair vma_create_buffer(VmaAllocator alloctor, const VkBufferCreateInfo &create_info, VmaAllocationCreateInfo &alloc_create_info, VmaAllocationInfo *alloc_info) +{ + VkBuffer handle = VK_NULL_HANDLE; + VmaAllocation allocation = VK_NULL_HANDLE; + + auto result = vmaCreateBuffer( + alloctor, + &create_info, + &alloc_create_info, + &handle, + &allocation, + alloc_info); + + if (result != VK_SUCCESS) + { + throw VulkanException{result, "Cannot create Buffer"}; + } + return {handle, allocation}; +} + +[[nodiscard]] std::pair vma_create_image(VmaAllocator alloctor, const VkImageCreateInfo &create_info, VmaAllocationCreateInfo &alloc_create_info, VmaAllocationInfo *alloc_info) +{ + VkImage handle = VK_NULL_HANDLE; + VmaAllocation allocation = VK_NULL_HANDLE; + +#if 0 + // If the image is an attachment, prefer dedicated memory + constexpr VkImageUsageFlags attachment_only_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; + if (create_info.usage & attachment_only_flags) + { + alloc_create_info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } + + if (create_info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) + { + alloc_create_info.preferredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + } +#endif + + auto result = vmaCreateImage( + alloctor, + &create_info, + &alloc_create_info, + &handle, + &allocation, + alloc_info); + + if (result != VK_SUCCESS) + { + throw VulkanException{result, "Cannot create Image"}; + } + + return {handle, allocation}; +} + +} // namespace allocated + +} // namespace vkb diff --git a/framework/core/allocated.h b/framework/core/allocated.h new file mode 100644 index 0000000000..5e7b44bb6d --- /dev/null +++ b/framework/core/allocated.h @@ -0,0 +1,426 @@ +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024, Bradley Austin Davis. 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 "common/error.h" +#include "core/vulkan_resource.h" +#include +#include + +namespace vkb +{ + +class Device; + +namespace allocated +{ + +template < + typename BuilderType, + typename CreateInfoType, + typename SharingModeType = VkSharingMode> +struct Builder +{ + VmaAllocationCreateInfo alloc_create_info{}; + CreateInfoType create_info; + std::string debug_name; + + protected: + Builder(const Builder &other) = delete; + Builder(const CreateInfoType &create_info) : + create_info(create_info) + { + alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO; + }; + + public: + BuilderType &with_debug_name(const std::string &name) + { + debug_name = name; + return *static_cast(this); + } + + BuilderType &with_vma_usage(VmaMemoryUsage usage) + { + alloc_create_info.usage = usage; + return *static_cast(this); + } + + BuilderType &with_vma_flags(VmaAllocationCreateFlags flags) + { + alloc_create_info.flags = flags; + return *static_cast(this); + } + + BuilderType &with_vma_required_flags(VkMemoryPropertyFlags flags) + { + alloc_create_info.requiredFlags = flags; + return *static_cast(this); + } + + BuilderType &with_vma_preferred_flags(VkMemoryPropertyFlags flags) + { + alloc_create_info.preferredFlags = flags; + return *static_cast(this); + } + + BuilderType &with_memory_type_bits(uint32_t type_bits) + { + alloc_create_info.memoryTypeBits = type_bits; + return *static_cast(this); + } + + BuilderType &with_vma_pool(VmaPool pool) + { + alloc_create_info.pool = pool; + return *static_cast(this); + } + + BuilderType &with_queue_families(uint32_t count, const uint32_t *family_indices) + { + create_info.queueFamilyIndexCount = count; + create_info.pQueueFamilyIndices = family_indices; + return *static_cast(this); + } + + BuilderType &with_sharing(VkSharingMode sharing) + { + create_info.sharingMode = sharing; + return *static_cast(this); + } + + BuilderType &with_implicit_sharing_mode() + { + if (create_info.queueFamilyIndexCount != 0) + { + create_info.sharingMode = static_cast(VK_SHARING_MODE_CONCURRENT); + } + else + { + create_info.sharingMode = static_cast(VK_SHARING_MODE_EXCLUSIVE); + } + return *static_cast(this); + } + + BuilderType &with_queue_families(const std::vector &queue_families) + { + return with_queue_families(static_cast(queue_families.size()), queue_families.data()); + } +}; + +[[nodiscard]] std::pair vma_create_buffer(VmaAllocator alloctor, const VkBufferCreateInfo &create_info, VmaAllocationCreateInfo &alloc_create_info, VmaAllocationInfo *alloc_info = nullptr); + +[[nodiscard]] std::pair vma_create_image(VmaAllocator alloctor, const VkImageCreateInfo &create_info, VmaAllocationCreateInfo &alloc_create_info, VmaAllocationInfo *alloc_info = nullptr); + +void init(const VmaAllocatorCreateInfo &create_info); + +template +void init(const DeviceType &device) +{ + VmaVulkanFunctions vma_vulkan_func{}; + vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr; + vma_vulkan_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr; + + VmaAllocatorCreateInfo allocator_info{}; + allocator_info.pVulkanFunctions = &vma_vulkan_func; + allocator_info.physicalDevice = static_cast(device.get_gpu().get_handle()); + allocator_info.device = static_cast(device.get_handle()); + allocator_info.instance = static_cast(device.get_gpu().get_instance().get_handle()); + + bool can_get_memory_requirements = device.is_extension_supported(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + bool has_dedicated_allocation = device.is_extension_supported(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + if (can_get_memory_requirements && has_dedicated_allocation) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + } + + if (device.is_extension_supported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) && device.is_enabled(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; + } + + if (device.is_extension_supported(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) && device.is_enabled(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; + } + + if (device.is_extension_supported(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) && device.is_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT; + } + + if (device.is_extension_supported(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) && device.is_enabled(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME)) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT; + } + + if (device.is_extension_supported(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) && device.is_enabled(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME)) + { + allocator_info.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT; + } + + init(allocator_info); +} + +VmaAllocator &get_memory_allocator(); + +void shutdown(); + +template < + typename HandleType, + typename MemoryType = VkDeviceMemory, + typename DeviceType = const vkb::Device, + typename ParentType = vkb::core::VulkanResource> +class Allocated : public ParentType +{ + public: + using ParentType::ParentType; + + // Import the base class constructors + template + Allocated(const VmaAllocationCreateInfo &alloc_create_info, Args &&...args) : + ParentType(std::forward(args)...), + alloc_create_info(alloc_create_info) + { + persistent = (alloc_create_info.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; + } + + Allocated(const Allocated &) = delete; + + Allocated(Allocated &&other) : + ParentType{static_cast(other)}, + alloc_create_info(std::exchange(other.alloc_create_info, {})), + allocation(std::exchange(other.allocation, {})), + memory(std::exchange(other.memory, {})), + mapped_data(std::exchange(other.mapped_data, {})), + mapped(std::exchange(other.mapped, {})), + coherent(std::exchange(other.coherent, {})), + persistent(std::exchange(other.persistent, {})) + { + assert(other.allocation == VK_NULL_HANDLE); + assert(other.memory == MemoryType{VK_NULL_HANDLE}); + assert(other.mapped_data == nullptr); + assert(other.mapped == false); + } + + Allocated &operator=(const Allocated &) = delete; + Allocated &operator=(Allocated &&) = delete; + + const HandleType *get() const + { + return &ParentType::get_handle(); + } + + VmaAllocation get_allocation() const + { + return allocation; + } + + const uint8_t *get_data() const + { + return mapped_data; + } + + MemoryType get_memory() const + { + return memory; + } + + /** + * @brief Flushes memory if it is HOST_VISIBLE and not HOST_COHERENT + */ + void flush(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) + { + if (!coherent) + { + vmaFlushAllocation(get_memory_allocator(), allocation, offset, size); + } + } + + /** + * @brief Maps vulkan memory if it isn't already mapped to an host visible address + * @return Pointer to host visible memory + */ + uint8_t *map() + { + if (!persistent && !mapped && !mapped_data) + { + VK_CHECK(vmaMapMemory(get_memory_allocator(), allocation, reinterpret_cast(&mapped_data))); + mapped = true; + } + return mapped_data; + } + + /** + * @brief Unmaps vulkan memory from the host visible address + */ + void unmap() + { + if (!persistent && mapped) + { + vmaUnmapMemory(get_memory_allocator(), allocation); + mapped_data = nullptr; + mapped = false; + } + } + + /** + * @brief Copies byte data into the buffer + * @param data The data to copy from + * @param size The amount of bytes to copy + * @param offset The offset to start the copying into the mapped data + */ + size_t update(const uint8_t *data, size_t size, size_t offset = 0) + { + if (persistent) + { + std::copy(data, data + size, mapped_data + offset); + flush(); + } + else + { + map(); + std::copy(data, data + size, mapped_data + offset); + flush(); + unmap(); + } + return size; + } + + /** + * @brief Converts any non byte data into bytes and then updates the buffer + * @param data The data to copy from + * @param size The amount of bytes to copy + * @param offset The offset to start the copying into the mapped data + */ + size_t update(void const *data, size_t size, size_t offset = 0) + { + return update(reinterpret_cast(data), size, offset); + } + + /** + * @brief Copies a vector of bytes into the buffer + * @param data The data vector to upload + * @param offset The offset to start the copying into the mapped data + */ + size_t update(const std::vector &data, size_t offset = 0) + { + return update(data.data(), data.size(), offset); + } + + template + size_t update(std::vector const &data, size_t offset = 0) + { + return update(data.data(), data.size() * sizeof(T), offset); + } + + template + size_t update(std::array const &data, size_t offset = 0) + { + return update(data.data(), data.size() * sizeof(T), offset); + } + + /** + * @brief Copies an object as byte data into the buffer + * @param object The object to convert into byte data + * @param offset The offset to start the copying into the mapped data + */ + template + size_t convert_and_update(const T &object, size_t offset = 0) + { + return update(reinterpret_cast(&object), sizeof(T), offset); + } + + protected: + void post_create(VmaAllocationInfo const &allocation_info) + { + VkMemoryPropertyFlags memory_properties; + vmaGetAllocationMemoryProperties(get_memory_allocator(), allocation, &memory_properties); + if (memory_properties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + { + coherent = true; + } + + memory = allocation_info.deviceMemory; + mapped_data = static_cast(allocation_info.pMappedData); + persistent = mapped_data != nullptr; + } + + [[nodiscard]] VkBuffer create_buffer(VkBufferCreateInfo const &create_info) + { + VkBuffer handleResult = VK_NULL_HANDLE; + VmaAllocationInfo allocation_info{}; + std::tie(handleResult, allocation) = vma_create_buffer(get_memory_allocator(), create_info, alloc_create_info, &allocation_info); + post_create(allocation_info); + return handleResult; + } + + [[nodiscard]] VkImage create_image(VkImageCreateInfo const &create_info) + { + assert(0 < create_info.mipLevels && "Images should have at least one level"); + assert(0 < create_info.arrayLayers && "Images should have at least one layer"); + assert(0 < create_info.usage && "Images should have at least one usage type"); + + VkImage handleResult = VK_NULL_HANDLE; + VmaAllocationInfo allocation_info{}; + std::tie(handleResult, allocation) = vma_create_image(get_memory_allocator(), create_info, alloc_create_info, &allocation_info); + post_create(allocation_info); + return handleResult; + } + + void destroy_buffer() + { + if (ParentType::get_handle() != HandleType{VK_NULL_HANDLE} && memory != MemoryType{VK_NULL_HANDLE}) + { + unmap(); + vmaDestroyBuffer(get_memory_allocator(), ParentType::get_handle(), allocation); + clear(); + } + } + + void destroy_image() + { + if (ParentType::get_handle() != VK_NULL_HANDLE && memory != MemoryType{VK_NULL_HANDLE}) + { + unmap(); + vmaDestroyImage(get_memory_allocator(), ParentType::get_handle(), allocation); + clear(); + } + } + + void clear() + { + memory = nullptr; + mapped_data = nullptr; + persistent = false; + alloc_create_info = {}; + } + + protected: + VmaAllocationCreateInfo alloc_create_info{}; + VmaAllocation allocation = VK_NULL_HANDLE; + MemoryType memory = nullptr; + uint8_t *mapped_data = nullptr; + bool coherent = false; + bool persistent = false; // Whether the buffer is persistently mapped or not + bool mapped = false; // Whether the buffer has been mapped with vmaMapMemory +}; + +} // namespace allocated +} // namespace vkb diff --git a/framework/core/buffer.cpp b/framework/core/buffer.cpp index defe63aed7..7a2f4fc0df 100644 --- a/framework/core/buffer.cpp +++ b/framework/core/buffer.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -23,123 +23,62 @@ namespace vkb { namespace core { -Buffer::Buffer(Device const &device, VkDeviceSize size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage memory_usage, VmaAllocationCreateFlags flags, const std::vector &queue_family_indices) : - VulkanResource{VK_NULL_HANDLE, &device}, - size{size} -{ -#ifdef VK_USE_PLATFORM_METAL_EXT - // Workaround for Mac (MoltenVK requires unmapping https://github.com/KhronosGroup/MoltenVK/issues/175) - // Force cleares the flag VMA_ALLOCATION_CREATE_MAPPED_BIT - flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; -#endif - - persistent = (flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; - - VkBufferCreateInfo buffer_info{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - buffer_info.usage = buffer_usage; - buffer_info.size = size; - if (queue_family_indices.size() >= 2) - { - buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; - buffer_info.queueFamilyIndexCount = static_cast(queue_family_indices.size()); - buffer_info.pQueueFamilyIndices = queue_family_indices.data(); - } - - VmaAllocationCreateInfo memory_info{}; - memory_info.flags = flags; - memory_info.usage = memory_usage; - - VmaAllocationInfo allocation_info{}; - auto result = vmaCreateBuffer(device.get_memory_allocator(), - &buffer_info, &memory_info, - &handle, &allocation, - &allocation_info); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Cannot create Buffer"}; - } - - memory = allocation_info.deviceMemory; - if (persistent) - { - mapped_data = static_cast(allocation_info.pMappedData); - } -} - -Buffer::Buffer(Buffer &&other) : - VulkanResource{other.handle, other.device}, - allocation{other.allocation}, - memory{other.memory}, - size{other.size}, - mapped_data{other.mapped_data}, - mapped{other.mapped} +Buffer Buffer::create_scratch_buffer(Device const &device, VkDeviceSize size) { - // Reset other handles to avoid releasing on destruction - other.allocation = VK_NULL_HANDLE; - other.memory = VK_NULL_HANDLE; - other.mapped_data = nullptr; - other.mapped = false; + BufferBuilder builder{size}; + builder.with_usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + builder.with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + return Buffer(device, builder); } -Buffer::~Buffer() +Buffer Buffer::create_staging_buffer(Device const &device, VkDeviceSize size, const void *data) { - if (handle != VK_NULL_HANDLE && allocation != VK_NULL_HANDLE) + BufferBuilder builder{size}; + builder.with_vma_flags(VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + builder.with_usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + Buffer result(device, builder); + if (data != nullptr) { - unmap(); - vmaDestroyBuffer(device->get_memory_allocator(), handle, allocation); + result.update(data, size); } + return result; } -const VkBuffer *Buffer::get() const -{ - return &handle; -} - -VmaAllocation Buffer::get_allocation() const -{ - return allocation; -} - -VkDeviceMemory Buffer::get_memory() const -{ - return memory; -} - -VkDeviceSize Buffer::get_size() const -{ - return size; -} - -uint8_t *Buffer::map() -{ - if (!mapped && !mapped_data) +Buffer::Buffer(Device const &device, VkDeviceSize size, VkBufferUsageFlags 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()) +{} + +Buffer::Buffer(Device const &device, const BufferBuilder &builder) : + Allocated{builder.alloc_create_info, VK_NULL_HANDLE, &device}, size(builder.create_info.size) +{ + handle = create_buffer(builder.create_info); + if (!builder.debug_name.empty()) { - VK_CHECK(vmaMapMemory(device->get_memory_allocator(), allocation, reinterpret_cast(&mapped_data))); - mapped = true; + set_debug_name(builder.debug_name); } - return mapped_data; } -void Buffer::unmap() +Buffer::Buffer(Buffer &&other) noexcept : + Allocated{std::move(other)}, + size{std::exchange(other.size, {})} { - if (mapped) - { - vmaUnmapMemory(device->get_memory_allocator(), allocation); - mapped_data = nullptr; - mapped = false; - } } -void Buffer::flush() const +Buffer::~Buffer() { - vmaFlushAllocation(device->get_memory_allocator(), allocation, 0, size); + destroy_buffer(); } -void Buffer::update(const std::vector &data, size_t offset) +VkDeviceSize Buffer::get_size() const { - update(data.data(), data.size(), offset); + return size; } uint64_t Buffer::get_device_address() @@ -150,26 +89,5 @@ uint64_t Buffer::get_device_address() return vkGetBufferDeviceAddressKHR(device->get_handle(), &buffer_device_address_info); } -void Buffer::update(void const *data, size_t size, size_t offset) -{ - update(reinterpret_cast(data), size, offset); -} - -void Buffer::update(const uint8_t *data, const size_t size, const size_t offset) -{ - if (persistent) - { - std::copy(data, data + size, mapped_data + offset); - flush(); - } - else - { - map(); - std::copy(data, data + size, mapped_data + offset); - flush(); - unmap(); - } -} - } // namespace core } // namespace vkb diff --git a/framework/core/buffer.h b/framework/core/buffer.h index 5ccf37d4fc..9d704153a3 100644 --- a/framework/core/buffer.h +++ b/framework/core/buffer.h @@ -19,6 +19,7 @@ #include "common/helpers.h" #include "common/vk_common.h" +#include "core/allocated.h" #include "core/vulkan_resource.h" namespace vkb @@ -27,9 +28,61 @@ class Device; namespace core { -class Buffer : public VulkanResource + +struct BufferBuilder : public allocated::Builder +{ + BufferBuilder(VkDeviceSize size) : + Builder(VkBufferCreateInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size}) + { + } + + BufferBuilder &with_flags(VkBufferCreateFlags flags) + { + create_info.flags = flags; + return *this; + } + + BufferBuilder &with_usage(VkBufferUsageFlags usage) + { + create_info.usage = usage; + return *this; + } + + BufferBuilder &with_sharing_mode(VkSharingMode sharing_mode) + { + create_info.sharingMode = sharing_mode; + return *this; + } + + BufferBuilder &with_implicit_sharing_mode() + { + if (create_info.queueFamilyIndexCount != 0) + { + create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + } + return *this; + } +}; + +class Buffer : public allocated::Allocated { public: + static Buffer create_staging_buffer(Device const &device, VkDeviceSize size, const void *data); + + template + static Buffer create_staging_buffer(Device const &device, const std::vector &data) + { + return create_staging_buffer(device, data.size() * sizeof(T), data.data()); + } + + template + static Buffer create_staging_buffer(Device const &device, const T &data) + { + return create_staging_buffer(device, sizeof(T), &data); + } + + static Buffer create_scratch_buffer(Device const &device, VkDeviceSize size); + /** * @brief Creates a buffer using VMA * @param device A valid Vulkan device @@ -46,9 +99,11 @@ class Buffer : public VulkanResource &queue_family_indices = {}); + Buffer(Device const &device, const BufferBuilder &builder); + Buffer(const Buffer &) = delete; - Buffer(Buffer &&other); + Buffer(Buffer &&other) noexcept; ~Buffer(); @@ -56,6 +111,9 @@ class Buffer : public VulkanResource static std::vector copy(std::unordered_map &buffers, const char *buffer_name) { @@ -82,103 +140,18 @@ class Buffer : public VulkanResource &data, size_t offset = 0); - - template - void update(std::array const &data, size_t offset = 0) - { - update(data.data(), data.size() * sizeof(T), offset); - } - - template - void update(std::vector const &data, size_t offset = 0) - { - update(data.data(), data.size() * sizeof(T), offset); - } - - /** - * @brief Copies an object as byte data into the buffer - * @param object The object to convert into byte data - * @param offset The offset to start the copying into the mapped data - */ - template - void convert_and_update(const T &object, size_t offset = 0) - { - update(reinterpret_cast(&object), sizeof(T), offset); - } - /** * @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(); private: - VmaAllocation allocation{VK_NULL_HANDLE}; - - VkDeviceMemory memory{VK_NULL_HANDLE}; - VkDeviceSize size{0}; - - uint8_t *mapped_data{nullptr}; - - /// Whether the buffer is persistently mapped or not - bool persistent{false}; - - /// Whether the buffer has been mapped with vmaMapMemory - bool mapped{false}; }; } // namespace core } // namespace vkb diff --git a/framework/core/command_buffer.h b/framework/core/command_buffer.h index e8680f0195..25c0530d39 100644 --- a/framework/core/command_buffer.h +++ b/framework/core/command_buffer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -47,7 +47,7 @@ struct LightingState; * @brief Helper class to manage and record a command buffer, building and * keeping track of pipeline state and resource bindings */ -class CommandBuffer : public core::VulkanResource +class CommandBuffer : public core::VulkanResource { public: enum class ResetMode diff --git a/framework/core/device.cpp b/framework/core/device.cpp index 3faaba8d3a..5dd42f2b9b 100644 --- a/framework/core/device.cpp +++ b/framework/core/device.cpp @@ -197,53 +197,7 @@ Device::Device(PhysicalDevice &gpu, } } - VmaVulkanFunctions vma_vulkan_func{}; - vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr; - vma_vulkan_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr; - - VmaAllocatorCreateInfo allocator_info{}; - allocator_info.physicalDevice = gpu.get_handle(); - allocator_info.device = handle; - allocator_info.instance = gpu.get_instance().get_handle(); - - if (can_get_memory_requirements && has_dedicated_allocation) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - } - - if (is_extension_supported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) && is_enabled(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; - } - - if (is_extension_supported(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) && is_enabled(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; - } - - if (is_extension_supported(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) && is_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT; - } - - if (is_extension_supported(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) && is_enabled(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT; - } - - if (is_extension_supported(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) && is_enabled(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT; - } - - allocator_info.pVulkanFunctions = &vma_vulkan_func; - - result = vmaCreateAllocator(&allocator_info, &memory_allocator); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Cannot create allocator"}; - } + prepare_memory_allocator(); command_pool = std::make_unique(*this, get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0).get_family_index()); fence_pool = std::make_unique(*this); @@ -264,15 +218,7 @@ Device::~Device() command_pool.reset(); fence_pool.reset(); - if (memory_allocator != VK_NULL_HANDLE) - { - VmaTotalStatistics stats; - vmaCalculateStatistics(memory_allocator, &stats); - - LOGI("Total device memory leaked: {} bytes.", stats.total.statistics.allocationBytes); - - vmaDestroyAllocator(memory_allocator); - } + vkb::allocated::shutdown(); if (handle != VK_NULL_HANDLE) { @@ -280,7 +226,7 @@ Device::~Device() } } -bool Device::is_extension_supported(const std::string &requested_extension) +bool Device::is_extension_supported(const std::string &requested_extension) const { return std::find_if(device_extensions.begin(), device_extensions.end(), [requested_extension](auto &device_extension) { @@ -288,7 +234,7 @@ bool Device::is_extension_supported(const std::string &requested_extension) }) != device_extensions.end(); } -bool Device::is_enabled(const char *extension) +bool Device::is_enabled(const char *extension) const { return std::find_if(enabled_extensions.begin(), enabled_extensions.end(), [extension](const char *enabled_extension) { return strcmp(extension, enabled_extension) == 0; }) != enabled_extensions.end(); } @@ -298,11 +244,6 @@ const PhysicalDevice &Device::get_gpu() const return gpu; } -VmaAllocator Device::get_memory_allocator() const -{ - return memory_allocator; -} - DriverVersion Device::get_driver_version() const { DriverVersion version; @@ -608,53 +549,7 @@ void Device::create_internal_command_pool() void Device::prepare_memory_allocator() { - bool can_get_memory_requirements = is_extension_supported("VK_KHR_get_memory_requirements2"); - bool has_dedicated_allocation = is_extension_supported("VK_KHR_dedicated_allocation"); - - VmaVulkanFunctions vma_vulkan_func{}; - vma_vulkan_func.vkAllocateMemory = vkAllocateMemory; - vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory; - vma_vulkan_func.vkBindImageMemory = vkBindImageMemory; - vma_vulkan_func.vkCreateBuffer = vkCreateBuffer; - vma_vulkan_func.vkCreateImage = vkCreateImage; - vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer; - vma_vulkan_func.vkDestroyImage = vkDestroyImage; - vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges; - vma_vulkan_func.vkFreeMemory = vkFreeMemory; - vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements; - vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements; - vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties; - vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties; - vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges; - vma_vulkan_func.vkMapMemory = vkMapMemory; - vma_vulkan_func.vkUnmapMemory = vkUnmapMemory; - vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer; - - VmaAllocatorCreateInfo allocator_info{}; - allocator_info.physicalDevice = gpu.get_handle(); - allocator_info.device = handle; - allocator_info.instance = gpu.get_instance().get_handle(); - - if (can_get_memory_requirements && has_dedicated_allocation) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - vma_vulkan_func.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2KHR; - vma_vulkan_func.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR; - } - - if (is_extension_supported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) && is_enabled(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; - } - - allocator_info.pVulkanFunctions = &vma_vulkan_func; - - VkResult result = vmaCreateAllocator(&allocator_info, &memory_allocator); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Cannot create allocator"}; - } + vkb::allocated::init(*this); } CommandBuffer &Device::request_command_buffer() const diff --git a/framework/core/device.h b/framework/core/device.h index d4bb7b5903..58aa098479 100644 --- a/framework/core/device.h +++ b/framework/core/device.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors - * Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Arm Limited and Contributors + * Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -50,7 +50,7 @@ struct DriverVersion uint16_t patch; }; -class Device : public core::VulkanResource +class Device : public core::VulkanResource { public: /** @@ -87,8 +87,6 @@ class Device : public core::VulkanResource const PhysicalDevice &get_gpu() const; - VmaAllocator get_memory_allocator() const; - /** * @brief Returns the debug utils associated with this Device. */ @@ -128,9 +126,9 @@ class Device : public core::VulkanResource */ const Queue &get_suitable_graphics_queue() const; - bool is_extension_supported(const std::string &extension); + bool is_extension_supported(const std::string &extension) const; - bool is_enabled(const char *extension); + bool is_enabled(const char *extension) const; uint32_t get_queue_family_index(VkQueueFlagBits queue_flag); @@ -225,8 +223,6 @@ class Device : public core::VulkanResource std::vector enabled_extensions{}; - VmaAllocator memory_allocator{VK_NULL_HANDLE}; - std::vector> queues; /// A command pool associated to the primary queue diff --git a/framework/core/hpp_allocated.h b/framework/core/hpp_allocated.h new file mode 100644 index 0000000000..70de6006b1 --- /dev/null +++ b/framework/core/hpp_allocated.h @@ -0,0 +1,99 @@ +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024, Bradley Austin Davis. 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 "allocated.h" +#include "hpp_vulkan_resource.h" + +namespace vkb +{ +namespace allocated +{ + +template < + typename BuilderType, + typename CreateInfoType> +struct HPPBuilder : public Builder +{ + private: + using Parent = Builder; + + protected: + HPPBuilder(const HPPBuilder &other) = delete; + + HPPBuilder(const CreateInfoType &create_info) : + Parent(create_info) + {} + + public: + BuilderType &with_vma_required_flags(const vk::MemoryPropertyFlags &flags) + { + Parent::alloc_create_info.requiredFlags = flags.operator VkMemoryPropertyFlags(); + return *static_cast(this); + } + + BuilderType &with_vma_preferred_flags(const vk::MemoryPropertyFlags &flags) + { + Parent::alloc_create_info.preferredFlags = flags.operator VkMemoryPropertyFlags(); + return *static_cast(this); + } + + BuilderType &with_sharing(vk::SharingMode sharingMode) + { + Parent::create_info.sharingMode = sharingMode; + return *static_cast(this); + } +}; + +template +class HPPAllocated : public Allocated> +{ + using Parent = Allocated>; + + public: + using Parent::get_handle; + using Parent::Parent; + using Parent::update; + + /** + * @brief Copies byte data into the buffer + * @param data The data to copy from + * @param offset The offset to start the copying into the mapped data + */ + template + vk::DeviceSize update(const vk::ArrayProxy &data, size_t offset = 0) + { + return Parent::update(static_cast(data.data()), data.size() * sizeof(T), offset); + } + + /** + * @brief Copies byte data into the buffer + * @param data The data to copy from + * @param count The number of array elements + * @param offset The offset to start the copying into the mapped data + */ + template + vk::DeviceSize update_from_array(const T *data, size_t count, size_t offset = 0) + { + return update(vk::ArrayProxy{data, count}, offset); + } +}; + +} // namespace allocated +} // namespace vkb diff --git a/framework/core/hpp_buffer.cpp b/framework/core/hpp_buffer.cpp index 6c8744fedd..0758425630 100644 --- a/framework/core/hpp_buffer.cpp +++ b/framework/core/hpp_buffer.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -23,79 +23,56 @@ namespace vkb { namespace core { -HPPBuffer::HPPBuffer(vkb::core::HPPDevice &device, - vk::DeviceSize size_, - vk::BufferUsageFlags buffer_usage, - VmaMemoryUsage memory_usage, - VmaAllocationCreateFlags flags, - const std::vector &queue_family_indices) : - HPPVulkanResource(nullptr, &device), size(size_) -{ -#ifdef VK_USE_PLATFORM_METAL_EXT - // Workaround for Mac (MoltenVK requires unmapping https://github.com/KhronosGroup/MoltenVK/issues/175) - // Force cleares the flag VMA_ALLOCATION_CREATE_MAPPED_BIT - flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; -#endif - - persistent = (flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; - vk::BufferCreateInfo buffer_create_info({}, size, buffer_usage); - if (queue_family_indices.size() >= 2) - { - buffer_create_info.sharingMode = vk::SharingMode::eConcurrent; - buffer_create_info.queueFamilyIndexCount = static_cast(queue_family_indices.size()); - buffer_create_info.pQueueFamilyIndices = queue_family_indices.data(); - } - - VmaAllocationCreateInfo memory_info{}; - memory_info.flags = flags; - memory_info.usage = memory_usage; - - VmaAllocationInfo allocation_info{}; - auto result = vmaCreateBuffer(device.get_memory_allocator(), - reinterpret_cast(&buffer_create_info), &memory_info, - reinterpret_cast(&get_handle()), &allocation, - &allocation_info); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Cannot create HPPBuffer"}; - } - - memory = static_cast(allocation_info.deviceMemory); +HPPBuffer HPPBuffer::create_staging_buffer(HPPDevice &device, vk::DeviceSize size, const void *data) +{ + HPPBufferBuilder builder{size}; + builder + .with_usage(vk::BufferUsageFlagBits::eTransferSrc) + .with_vma_flags(VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - if (persistent) + HPPBuffer staging_buffer{device, builder}; + if (data != nullptr) { - mapped_data = static_cast(allocation_info.pMappedData); + staging_buffer.update(static_cast(data), size); } + return staging_buffer; } -HPPBuffer::HPPBuffer(HPPBuffer &&other) : - HPPVulkanResource{other.get_handle(), &other.get_device()}, - allocation(std::exchange(other.allocation, {})), - memory(std::exchange(other.memory, {})), - size(std::exchange(other.size, {})), - mapped_data(std::exchange(other.mapped_data, {})), - mapped(std::exchange(other.mapped, {})) +HPPBuffer::HPPBuffer(vkb::core::HPPDevice &device, + vk::DeviceSize size_, + vk::BufferUsageFlags buffer_usage, + VmaMemoryUsage memory_usage, + VmaAllocationCreateFlags flags, + const std::vector &queue_family_indices) : + HPPBuffer(device, + HPPBufferBuilder{size_} + .with_usage(buffer_usage) + .with_vma_flags(flags) + .with_vma_usage(memory_usage) + .with_queue_families(queue_family_indices) + .with_implicit_sharing_mode()) {} -HPPBuffer::~HPPBuffer() +HPPBuffer::HPPBuffer(vkb::core::HPPDevice &device, + HPPBufferBuilder const &builder) : + Parent{builder.alloc_create_info, nullptr, &device}, size(builder.create_info.size) { - if (get_handle() && (allocation != VK_NULL_HANDLE)) + get_handle() = create_buffer(builder.create_info.operator const VkBufferCreateInfo &()); + if (!builder.debug_name.empty()) { - unmap(); - vmaDestroyBuffer(get_device().get_memory_allocator(), static_cast(get_handle()), allocation); + set_debug_name(builder.debug_name); } } -VmaAllocation HPPBuffer::get_allocation() const -{ - return allocation; -} +HPPBuffer::HPPBuffer(HPPBuffer &&other) noexcept : + HPPAllocated{static_cast(other)}, + size(std::exchange(other.size, {})) +{} -vk::DeviceMemory HPPBuffer::get_memory() const +HPPBuffer::~HPPBuffer() { - return memory; + destroy_buffer(); } vk::DeviceSize HPPBuffer::get_size() const @@ -103,66 +80,10 @@ vk::DeviceSize HPPBuffer::get_size() const return size; } -const uint8_t *HPPBuffer::get_data() const -{ - return mapped_data; -} - -uint8_t *HPPBuffer::map() -{ - if (!mapped && !mapped_data) - { - VK_CHECK(vmaMapMemory(get_device().get_memory_allocator(), allocation, reinterpret_cast(&mapped_data))); - mapped = true; - } - return mapped_data; -} - -void HPPBuffer::unmap() -{ - if (mapped) - { - vmaUnmapMemory(get_device().get_memory_allocator(), allocation); - mapped_data = nullptr; - mapped = false; - } -} - -void HPPBuffer::flush() -{ - vmaFlushAllocation(get_device().get_memory_allocator(), allocation, 0, size); -} - -void HPPBuffer::update(const std::vector &data, size_t offset) -{ - update(data.data(), data.size(), offset); -} - uint64_t HPPBuffer::get_device_address() const { return get_device().get_handle().getBufferAddressKHR({get_handle()}); } -void HPPBuffer::update(void const *data, size_t size, size_t offset) -{ - update(reinterpret_cast(data), size, offset); -} - -void HPPBuffer::update(const uint8_t *data, const size_t size, const size_t offset) -{ - if (persistent) - { - std::copy(data, data + size, mapped_data + offset); - flush(); - } - else - { - map(); - std::copy(data, data + size, mapped_data + offset); - flush(); - unmap(); - } -} - } // namespace core } // namespace vkb diff --git a/framework/core/hpp_buffer.h b/framework/core/hpp_buffer.h index 4aa899c966..8b5f4e93a6 100644 --- a/framework/core/hpp_buffer.h +++ b/framework/core/hpp_buffer.h @@ -17,18 +17,55 @@ #pragma once +#include "allocated.h" +#include "buffer.h" +#include "common/hpp_error.h" +#include "hpp_allocated.h" #include "hpp_vulkan_resource.h" - #include -#include namespace vkb { namespace core { -class HPPBuffer : public vkb::core::HPPVulkanResource + +struct HPPBufferBuilder : public allocated::HPPBuilder +{ + private: + using Parent = HPPBuilder; + + public: + HPPBufferBuilder(vk::DeviceSize size) : + HPPBuilder(vk::BufferCreateInfo{{}, size}) + { + } + + HPPBufferBuilder &with_usage(vk::BufferUsageFlags usage) + { + create_info.usage = usage; + return *this; + } + + HPPBufferBuilder &with_flags(vk::BufferCreateFlags flags) + { + create_info.flags = flags; + return *this; + } +}; + +class HPPBuffer : public allocated::HPPAllocated { + using Parent = allocated::HPPAllocated; + public: + static HPPBuffer create_staging_buffer(HPPDevice &device, vk::DeviceSize size, const void *data); + + template + static HPPBuffer create_staging_buffer(HPPDevice &device, std::vector const &data) + { + return create_staging_buffer(device, data.size() * sizeof(T), data.data()); + } + /** * @brief Creates a buffer using VMA * @param device A valid Vulkan device @@ -38,25 +75,25 @@ class HPPBuffer : public vkb::core::HPPVulkanResource * @param flags The allocation create flags * @param queue_family_indices optional queue family indices */ - HPPBuffer(vkb::core::HPPDevice &device, + // [[deprecated("Use the HPPBufferBuilder ctor instead")]] + HPPBuffer(HPPDevice &device, vk::DeviceSize size, vk::BufferUsageFlags 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 = {}); + HPPBuffer(vkb::core::HPPDevice &device, + HPPBufferBuilder const &builder); + HPPBuffer(const HPPBuffer &) = delete; - HPPBuffer(HPPBuffer &&other); + HPPBuffer(HPPBuffer &&other) noexcept; ~HPPBuffer(); HPPBuffer &operator=(const HPPBuffer &) = delete; HPPBuffer &operator=(HPPBuffer &&) = delete; - VmaAllocation get_allocation() const; - const uint8_t *get_data() const; - vk::DeviceMemory get_memory() const; - /** * @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) */ @@ -67,69 +104,9 @@ class HPPBuffer : public vkb::core::HPPVulkanResource */ vk::DeviceSize get_size() const; - /** - * @brief Flushes memory if it is HOST_VISIBLE and not HOST_COHERENT - */ - void flush(); - - /** - * @brief Maps vulkan memory if it isn't already mapped to an host visible address - * @return Pointer to host visible memory - */ - uint8_t *map(); - - /** - * @brief Unmaps vulkan memory from the host visible address - */ - void unmap(); - - /** - * @brief Copies byte data into the buffer - * @param data The data to copy from - * @param size The amount of bytes to copy - * @param offset The offset to start the copying into the mapped data - */ - void update(const uint8_t *data, size_t size, size_t offset = 0); - - /** - * @brief Converts any non byte data into bytes and then updates the buffer - * @param data The data to copy from - * @param size The amount of bytes to copy - * @param offset The offset to start the copying into the mapped data - */ - void update(void const *data, size_t size, size_t offset = 0); - - /** - * @brief Copies a vector of bytes into the buffer - * @param data The data vector to upload - * @param offset The offset to start the copying into the mapped data - */ - void update(const std::vector &data, size_t offset = 0); - - template - void update(std::vector const &data, size_t offset = 0) - { - update(data.data(), data.size() * sizeof(T), offset); - } - - /** - * @brief Copies an object as byte data into the buffer - * @param object The object to convert into byte data - * @param offset The offset to start the copying into the mapped data - */ - template - void convert_and_update(const T &object, size_t offset = 0) - { - update(reinterpret_cast(&object), sizeof(T), offset); - } - private: - VmaAllocation allocation = VK_NULL_HANDLE; - vk::DeviceMemory memory = nullptr; - vk::DeviceSize size = 0; - uint8_t *mapped_data = nullptr; - bool persistent = false; // Whether the buffer is persistently mapped or not - bool mapped = false; // Whether the buffer has been mapped with vmaMapMemory + vk::DeviceSize size = 0; }; + } // namespace core } // namespace vkb diff --git a/framework/core/hpp_device.cpp b/framework/core/hpp_device.cpp index 2e4c49b14d..7ce71f559c 100644 --- a/framework/core/hpp_device.cpp +++ b/framework/core/hpp_device.cpp @@ -180,53 +180,7 @@ HPPDevice::HPPDevice(vkb::core::HPPPhysicalDevice &gpu, } } - VmaVulkanFunctions vma_vulkan_func{}; - vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr; - vma_vulkan_func.vkGetDeviceProcAddr = reinterpret_cast(get_handle().getProcAddr("vkGetDeviceProcAddr")); - - VmaAllocatorCreateInfo allocator_info{}; - allocator_info.physicalDevice = static_cast(gpu.get_handle()); - allocator_info.device = static_cast(get_handle()); - allocator_info.instance = static_cast(gpu.get_instance().get_handle()); - - if (can_get_memory_requirements && has_dedicated_allocation) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - } - - if (is_extension_supported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) && is_enabled(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; - } - - if (is_extension_supported(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) && is_enabled(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; - } - - if (is_extension_supported(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) && is_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT; - } - - if (is_extension_supported(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) && is_enabled(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT; - } - - if (is_extension_supported(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) && is_enabled(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME)) - { - allocator_info.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT; - } - - allocator_info.pVulkanFunctions = &vma_vulkan_func; - - VkResult result = vmaCreateAllocator(&allocator_info, &memory_allocator); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Cannot create allocator"}; - } + vkb::allocated::init(*this); command_pool = std::make_unique( *this, get_queue_by_flags(vk::QueueFlagBits::eGraphics | vk::QueueFlagBits::eCompute, 0).get_family_index()); @@ -240,15 +194,7 @@ HPPDevice::~HPPDevice() command_pool.reset(); fence_pool.reset(); - if (memory_allocator != VK_NULL_HANDLE) - { - VmaTotalStatistics stats; - vmaCalculateStatistics(memory_allocator, &stats); - - LOGI("Total device memory leaked: {} bytes.", stats.total.statistics.allocationBytes); - - vmaDestroyAllocator(memory_allocator); - } + vkb::allocated::shutdown(); if (get_handle()) { @@ -275,11 +221,6 @@ vkb::core::HPPPhysicalDevice const &HPPDevice::get_gpu() const return gpu; } -VmaAllocator const &HPPDevice::get_memory_allocator() const -{ - return memory_allocator; -} - vkb::core::HPPDebugUtils const &HPPDevice::get_debug_utils() const { return *debug_utils; diff --git a/framework/core/hpp_device.h b/framework/core/hpp_device.h index 5bbfdf9d58..342a2f106e 100644 --- a/framework/core/hpp_device.h +++ b/framework/core/hpp_device.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -60,8 +60,6 @@ class HPPDevice : public vkb::core::HPPVulkanResource vkb::core::HPPPhysicalDevice const &get_gpu() const; - VmaAllocator const &get_memory_allocator() const; - /** * @brief Returns the debug utils associated with this HPPDevice. */ @@ -139,8 +137,6 @@ class HPPDevice : public vkb::core::HPPVulkanResource std::vector enabled_extensions{}; - VmaAllocator memory_allocator{VK_NULL_HANDLE}; - std::vector> queues; /// A command pool associated to the primary queue diff --git a/framework/core/hpp_image.cpp b/framework/core/hpp_image.cpp index 5e6f27363f..eb52188207 100644 --- a/framework/core/hpp_image.cpp +++ b/framework/core/hpp_image.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -55,48 +55,27 @@ HPPImage::HPPImage(HPPDevice &device, vk::ImageCreateFlags flags, uint32_t num_queue_families, const uint32_t *queue_families) : - HPPVulkanResource{nullptr, &device}, - type{find_image_type(extent)}, - extent{extent}, - format{format}, - sample_count{sample_count}, - usage{image_usage}, - array_layer_count{array_layers}, - tiling{tiling} -{ - assert(0 < mip_levels && "HPPImage should have at least one level"); - assert(0 < array_layers && "HPPImage should have at least one layer"); - - subresource.mipLevel = mip_levels; - subresource.arrayLayer = array_layers; - - vk::ImageCreateInfo image_info(flags, type, format, extent, mip_levels, array_layers, sample_count, tiling, image_usage); - - if (num_queue_families != 0) - { - image_info.sharingMode = vk::SharingMode::eConcurrent; - image_info.queueFamilyIndexCount = num_queue_families; - image_info.pQueueFamilyIndices = queue_families; - } - - VmaAllocationCreateInfo memory_info{}; - memory_info.usage = memory_usage; - - if (image_usage & vk::ImageUsageFlagBits::eTransientAttachment) - { - memory_info.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - } - - auto result = vmaCreateImage(device.get_memory_allocator(), - reinterpret_cast(&image_info), - &memory_info, - const_cast(reinterpret_cast(&get_handle())), - &memory, - nullptr); - - if (result != VK_SUCCESS) + HPPImage{device, + HPPImageBuilder{extent} + .with_format(format) + .with_mip_levels(mip_levels) + .with_array_layers(array_layers) + .with_sample_count(sample_count) + .with_tiling(tiling) + .with_flags(flags) + .with_usage(image_usage) + .with_queue_families(num_queue_families, queue_families)} +{} + +HPPImage::HPPImage(HPPDevice &device, HPPImageBuilder const &builder) : + HPPAllocated{builder.alloc_create_info, nullptr, &device}, create_info{builder.create_info} +{ + get_handle() = create_image(create_info.operator const VkImageCreateInfo &()); + subresource.arrayLayer = create_info.arrayLayers; + subresource.mipLevel = create_info.mipLevels; + if (!builder.debug_name.empty()) { - throw VulkanException{result, "Cannot create HPPImage"}; + set_debug_name(builder.debug_name); } } @@ -106,25 +85,23 @@ HPPImage::HPPImage(HPPDevice &device, vk::Format format, vk::ImageUsageFlags image_usage, vk::SampleCountFlagBits sample_count) : - HPPVulkanResource{handle, &device}, type{find_image_type(extent)}, extent{extent}, format{format}, sample_count{sample_count}, usage{image_usage} + HPPAllocated{handle, &device} { - subresource.mipLevel = 1; - subresource.arrayLayer = 1; + create_info.samples = sample_count; + create_info.format = format; + create_info.extent = extent; + create_info.imageType = find_image_type(extent); + create_info.arrayLayers = 1; + create_info.mipLevels = 1; + subresource.mipLevel = 1; + subresource.arrayLayer = 1; } -HPPImage::HPPImage(HPPImage &&other) : - HPPVulkanResource{std::move(other)}, - memory(std::exchange(other.memory, {})), - type(std::exchange(other.type, {})), - extent(std::exchange(other.extent, {})), - format(std::exchange(other.format, {})), - sample_count(std::exchange(other.sample_count, {})), - usage(std::exchange(other.usage, {})), - tiling(std::exchange(other.tiling, {})), +HPPImage::HPPImage(HPPImage &&other) noexcept : + HPPAllocated{std::move(other)}, + create_info(std::exchange(other.create_info, {})), subresource(std::exchange(other.subresource, {})), - views(std::exchange(other.views, {})), - mapped_data(std::exchange(other.mapped_data, {})), - mapped(std::exchange(other.mapped, {})) + views(std::exchange(other.views, {})) { // Update image views references to this image to avoid dangling pointers for (auto &view : views) @@ -135,70 +112,46 @@ HPPImage::HPPImage(HPPImage &&other) : HPPImage::~HPPImage() { - if (get_handle() && memory) - { - unmap(); - vmaDestroyImage(get_device().get_memory_allocator(), static_cast(get_handle()), memory); - } -} - -VmaAllocation HPPImage::get_memory() const -{ - return memory; + destroy_image(); } uint8_t *HPPImage::map() { - if (!mapped_data) - { - if (tiling != vk::ImageTiling::eLinear) - { - LOGW("Mapping image memory that is not linear"); - } - VK_CHECK(vmaMapMemory(get_device().get_memory_allocator(), memory, reinterpret_cast(&mapped_data))); - mapped = true; - } - return mapped_data; -} - -void HPPImage::unmap() -{ - if (mapped) + if (create_info.tiling != vk::ImageTiling::eLinear) { - vmaUnmapMemory(get_device().get_memory_allocator(), memory); - mapped_data = nullptr; - mapped = false; + LOGW("Mapping image memory that is not linear"); } + return Allocated::map(); } vk::ImageType HPPImage::get_type() const { - return type; + return create_info.imageType; } const vk::Extent3D &HPPImage::get_extent() const { - return extent; + return create_info.extent; } vk::Format HPPImage::get_format() const { - return format; + return create_info.format; } vk::SampleCountFlagBits HPPImage::get_sample_count() const { - return sample_count; + return create_info.samples; } vk::ImageUsageFlags HPPImage::get_usage() const { - return usage; + return create_info.usage; } vk::ImageTiling HPPImage::get_tiling() const { - return tiling; + return create_info.tiling; } vk::ImageSubresource HPPImage::get_subresource() const @@ -208,7 +161,7 @@ vk::ImageSubresource HPPImage::get_subresource() const uint32_t HPPImage::get_array_layer_count() const { - return array_layer_count; + return create_info.arrayLayers; } std::unordered_set &HPPImage::get_views() diff --git a/framework/core/hpp_image.h b/framework/core/hpp_image.h index 39277d6a1c..038337d7d2 100644 --- a/framework/core/hpp_image.h +++ b/framework/core/hpp_image.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -18,8 +18,8 @@ #pragma once #include "core/hpp_vulkan_resource.h" +#include "hpp_allocated.h" #include -#include namespace vkb { @@ -28,7 +28,87 @@ namespace core class HPPDevice; class HPPImageView; -class HPPImage : public vkb::core::HPPVulkanResource +struct HPPImageBuilder : public allocated::HPPBuilder +{ + private: + using Parent = allocated::HPPBuilder; + + public: + HPPImageBuilder(vk::Extent3D const &extent) : + // Better reasonable defaults than vk::ImageCreateInfo default ctor + Parent(vk::ImageCreateInfo{{}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm, extent, 1, 1}) + { + } + + HPPImageBuilder(vk::Extent2D const &extent) : + HPPImageBuilder(vk::Extent3D{extent.width, extent.height, 1}) + { + } + + HPPImageBuilder(uint32_t width, uint32_t height = 1, uint32_t depth = 1) : + HPPImageBuilder(vk::Extent3D{width, height, depth}) + { + } + + HPPImageBuilder &with_format(vk::Format format) + { + create_info.format = format; + return *this; + } + + HPPImageBuilder &with_image_type(vk::ImageType type) + { + create_info.imageType = type; + return *this; + } + + HPPImageBuilder &with_array_layers(uint32_t layers) + { + create_info.arrayLayers = layers; + return *this; + } + + HPPImageBuilder &with_mip_levels(uint32_t levels) + { + create_info.mipLevels = levels; + return *this; + } + + HPPImageBuilder &with_sample_count(vk::SampleCountFlagBits sample_count) + { + create_info.samples = sample_count; + return *this; + } + + HPPImageBuilder &with_tiling(vk::ImageTiling tiling) + { + create_info.tiling = tiling; + return *this; + } + + HPPImageBuilder &with_usage(vk::ImageUsageFlags usage) + { + create_info.usage = usage; + return *this; + } + + HPPImageBuilder &with_flags(vk::ImageCreateFlags flags) + { + create_info.flags = flags; + return *this; + } + + HPPImageBuilder &with_implicit_sharing_mode() + { + if (create_info.queueFamilyIndexCount != 0) + { + create_info.sharingMode = vk::SharingMode::eConcurrent; + } + return *this; + } +}; + +class HPPImage : public allocated::HPPAllocated { public: HPPImage(HPPDevice &device, @@ -38,42 +118,38 @@ class HPPImage : public vkb::core::HPPVulkanResource vk::ImageUsageFlags image_usage, vk::SampleCountFlagBits sample_count = vk::SampleCountFlagBits::e1); - HPPImage(HPPDevice &device, - const vk::Extent3D &extent, - vk::Format format, - vk::ImageUsageFlags image_usage, - VmaMemoryUsage memory_usage, - vk::SampleCountFlagBits sample_count = vk::SampleCountFlagBits::e1, - uint32_t mip_levels = 1, - uint32_t array_layers = 1, - vk::ImageTiling tiling = vk::ImageTiling::eOptimal, - vk::ImageCreateFlags flags = {}, - uint32_t num_queue_families = 0, - const uint32_t *queue_families = nullptr); + [[deprecated("Use the HPPImageBuilder ctor instead")]] HPPImage(HPPDevice &device, + const vk::Extent3D &extent, + vk::Format format, + vk::ImageUsageFlags image_usage, + VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_AUTO, + vk::SampleCountFlagBits sample_count = vk::SampleCountFlagBits::e1, + uint32_t mip_levels = 1, + uint32_t array_layers = 1, + vk::ImageTiling tiling = vk::ImageTiling::eOptimal, + vk::ImageCreateFlags flags = {}, + uint32_t num_queue_families = 0, + const uint32_t *queue_families = nullptr); + + HPPImage(HPPDevice &device, + HPPImageBuilder const &builder); HPPImage(const HPPImage &) = delete; - HPPImage(HPPImage &&other); + HPPImage(HPPImage &&other) noexcept; - ~HPPImage() override; + ~HPPImage(); HPPImage &operator=(const HPPImage &) = delete; HPPImage &operator=(HPPImage &&) = delete; - VmaAllocation get_memory() const; - /** * @brief Maps vulkan memory to an host visible address * @return Pointer to host visible memory */ uint8_t *map(); - /** - * @brief Unmaps vulkan memory from the host visible address - */ - void unmap(); - vk::ImageType get_type() const; const vk::Extent3D &get_extent() const; vk::Format get_format() const; @@ -85,18 +161,9 @@ class HPPImage : public vkb::core::HPPVulkanResource std::unordered_set &get_views(); private: - VmaAllocation memory = VK_NULL_HANDLE; - vk::ImageType type; - vk::Extent3D extent; - vk::Format format; - vk::ImageUsageFlags usage; - vk::SampleCountFlagBits sample_count; - vk::ImageTiling tiling; + vk::ImageCreateInfo create_info; vk::ImageSubresource subresource; - uint32_t array_layer_count = 0; std::unordered_set views; /// HPPImage views referring to this image - uint8_t *mapped_data = nullptr; - bool mapped = false; /// Whether it was mapped with vmaMapMemory }; } // namespace core } // namespace vkb diff --git a/framework/core/image.cpp b/framework/core/image.cpp index 81878d06cf..af37330369 100644 --- a/framework/core/image.cpp +++ b/framework/core/image.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -67,6 +67,7 @@ inline VkImageType find_image_type(VkExtent3D extent) namespace core { + Image::Image(Device const &device, const VkExtent3D &extent, VkFormat format, @@ -79,88 +80,53 @@ Image::Image(Device const &device, VkImageCreateFlags flags, uint32_t num_queue_families, const uint32_t *queue_families) : - VulkanResource{VK_NULL_HANDLE, &device}, - type{find_image_type(extent)}, - extent{extent}, - format{format}, - sample_count{sample_count}, - usage{image_usage}, - array_layer_count{array_layers}, - tiling{tiling} -{ - assert(mip_levels > 0 && "Image should have at least one level"); - assert(array_layers > 0 && "Image should have at least one layer"); - - subresource.mipLevel = mip_levels; - subresource.arrayLayer = array_layers; - - VkImageCreateInfo image_info{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; - image_info.flags = flags; - image_info.imageType = type; - image_info.format = format; - image_info.extent = extent; - image_info.mipLevels = mip_levels; - image_info.arrayLayers = array_layers; - image_info.samples = sample_count; - image_info.tiling = tiling; - image_info.usage = image_usage; - - if (num_queue_families != 0) - { - image_info.sharingMode = VK_SHARING_MODE_CONCURRENT; - image_info.queueFamilyIndexCount = num_queue_families; - image_info.pQueueFamilyIndices = queue_families; - } - - VmaAllocationCreateInfo memory_info{}; - memory_info.usage = memory_usage; - - if (image_usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) - { - memory_info.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - } - - auto result = vmaCreateImage(device.get_memory_allocator(), - &image_info, &memory_info, - &handle, &memory, - nullptr); - - if (result != VK_SUCCESS) + // Pass through to the ImageBuilder ctor + Image(device, + ImageBuilder(extent) + .with_format(format) + .with_image_type(find_image_type(extent)) + .with_usage(image_usage) + .with_mip_levels(mip_levels) + .with_array_layers(array_layers) + .with_tiling(tiling) + .with_flags(flags) + .with_vma_usage(memory_usage) + .with_sample_count(sample_count) + .with_queue_families(num_queue_families, queue_families) + .with_implicit_sharing_mode()) +{ +} + +Image::Image(Device const &device, ImageBuilder const &builder) : + Allocated{builder.alloc_create_info, VK_NULL_HANDLE, &device}, create_info(builder.create_info) +{ + handle = create_image(create_info); + subresource.arrayLayer = create_info.arrayLayers; + subresource.mipLevel = create_info.mipLevels; + if (!builder.debug_name.empty()) { - throw VulkanException{result, "Cannot create Image"}; + set_debug_name(builder.debug_name); } } Image::Image(Device const &device, VkImage handle, const VkExtent3D &extent, VkFormat format, VkImageUsageFlags image_usage, VkSampleCountFlagBits sample_count) : - VulkanResource{handle, &device}, - type{find_image_type(extent)}, - extent{extent}, - format{format}, - sample_count{sample_count}, - usage{image_usage} -{ - subresource.mipLevel = 1; - subresource.arrayLayer = 1; + Allocated{handle, &device} +{ + create_info.extent = extent; + create_info.imageType = find_image_type(extent); + create_info.format = format; + create_info.samples = sample_count; + create_info.usage = image_usage; + subresource.arrayLayer = create_info.arrayLayers = 1; + subresource.mipLevel = create_info.mipLevels = 1; } -Image::Image(Image &&other) : - VulkanResource{std::move(other)}, - memory{other.memory}, - type{other.type}, - extent{other.extent}, - format{other.format}, - sample_count{other.sample_count}, - usage{other.usage}, - tiling{other.tiling}, - subresource{other.subresource}, - views(std::exchange(other.views, {})), - mapped_data{other.mapped_data}, - mapped{other.mapped} -{ - other.memory = VK_NULL_HANDLE; - other.mapped_data = nullptr; - other.mapped = false; - +Image::Image(Image &&other) noexcept : + Allocated{std::move(other)}, + create_info{std::exchange(other.create_info, {})}, + subresource{std::exchange(other.subresource, {})}, + views(std::exchange(other.views, {})) +{ // Update image views references to this image to avoid dangling pointers for (auto &view : views) { @@ -170,80 +136,47 @@ Image::Image(Image &&other) : Image::~Image() { - if (handle != VK_NULL_HANDLE && memory != VK_NULL_HANDLE) - { - unmap(); - vmaDestroyImage(device->get_memory_allocator(), handle, memory); - } -} - -VmaAllocation Image::get_memory() const -{ - return memory; -} - -uint8_t *Image::map() -{ - if (!mapped_data) - { - if (tiling != VK_IMAGE_TILING_LINEAR) - { - LOGW("Mapping image memory that is not linear"); - } - VK_CHECK(vmaMapMemory(device->get_memory_allocator(), memory, reinterpret_cast(&mapped_data))); - mapped = true; - } - return mapped_data; -} - -void Image::unmap() -{ - if (mapped) - { - vmaUnmapMemory(device->get_memory_allocator(), memory); - mapped_data = nullptr; - mapped = false; - } + destroy_image(); } VkImageType Image::get_type() const { - return type; + return create_info.imageType; } const VkExtent3D &Image::get_extent() const { - return extent; + return create_info.extent; } VkFormat Image::get_format() const { - return format; + return create_info.format; } VkSampleCountFlagBits Image::get_sample_count() const { - return sample_count; + return create_info.samples; } VkImageUsageFlags Image::get_usage() const { - return usage; + return create_info.usage; } VkImageTiling Image::get_tiling() const { - return tiling; + return create_info.tiling; } -VkImageSubresource Image::get_subresource() const +const VkImageSubresource &Image::get_subresource() const { return subresource; } uint32_t Image::get_array_layer_count() const { - return array_layer_count; + return create_info.arrayLayers; } std::unordered_set &Image::get_views() diff --git a/framework/core/image.h b/framework/core/image.h index 53af4ce668..2214c4b4e2 100644 --- a/framework/core/image.h +++ b/framework/core/image.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -21,6 +21,7 @@ #include "common/helpers.h" #include "common/vk_common.h" +#include "core/allocated.h" #include "core/vulkan_resource.h" namespace vkb @@ -29,33 +30,124 @@ class Device; namespace core { + +struct ImageBuilder : public allocated::Builder +{ + private: + using Parent = allocated::Builder; + + public: + ImageBuilder(VkExtent3D const &extent) : + Parent(VkImageCreateInfo{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr}) + { + create_info.extent = extent; + create_info.arrayLayers = 1; + create_info.mipLevels = 1; + create_info.imageType = VK_IMAGE_TYPE_2D; + create_info.format = VK_FORMAT_R8G8B8A8_UNORM; + create_info.samples = VK_SAMPLE_COUNT_1_BIT; + } + + ImageBuilder(uint32_t width, uint32_t height = 1, uint32_t depth = 1) : + ImageBuilder(VkExtent3D{width, height, depth}) + { + } + + ImageBuilder &with_format(VkFormat format) + { + create_info.format = format; + return *this; + } + + ImageBuilder &with_usage(VkImageUsageFlags usage) + { + create_info.usage = usage; + return *this; + } + + ImageBuilder &with_sharing_mode(VkSharingMode sharing_mode) + { + create_info.sharingMode = sharing_mode; + return *this; + } + + ImageBuilder &with_flags(VkImageCreateFlags flags) + { + create_info.flags = flags; + return *this; + } + + ImageBuilder &with_image_type(VkImageType type) + { + create_info.imageType = type; + return *this; + } + + ImageBuilder &with_array_layers(uint32_t layers) + { + create_info.arrayLayers = layers; + return *this; + } + + ImageBuilder &with_mip_levels(uint32_t levels) + { + create_info.mipLevels = levels; + return *this; + } + + ImageBuilder &with_sample_count(VkSampleCountFlagBits sample_count) + { + create_info.samples = sample_count; + return *this; + } + + ImageBuilder &with_tiling(VkImageTiling tiling) + { + create_info.tiling = tiling; + return *this; + } + + ImageBuilder &with_implicit_sharing_mode() + { + if (create_info.queueFamilyIndexCount != 0) + { + create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + } + return *this; + } +}; + class ImageView; -class Image : public VulkanResource +class Image : public allocated::Allocated { + VkImageCreateInfo create_info; + public: - Image(Device const & device, + Image(Device const &device, VkImage handle, - const VkExtent3D & extent, + const VkExtent3D &extent, VkFormat format, VkImageUsageFlags image_usage, VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT); - Image(Device const & device, - const VkExtent3D & extent, - VkFormat format, - VkImageUsageFlags image_usage, - VmaMemoryUsage memory_usage, - VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT, - uint32_t mip_levels = 1, - uint32_t array_layers = 1, - VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, - VkImageCreateFlags flags = 0, - uint32_t num_queue_families = 0, - const uint32_t * queue_families = nullptr); - + [[deprecated("Use the ImageBuilder ctor instead")]] Image(Device const &device, + const VkExtent3D &extent, + VkFormat format, + VkImageUsageFlags image_usage, + VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_AUTO, + VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT, + uint32_t mip_levels = 1, + uint32_t array_layers = 1, + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, + VkImageCreateFlags flags = 0, + uint32_t num_queue_families = 0, + const uint32_t *queue_families = nullptr); + + Image(Device const &device, + ImageBuilder const &builder); Image(const Image &) = delete; - Image(Image &&other); + Image(Image &&other) noexcept; ~Image() override; @@ -63,19 +155,6 @@ class Image : public VulkanResource Image &operator=(Image &&) = delete; - VmaAllocation get_memory() const; - - /** - * @brief Maps vulkan memory to an host visible address - * @return Pointer to host visible memory - */ - uint8_t *map(); - - /** - * @brief Unmaps vulkan memory from the host visible address - */ - void unmap(); - VkImageType get_type() const; const VkExtent3D &get_extent() const; @@ -88,38 +167,16 @@ class Image : public VulkanResource VkImageTiling get_tiling() const; - VkImageSubresource get_subresource() const; + const VkImageSubresource &get_subresource() const; uint32_t get_array_layer_count() const; std::unordered_set &get_views(); private: - VmaAllocation memory{VK_NULL_HANDLE}; - - VkImageType type{}; - - VkExtent3D extent{}; - - VkFormat format{}; - - VkImageUsageFlags usage{}; - - VkSampleCountFlagBits sample_count{}; - - VkImageTiling tiling{}; - - VkImageSubresource subresource{}; - - uint32_t array_layer_count{0}; - /// Image views referring to this image std::unordered_set views; - - uint8_t *mapped_data{nullptr}; - - /// Whether it was mapped with vmaMapMemory - bool mapped{false}; + VkImageSubresource subresource{}; }; } // namespace core } // namespace vkb diff --git a/framework/core/image_view.h b/framework/core/image_view.h index e6eb593eda..9b5a10e9fe 100644 --- a/framework/core/image_view.h +++ b/framework/core/image_view.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -26,7 +26,7 @@ namespace vkb { namespace core { -class ImageView : public VulkanResource +class ImageView : public VulkanResource { public: ImageView(Image &image, VkImageViewType view_type, VkFormat format = VK_FORMAT_UNDEFINED, diff --git a/framework/core/render_pass.h b/framework/core/render_pass.h index f83290d50d..8c60321acb 100644 --- a/framework/core/render_pass.h +++ b/framework/core/render_pass.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -43,13 +43,13 @@ struct SubpassInfo std::string debug_name; }; -class RenderPass : public core::VulkanResource +class RenderPass : public core::VulkanResource { public: - RenderPass(Device & device, - const std::vector & attachments, + RenderPass(Device &device, + const std::vector &attachments, const std::vector &load_store_infos, - const std::vector & subpasses); + const std::vector &subpasses); RenderPass(const RenderPass &) = delete; diff --git a/framework/core/sampler.h b/framework/core/sampler.h index e79c253954..66a099d64c 100644 --- a/framework/core/sampler.h +++ b/framework/core/sampler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -30,7 +30,7 @@ namespace core /** * @brief Represents a Vulkan Sampler */ -class Sampler : public VulkanResource +class Sampler : public VulkanResource { public: /** diff --git a/framework/core/scratch_buffer.cpp b/framework/core/scratch_buffer.cpp deleted file mode 100644 index 84816933f7..0000000000 --- a/framework/core/scratch_buffer.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2021, Sascha Willems - * - * 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. - */ - -#include "scratch_buffer.h" - -#include "device.h" - -namespace vkb -{ -namespace core -{ -ScratchBuffer::ScratchBuffer(Device &device, VkDeviceSize size) : - device{device}, - size{size} -{ - VkBufferCreateInfo buffer_info{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - buffer_info.size = size; - - VmaAllocationCreateInfo memory_info{}; - memory_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; - - VmaAllocationInfo allocation_info{}; - auto result = vmaCreateBuffer(device.get_memory_allocator(), - &buffer_info, &memory_info, - &handle, &allocation, - &allocation_info); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Could not create Scratchbuffer"}; - } - - memory = allocation_info.deviceMemory; - - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = handle; - device_address = vkGetBufferDeviceAddressKHR(device.get_handle(), &buffer_device_address_info); -} - -ScratchBuffer::~ScratchBuffer() -{ - if (handle != VK_NULL_HANDLE && allocation != VK_NULL_HANDLE) - { - vmaDestroyBuffer(device.get_memory_allocator(), handle, allocation); - } -} - -VkBuffer ScratchBuffer::get_handle() const -{ - return handle; -} - -uint64_t ScratchBuffer::get_device_address() const -{ - return device_address; -} -} // namespace core -} // namespace vkb diff --git a/framework/core/scratch_buffer.h b/framework/core/scratch_buffer.h deleted file mode 100644 index a0df565109..0000000000 --- a/framework/core/scratch_buffer.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) 2023, Sascha Willems - * - * 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 "common/helpers.h" -#include "common/vk_common.h" - -namespace vkb -{ -class Device; - -namespace core -{ -/** - * @brief A simplified buffer class for creating temporary device local scratch buffers, used in e.g. ray tracing - */ -class ScratchBuffer -{ - public: - /** - * @brief Creates a scratch buffer using VMA with pre-defined usage flags - * @param device A valid Vulkan device - * @param size The size in bytes of the buffer - */ - ScratchBuffer(Device & device, - VkDeviceSize size); - - ~ScratchBuffer(); - - VkBuffer get_handle() const; - - uint64_t get_device_address() const; - - /** - * @return The size of the buffer - */ - VkDeviceSize get_size() const - { - return size; - } - - private: - Device &device; - - uint64_t device_address{0}; - - VkBuffer handle{VK_NULL_HANDLE}; - - VmaAllocation allocation{VK_NULL_HANDLE}; - - VkDeviceMemory memory{VK_NULL_HANDLE}; - - VkDeviceSize size{0}; -}; -} // namespace core -} // namespace vkb \ No newline at end of file diff --git a/framework/core/shader_binding_table.cpp b/framework/core/shader_binding_table.cpp deleted file mode 100644 index eb2fe55755..0000000000 --- a/framework/core/shader_binding_table.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (c) 2021, Sascha Willems - * - * 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. - */ - -#include "shader_binding_table.h" - -#include "device.h" - -namespace vkb -{ -namespace core -{ -ShaderBindingTable::ShaderBindingTable(Device & device, - uint32_t handle_count, - VkDeviceSize handle_size_aligned, - VmaMemoryUsage memory_usage) : - device{device} -{ - VkBufferCreateInfo buffer_info{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - buffer_info.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - buffer_info.size = handle_count * handle_size_aligned; - - VmaAllocationCreateInfo memory_info{}; - memory_info.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - memory_info.usage = memory_usage; - - VmaAllocationInfo allocation_info{}; - auto result = vmaCreateBuffer(device.get_memory_allocator(), - &buffer_info, &memory_info, - &handle, &allocation, - &allocation_info); - - if (result != VK_SUCCESS) - { - throw VulkanException{result, "Could not create ShaderBindingTable"}; - } - - memory = allocation_info.deviceMemory; - - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = handle; - strided_device_address_region.deviceAddress = vkGetBufferDeviceAddressKHR(device.get_handle(), &buffer_device_address_info); - strided_device_address_region.stride = handle_size_aligned; - strided_device_address_region.size = handle_count * handle_size_aligned; - - mapped_data = static_cast(allocation_info.pMappedData); -} - -ShaderBindingTable::~ShaderBindingTable() -{ - if (handle != VK_NULL_HANDLE && allocation != VK_NULL_HANDLE) - { - vmaDestroyBuffer(device.get_memory_allocator(), handle, allocation); - } -} - -const VkStridedDeviceAddressRegionKHR *vkb::core::ShaderBindingTable::get_strided_device_address_region() const -{ - return &strided_device_address_region; -} -uint8_t *ShaderBindingTable::get_data() const -{ - return mapped_data; -} -} // namespace core -} // namespace vkb diff --git a/framework/core/shader_binding_table.h b/framework/core/shader_binding_table.h deleted file mode 100644 index c822d2e931..0000000000 --- a/framework/core/shader_binding_table.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2021, Sascha Willems - * - * 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 "common/helpers.h" -#include "common/vk_common.h" - -namespace vkb -{ -class Device; - -namespace core -{ -/** - * @brief Extended buffer class to simplify ray tracing shader binding table usage - */ -class ShaderBindingTable -{ - public: - /** - * @brief Creates a shader binding table - * @param device A valid Vulkan device - * @param handle_count Shader group handle count - * @param handle_size_aligned Aligned shader group handle size - * @param memory_usage The memory usage of the shader binding table - */ - ShaderBindingTable(Device & device, - uint32_t handle_count, - VkDeviceSize handle_size_aligned, - VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU); - - ~ShaderBindingTable(); - - const VkStridedDeviceAddressRegionKHR *get_strided_device_address_region() const; - - uint8_t *get_data() const; - - private: - Device &device; - - VkStridedDeviceAddressRegionKHR strided_device_address_region{}; - - uint64_t device_address{0}; - - VkBuffer handle{VK_NULL_HANDLE}; - - VmaAllocation allocation{VK_NULL_HANDLE}; - - VkDeviceMemory memory{VK_NULL_HANDLE}; - - uint8_t *mapped_data{nullptr}; -}; -} // namespace core -} // namespace vkb \ No newline at end of file diff --git a/framework/core/vulkan_resource.h b/framework/core/vulkan_resource.h index e20f4b6a43..8d8b06a632 100644 --- a/framework/core/vulkan_resource.h +++ b/framework/core/vulkan_resource.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, Arm Limited and Contributors +/* Copyright (c) 2021-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -33,11 +33,60 @@ namespace detail void set_debug_name(const Device *device, VkObjectType object_type, uint64_t handle, const char *debug_name); } +template +constexpr VkObjectType get_object_type(const HandleType &handle) +{ + throw std::runtime_error("Unknown handle type"); + return static_cast(-1); +} + +template <> +constexpr VkObjectType get_object_type(const VkImage &handle) +{ + return VK_OBJECT_TYPE_IMAGE; +} + +template <> +constexpr VkObjectType get_object_type(const VkImageView &handle) +{ + return VK_OBJECT_TYPE_IMAGE_VIEW; +} + +template <> +constexpr VkObjectType get_object_type(const VkRenderPass &handle) +{ + return VK_OBJECT_TYPE_RENDER_PASS; +} + +template <> +constexpr VkObjectType get_object_type(const VkSampler &handle) +{ + return VK_OBJECT_TYPE_SAMPLER; +} + +template <> +constexpr VkObjectType get_object_type(const VkBuffer &handle) +{ + return VK_OBJECT_TYPE_BUFFER; +} + +template <> +constexpr VkObjectType get_object_type(const VkDevice &handle) +{ + return VK_OBJECT_TYPE_DEVICE; +} + +template <> +constexpr VkObjectType get_object_type(const VkCommandBuffer &handle) +{ + return VK_OBJECT_TYPE_COMMAND_BUFFER; +} + /// Inherit this for any Vulkan object with a handle of type `THandle`. /// /// This allows the derived class to store a Vulkan handle, and also a pointer to the parent Device. /// It also allow for adding debug data to any Vulkan object. -template +template class VulkanResource { public: @@ -46,7 +95,7 @@ class VulkanResource { } - VulkanResource(const VulkanResource &) = delete; + VulkanResource(const VulkanResource &) = delete; VulkanResource &operator=(const VulkanResource &) = delete; VulkanResource(VulkanResource &&other) : @@ -70,9 +119,9 @@ class VulkanResource virtual ~VulkanResource() = default; - inline VkObjectType get_object_type() const + constexpr VkObjectType get_object_type() const { - return OBJECT_TYPE; + return vkb::core::get_object_type(handle); } inline Device &get_device() const @@ -104,12 +153,12 @@ class VulkanResource inline void set_debug_name(const std::string &name) { debug_name = name; - detail::set_debug_name(device, OBJECT_TYPE, get_handle_u64(), debug_name.c_str()); + detail::set_debug_name(device, get_object_type(), get_handle_u64(), debug_name.c_str()); } protected: THandle handle; - Device * device; + Device *device; std::string debug_name; }; diff --git a/framework/gltf_loader.cpp b/framework/gltf_loader.cpp index 6e6eddc27d..6765c4d9bf 100644 --- a/framework/gltf_loader.cpp +++ b/framework/gltf_loader.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors - * Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2018-2024, Arm Limited and Contributors + * Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -349,7 +349,9 @@ inline void prepare_meshlets(std::vector &meshlets, std::unique_ptr(index_data.data()) + i); if (vertices.insert(meshlet.indices[meshlet.index_count]).second) + { ++meshlet.vertex_count; + } meshlet.index_count++; triangle_check = triangle_check < 3 ? ++triangle_check : 1; @@ -358,7 +360,9 @@ inline void prepare_meshlets(std::vector &meshlets, std::unique_ptrvertex_indices - 1) { if (i == submesh->vertex_indices - 1) + { assert(triangle_check == 3); + } uint32_t counter = 0; for (auto v : vertices) @@ -587,15 +591,10 @@ sg::Scene GLTFLoader::load_scene(int scene_index) auto &image = image_components[image_index]; - core::Buffer stage_buffer{device, - image->get_data().size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, image->get_data()); batch_size += image->get_data().size(); - stage_buffer.update(image->get_data()); - upload_image_to_gpu(command_buffer, stage_buffer, *image); transient_buffers.push_back(std::move(stage_buffer)); @@ -735,6 +734,7 @@ sg::Scene GLTFLoader::load_scene(int scene_index) submesh->vertices_count = to_u32(model.accessors[attribute.second].count); } + // FIXME this is low performance as it renders from a host visible buffer core::Buffer buffer{device, vertex_data.size(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, @@ -1146,12 +1146,7 @@ std::unique_ptr GLTFLoader::load_model(uint32_t index, bool storage aligned_vertex_data.push_back(vert); } - core::Buffer stage_buffer{device, - aligned_vertex_data.size() * sizeof(AlignedVertex), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(aligned_vertex_data.data(), aligned_vertex_data.size() * sizeof(AlignedVertex)); + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, aligned_vertex_data); core::Buffer buffer{device, aligned_vertex_data.size() * sizeof(AlignedVertex), @@ -1179,12 +1174,7 @@ std::unique_ptr GLTFLoader::load_model(uint32_t index, bool storage vertex_data.push_back(vert); } - core::Buffer stage_buffer{device, - vertex_data.size() * sizeof(Vertex), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(vertex_data.data(), vertex_data.size() * sizeof(Vertex)); + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, vertex_data); core::Buffer buffer{device, vertex_data.size() * sizeof(Vertex), @@ -1239,14 +1229,9 @@ std::unique_ptr GLTFLoader::load_model(uint32_t index, bool storage prepare_meshlets(meshlets, submesh, index_data); // vertex_indices and index_buffer are used for meshlets now - submesh->vertex_indices = (uint32_t) meshlets.size(); + submesh->vertex_indices = static_cast(meshlets.size()); - core::Buffer stage_buffer{device, - meshlets.size() * sizeof(Meshlet), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(meshlets.data(), meshlets.size() * sizeof(Meshlet)); + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, meshlets); submesh->index_buffer = std::make_unique(device, meshlets.size() * sizeof(Meshlet), @@ -1259,12 +1244,7 @@ std::unique_ptr GLTFLoader::load_model(uint32_t index, bool storage } else { - core::Buffer stage_buffer{device, - index_data.size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(index_data); + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, index_data); submesh->index_buffer = std::make_unique(device, index_data.size(), diff --git a/framework/gui.cpp b/framework/gui.cpp index 1c9b687778..a1fb715513 100644 --- a/framework/gui.cpp +++ b/framework/gui.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors - * Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2018-2024, Arm Limited and Contributors + * Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -49,10 +49,10 @@ namespace vkb { namespace { -void upload_draw_data(ImDrawData *draw_data, const uint8_t *vertex_data, const uint8_t *index_data) +void upload_draw_data(const ImDrawData *draw_data, uint8_t *vertex_data, uint8_t *index_data) { - ImDrawVert *vtx_dst = (ImDrawVert *) vertex_data; - ImDrawIdx *idx_dst = (ImDrawIdx *) index_data; + ImDrawVert *vtx_dst = reinterpret_cast(vertex_data); + ImDrawIdx *idx_dst = reinterpret_cast(index_data); for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -165,20 +165,22 @@ Gui::Gui(VulkanSample &sample_, const Window &window, const Stats *stats, auto &device = sample.get_render_context().get_device(); // Create target image for copy - VkExtent3D font_extent{to_u32(tex_width), to_u32(tex_height), 1u}; - - font_image = std::make_unique(device, font_extent, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - font_image->set_debug_name("GUI font image"); - + vkb::core::ImageBuilder builder{ + static_cast(tex_width), + static_cast(tex_height)}; + builder + .with_format(VK_FORMAT_R8G8B8A8_UNORM) + .with_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY) + .with_debug_name("GUI font image"); + + font_image = std::make_unique(device, builder); font_image_view = std::make_unique(*font_image, VK_IMAGE_VIEW_TYPE_2D); font_image_view->set_debug_name("View on GUI font image"); // Upload font data into the vulkan image memory { - core::Buffer stage_buffer{device, upload_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY, 0}; - stage_buffer.update({font_data, font_data + upload_size}); + core::Buffer stage_buffer = core::Buffer::create_staging_buffer(device, upload_size, font_data); auto &command_buffer = device.request_command_buffer(); @@ -1141,7 +1143,9 @@ bool Drawer::radio_button(const char *caption, int32_t *selectedOption, const in { bool res = ImGui::RadioButton(caption, selectedOption, elementOption); if (res) + { dirty = true; + } return res; } diff --git a/framework/hpp_api_vulkan_sample.cpp b/framework/hpp_api_vulkan_sample.cpp index a16212b1d1..cdd1b23528 100644 --- a/framework/hpp_api_vulkan_sample.cpp +++ b/framework/hpp_api_vulkan_sample.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -838,9 +838,7 @@ HPPTexture HPPApiVulkanSample::load_texture(const std::string &file, vkb::scene_ vk::CommandBuffer command_buffer = get_device()->create_command_buffer(vk::CommandBufferLevel::ePrimary, true); - vkb::core::HPPBuffer stage_buffer{*get_device(), texture.image->get_data().size(), vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::HPPBuffer stage_buffer = vkb::core::HPPBuffer::create_staging_buffer(*get_device(), texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector bufferCopyRegions; @@ -898,9 +896,7 @@ HPPTexture HPPApiVulkanSample::load_texture_array(const std::string &file, vkb:: vk::CommandBuffer command_buffer = get_device()->create_command_buffer(vk::CommandBufferLevel::ePrimary, true); - vkb::core::HPPBuffer stage_buffer{*get_device(), texture.image->get_data().size(), vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::HPPBuffer stage_buffer = vkb::core::HPPBuffer::create_staging_buffer(*get_device(), texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector buffer_copy_regions; @@ -964,9 +960,7 @@ HPPTexture HPPApiVulkanSample::load_texture_cubemap(const std::string &file, vkb vk::CommandBuffer command_buffer = get_device()->create_command_buffer(vk::CommandBufferLevel::ePrimary, true); - vkb::core::HPPBuffer stage_buffer{*get_device(), texture.image->get_data().size(), vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_ONLY}; - - stage_buffer.update(texture.image->get_data()); + vkb::core::HPPBuffer stage_buffer = vkb::core::HPPBuffer::create_staging_buffer(*get_device(), texture.image->get_data()); // Setup buffer copy regions for each mip level std::vector buffer_copy_regions; diff --git a/framework/hpp_buffer_pool.h b/framework/hpp_buffer_pool.h index ed1bf17d97..6a186ee9c1 100644 --- a/framework/hpp_buffer_pool.h +++ b/framework/hpp_buffer_pool.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -80,7 +80,7 @@ class HPPBufferPool : private vkb::BufferPool using vkb::BufferPool::reset; HPPBufferPool( - vkb::core::HPPDevice &device, vk::DeviceSize block_size, vk::BufferUsageFlags usage, VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU) : + vkb::core::HPPDevice &device, vk::DeviceSize block_size, vk::BufferUsageFlags usage, VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_AUTO) : vkb::BufferPool( reinterpret_cast(device), static_cast(block_size), static_cast(usage), memory_usage) { diff --git a/framework/hpp_gui.cpp b/framework/hpp_gui.cpp index f518576626..626773e941 100644 --- a/framework/hpp_gui.cpp +++ b/framework/hpp_gui.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -26,10 +26,10 @@ namespace vkb { namespace { -void upload_draw_data(const ImDrawData *draw_data, const uint8_t *vertex_data, const uint8_t *index_data) +void upload_draw_data(const ImDrawData *draw_data, uint8_t *vertex_data, uint8_t *index_data) { - ImDrawVert *vtx_dst = (ImDrawVert *) vertex_data; - ImDrawIdx *idx_dst = (ImDrawIdx *) index_data; + ImDrawVert *vtx_dst = reinterpret_cast(vertex_data); + ImDrawIdx *idx_dst = reinterpret_cast(index_data); for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -133,9 +133,10 @@ HPPGui::HPPGui(HPPVulkanSample &sample_, const vkb::Window &window, const vkb::s // Create target image for copy vk::Extent3D font_extent(to_u32(tex_width), to_u32(tex_height), 1u); - font_image = std::make_unique(device, font_extent, vk::Format::eR8G8B8A8Unorm, - vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, - VMA_MEMORY_USAGE_GPU_ONLY); + vkb::core::HPPImageBuilder image_builder(font_extent); + image_builder.with_format(vk::Format::eR8G8B8A8Unorm); + image_builder.with_usage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst); + font_image = std::make_unique(device, image_builder); font_image->set_debug_name("GUI font image"); font_image_view = std::make_unique(*font_image, vk::ImageViewType::e2D); @@ -143,8 +144,7 @@ HPPGui::HPPGui(HPPVulkanSample &sample_, const vkb::Window &window, const vkb::s // Upload font data into the vulkan image memory { - vkb::core::HPPBuffer stage_buffer(device, upload_size, vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_ONLY, 0); - stage_buffer.update({font_data, font_data + upload_size}); + vkb::core::HPPBuffer stage_buffer = vkb::core::HPPBuffer::create_staging_buffer(device, upload_size, font_data); auto &command_buffer = device.get_command_pool().request_command_buffer(); @@ -225,10 +225,14 @@ HPPGui::HPPGui(HPPVulkanSample &sample_, const vkb::Window &window, const vkb::s if (explicit_update) { - vertex_buffer = std::make_unique(sample.get_render_context().get_device(), 1, vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_GPU_TO_CPU); + vkb::core::HPPBufferBuilder vertex_buffer_builder(1); + vertex_buffer_builder.with_usage(vk::BufferUsageFlagBits::eVertexBuffer).with_vma_usage(VMA_MEMORY_USAGE_GPU_TO_CPU); + vertex_buffer = std::make_unique(sample.get_render_context().get_device(), vertex_buffer_builder); vertex_buffer->set_debug_name("GUI vertex buffer"); - index_buffer = std::make_unique(sample.get_render_context().get_device(), 1, vk::BufferUsageFlagBits::eIndexBuffer, VMA_MEMORY_USAGE_GPU_TO_CPU); + vkb::core::HPPBufferBuilder index_buffer_builder(1); + index_buffer_builder.with_usage(vk::BufferUsageFlagBits::eIndexBuffer).with_vma_usage(VMA_MEMORY_USAGE_GPU_TO_CPU); + index_buffer = std::make_unique(sample.get_render_context().get_device(), index_buffer_builder); index_buffer->set_debug_name("GUI index buffer"); } } @@ -691,7 +695,9 @@ bool HPPGui::is_debug_view_active() const HPPGui::StatsView::StatsView(const vkb::stats::HPPStats *stats) { if (stats == nullptr) + { return; + } // Request graph data information for each stat and record it in graph_map const std::set &indices = stats->get_requested_stats(); @@ -1061,7 +1067,7 @@ bool HPPDrawer::checkbox(const std::string &caption, int32_t *value) if (res) { dirty = true; - }; + } return res; } @@ -1069,8 +1075,9 @@ bool HPPDrawer::radio_button(const char *caption, int32_t *selectedOption, const { bool res = ImGui::RadioButton(caption, selectedOption, elementOption); if (res) + { dirty = true; - + } return res; } @@ -1080,7 +1087,7 @@ bool HPPDrawer::input_float(const std::string &caption, float *value, float step if (res) { dirty = true; - }; + } return res; } diff --git a/framework/rendering/hpp_render_context.cpp b/framework/rendering/hpp_render_context.cpp index 8b72c1216b..ed44c32855 100644 --- a/framework/rendering/hpp_render_context.cpp +++ b/framework/rendering/hpp_render_context.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -70,13 +70,12 @@ void HPPRenderContext::prepare(size_t thread_count, vkb::rendering::HPPRenderTar { // Otherwise, create a single RenderFrame swapchain = nullptr; + // We can use any format here that we like + core::HPPImageBuilder builder(surface_extent); + builder.with_format(DEFAULT_VK_FORMAT); + builder.with_usage(vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc); - auto color_image = vkb::core::HPPImage{device, - vk::Extent3D{surface_extent.width, surface_extent.height, 1}, - DEFAULT_VK_FORMAT, // We can use any format here that we like - vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc, - VMA_MEMORY_USAGE_GPU_ONLY}; - + auto color_image = vkb::core::HPPImage{device, builder}; auto render_target = create_render_target_func(std::move(color_image)); frames.emplace_back(std::make_unique(device, std::move(render_target), thread_count)); } diff --git a/framework/rendering/hpp_render_context.h b/framework/rendering/hpp_render_context.h index 8fb312c24f..296a58bd07 100644 --- a/framework/rendering/hpp_render_context.h +++ b/framework/rendering/hpp_render_context.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -196,7 +196,7 @@ class HPPRenderContext /** * @brief Handles surface changes, only applicable if the render_context makes use of a swapchain */ - virtual bool handle_surface_changes(bool force_update = false); + bool handle_surface_changes(bool force_update = false); /** * @brief Returns the WSI acquire semaphore. Only to be used in very special circumstances. diff --git a/framework/rendering/hpp_render_target.cpp b/framework/rendering/hpp_render_target.cpp index 8791312d51..cbf2d20ec8 100644 --- a/framework/rendering/hpp_render_target.cpp +++ b/framework/rendering/hpp_render_target.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -26,10 +26,10 @@ namespace rendering const HPPRenderTarget::CreateFunc HPPRenderTarget::DEFAULT_CREATE_FUNC = [](core::HPPImage &&swapchain_image) -> std::unique_ptr { vk::Format depth_format = common::get_suitable_depth_format(swapchain_image.get_device().get_gpu().get_handle()); - core::HPPImage depth_image{swapchain_image.get_device(), swapchain_image.get_extent(), - depth_format, - vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eTransientAttachment, - VMA_MEMORY_USAGE_GPU_ONLY}; + core::HPPImageBuilder builder(swapchain_image.get_extent()); + builder.with_format(depth_format); + builder.with_usage(vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eTransientAttachment); + core::HPPImage depth_image{swapchain_image.get_device(), builder}; std::vector images; images.push_back(std::move(swapchain_image)); diff --git a/framework/rendering/render_context.cpp b/framework/rendering/render_context.cpp index 004a88ff58..97f5139ca5 100644 --- a/framework/rendering/render_context.cpp +++ b/framework/rendering/render_context.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -74,13 +74,13 @@ void RenderContext::prepare(size_t thread_count, RenderTarget::CreateFunc create { // Otherwise, create a single RenderFrame swapchain = nullptr; + vkb::core::ImageBuilder builder{surface_extent.width, surface_extent.height}; + builder + .with_format(DEFAULT_VK_FORMAT) + .with_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); - auto color_image = core::Image{device, - VkExtent3D{surface_extent.width, surface_extent.height, 1}, - DEFAULT_VK_FORMAT, // We can use any format here that we like - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_GPU_ONLY}; - + auto color_image = core::Image{device, builder}; auto render_target = create_render_target_func(std::move(color_image)); frames.emplace_back(std::make_unique(device, std::move(render_target), thread_count)); } diff --git a/framework/rendering/render_context.h b/framework/rendering/render_context.h index 44798653d4..c06c3a8f24 100644 --- a/framework/rendering/render_context.h +++ b/framework/rendering/render_context.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -217,7 +217,7 @@ class RenderContext /** * @brief Handles surface changes, only applicable if the render_context makes use of a swapchain */ - virtual bool handle_surface_changes(bool force_update = false); + bool handle_surface_changes(bool force_update = false); /** * @brief Returns the WSI acquire semaphore. Only to be used in very special circumstances. diff --git a/framework/rendering/render_target.cpp b/framework/rendering/render_target.cpp index c5283bc011..195511b7cb 100644 --- a/framework/rendering/render_target.cpp +++ b/framework/rendering/render_target.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -41,10 +41,12 @@ Attachment::Attachment(VkFormat format, VkSampleCountFlagBits samples, VkImageUs const RenderTarget::CreateFunc RenderTarget::DEFAULT_CREATE_FUNC = [](core::Image &&swapchain_image) -> std::unique_ptr { VkFormat depth_format = get_suitable_depth_format(swapchain_image.get_device().get_gpu().get_handle()); - core::Image depth_image{swapchain_image.get_device(), swapchain_image.get_extent(), - depth_format, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - VMA_MEMORY_USAGE_GPU_ONLY}; + core::ImageBuilder builder(swapchain_image.get_extent()); + builder + .with_format(depth_format) + .with_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + core::Image depth_image{swapchain_image.get_device(), builder}; std::vector images; images.push_back(std::move(swapchain_image)); diff --git a/framework/scene_graph/components/hpp_image.cpp b/framework/scene_graph/components/hpp_image.cpp index 78fa003b16..98223edb76 100644 --- a/framework/scene_graph/components/hpp_image.cpp +++ b/framework/scene_graph/components/hpp_image.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -202,17 +202,17 @@ void HPPImage::create_vk_image(vkb::core::HPPDevice &device, vk::ImageViewType i { assert(!vk_image && !vk_image_view && "Vulkan HPPImage already constructed"); - vk_image = std::make_unique(device, - get_extent(), - format, - vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, - VMA_MEMORY_USAGE_GPU_ONLY, - vk::SampleCountFlagBits::e1, - to_u32(mipmaps.size()), - layers, - vk::ImageTiling::eOptimal, - flags); - vk_image->set_debug_name(get_name()); + vkb::core::HPPImageBuilder builder{get_extent()}; + builder + .with_format(format) + .with_usage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY) + .with_mip_levels(to_u32(mipmaps.size())) + .with_array_layers(layers) + .with_flags(flags) + .with_debug_name(get_name()); + + vk_image = std::make_unique(device, builder); vk_image_view = std::make_unique(*vk_image, image_view_type); vk_image_view->set_debug_name("View on " + get_name()); diff --git a/framework/scene_graph/components/image.cpp b/framework/scene_graph/components/image.cpp index 8ab8f68d6a..22f5d2dee2 100644 --- a/framework/scene_graph/components/image.cpp +++ b/framework/scene_graph/components/image.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -202,17 +202,17 @@ void Image::create_vk_image(Device const &device, VkImageViewType image_view_typ { assert(!vk_image && !vk_image_view && "Vulkan image already constructed"); - vk_image = std::make_unique(device, - get_extent(), - format, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VMA_MEMORY_USAGE_GPU_ONLY, - VK_SAMPLE_COUNT_1_BIT, - to_u32(mipmaps.size()), - layers, - VK_IMAGE_TILING_OPTIMAL, - flags); - vk_image->set_debug_name(get_name()); + vkb::core::ImageBuilder builder{get_extent()}; + builder + .with_format(format) + .with_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY) + .with_mip_levels(to_u32(mipmaps.size())) + .with_array_layers(layers) + .with_flags(flags) + .with_debug_name(get_name()); + + vk_image = std::make_unique(device, builder); vk_image_view = std::make_unique(*vk_image, image_view_type); vk_image_view->set_debug_name("View on " + get_name()); diff --git a/samples/api/compute_nbody/compute_nbody.cpp b/samples/api/compute_nbody/compute_nbody.cpp index 659b901e82..734f634ba7 100644 --- a/samples/api/compute_nbody/compute_nbody.cpp +++ b/samples/api/compute_nbody/compute_nbody.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -322,8 +322,7 @@ void ComputeNBody::prepare_storage_buffers() // Staging // SSBO won't be changed on the host after upload so copy to device local memory - vkb::core::Buffer staging_buffer{get_device(), storage_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY}; - staging_buffer.update(particle_buffer.data(), storage_buffer_size); + vkb::core::Buffer staging_buffer = vkb::core::Buffer::create_staging_buffer(get_device(), particle_buffer); compute.storage_buffer = std::make_unique(get_device(), storage_buffer_size, diff --git a/samples/api/hpp_compute_nbody/hpp_compute_nbody.cpp b/samples/api/hpp_compute_nbody/hpp_compute_nbody.cpp index 6e1986afdb..6062635708 100644 --- a/samples/api/hpp_compute_nbody/hpp_compute_nbody.cpp +++ b/samples/api/hpp_compute_nbody/hpp_compute_nbody.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -371,7 +371,7 @@ void HPPComputeNBody::initializeCamera() camera.type = vkb::CameraType::LookAt; // Note: Using reversed depth-buffer for increased precision, so Z-Near and Z-Far are flipped - camera.set_perspective(60.0f, (float) extent.width / (float) extent.height, 512.0f, 0.1f); + camera.set_perspective(60.0f, static_cast(extent.width) / static_cast(extent.height), 512.0f, 0.1f); camera.set_rotation(glm::vec3(-26.0f, 75.0f, 0.0f)); camera.set_translation(glm::vec3(0.0f, 0.0f, -14.0f)); camera.translation_speed = 2.5f; @@ -513,7 +513,7 @@ void HPPComputeNBody::prepare_compute_storage_buffers() // Initial particle positions std::vector particle_buffer(compute.ubo.particle_count); - std::default_random_engine rnd_engine(lock_simulation_speed ? 0 : (unsigned) time(nullptr)); + std::default_random_engine rnd_engine(lock_simulation_speed ? 0 : static_cast(time(nullptr))); std::normal_distribution rnd_distribution(0.0f, 1.0f); for (uint32_t i = 0; i < static_cast(attractors.size()); i++) @@ -547,7 +547,7 @@ void HPPComputeNBody::prepare_compute_storage_buffers() } // Color gradient offset - particle.vel.w = (float) i * 1.0f / static_cast(attractors.size()); + particle.vel.w = static_cast(i) * 1.0f / static_cast(attractors.size()); } } @@ -555,8 +555,7 @@ void HPPComputeNBody::prepare_compute_storage_buffers() // Staging // SSBO won't be changed on the host after upload so copy to device local memory - vkb::core::HPPBuffer staging_buffer(*get_device(), storage_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_ONLY); - staging_buffer.update(particle_buffer.data(), storage_buffer_size); + vkb::core::HPPBuffer staging_buffer = vkb::core::HPPBuffer::create_staging_buffer(*get_device(), particle_buffer); compute.storage_buffer = std::make_unique(*get_device(), storage_buffer_size, diff --git a/samples/api/hpp_texture_mipmap_generation/hpp_texture_mipmap_generation.cpp b/samples/api/hpp_texture_mipmap_generation/hpp_texture_mipmap_generation.cpp index 9ba608edcd..3957dd1437 100644 --- a/samples/api/hpp_texture_mipmap_generation/hpp_texture_mipmap_generation.cpp +++ b/samples/api/hpp_texture_mipmap_generation/hpp_texture_mipmap_generation.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -267,8 +267,7 @@ void HPPTextureMipMapGeneration::load_assets() check_format_features(format); // Create a host-visible staging buffer that contains the raw image data - vkb::core::HPPBuffer staging_buffer(*device, ktx_texture->dataSize, vk::BufferUsageFlagBits::eTransferSrc, VMA_MEMORY_USAGE_CPU_TO_GPU); - staging_buffer.update(ktx_texture->pData, ktx_texture->dataSize); + vkb::core::HPPBuffer staging_buffer = vkb::core::HPPBuffer::create_staging_buffer(*device, ktx_texture->dataSize, ktx_texture->pData); // now, the ktx_texture can be destroyed ktxTexture_Destroy(ktx_texture); diff --git a/samples/api/instancing/instancing.cpp b/samples/api/instancing/instancing.cpp index 7535f114f8..9e9e9d4e45 100644 --- a/samples/api/instancing/instancing.cpp +++ b/samples/api/instancing/instancing.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -402,8 +402,7 @@ void Instancing::prepare_instance_data() // On devices with separate memory types for host visible and device local memory this will result in better performance // On devices with unified memory types (DEVICE_LOCAL_BIT and HOST_VISIBLE_BIT supported at once) this isn't necessary and you could skip the staging - vkb::core::Buffer staging_buffer(get_device(), instance_buffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); - staging_buffer.update(instance_data); + vkb::core::Buffer staging_buffer = vkb::core::Buffer::create_staging_buffer(get_device(), instance_data); instance_buffer.buffer = std::make_unique(get_device(), instance_buffer.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); diff --git a/samples/api/oit_linked_lists/oit_linked_lists.cpp b/samples/api/oit_linked_lists/oit_linked_lists.cpp index 1e88944f36..791c69ad5f 100644 --- a/samples/api/oit_linked_lists/oit_linked_lists.cpp +++ b/samples/api/oit_linked_lists/oit_linked_lists.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, Google +/* Copyright (c) 2023-2024, Google * * SPDX-License-Identifier: Apache-2.0 * @@ -250,9 +250,14 @@ void OITLinkedLists::create_gather_pass_objects(const uint32_t width, const uint void OITLinkedLists::create_fragment_resources(const uint32_t width, const uint32_t height) { { - const VkExtent3D image_extent = {width, height, 1}; - linked_list_head_image = std::make_unique(get_device(), image_extent, VK_FORMAT_R32_UINT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY, VK_SAMPLE_COUNT_1_BIT); - linked_list_head_image_view = std::make_unique(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT); + vkb::core::ImageBuilder builder{width, height}; + builder + .with_format(VK_FORMAT_R32_UINT) + .with_usage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + + linked_list_head_image = std::make_unique(get_device(), builder); + linked_list_head_image_view = std::make_unique(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D); } { diff --git a/samples/extensions/conservative_rasterization/conservative_rasterization.cpp b/samples/extensions/conservative_rasterization/conservative_rasterization.cpp index 06d98e79a6..cfd757480f 100644 --- a/samples/extensions/conservative_rasterization/conservative_rasterization.cpp +++ b/samples/extensions/conservative_rasterization/conservative_rasterization.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -353,11 +353,8 @@ void ConservativeRasterization::load_assets() uint32_t index_buffer_size = triangle.index_count * sizeof(uint32_t); // Host visible source buffers (staging) - vkb::core::Buffer vertex_staging_buffer{get_device(), vertex_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY}; - vertex_staging_buffer.update(vertex_buffer.data(), vertex_buffer_size); - - vkb::core::Buffer index_staging_buffer{get_device(), index_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY}; - index_staging_buffer.update(index_buffer.data(), index_buffer_size); + vkb::core::Buffer vertex_staging_buffer = vkb::core::Buffer::create_staging_buffer(get_device(), vertex_buffer); + vkb::core::Buffer index_staging_buffer = vkb::core::Buffer::create_staging_buffer(get_device(), index_buffer); // Device local destination buffers triangle.vertices = std::make_unique(get_device(), diff --git a/samples/extensions/fragment_shading_rate_dynamic/fragment_shading_rate_dynamic.cpp b/samples/extensions/fragment_shading_rate_dynamic/fragment_shading_rate_dynamic.cpp index 43c2676f81..4e6db77524 100644 --- a/samples/extensions/fragment_shading_rate_dynamic/fragment_shading_rate_dynamic.cpp +++ b/samples/extensions/fragment_shading_rate_dynamic/fragment_shading_rate_dynamic.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Holochip +/* Copyright (c) 2021-2024, Holochip * * SPDX-License-Identifier: Apache-2.0 * @@ -115,19 +115,19 @@ void FragmentShadingRateDynamic::create_shading_rate_attachment() image_extent.depth = 1; auto create_shading_rate = [&](VkImageUsageFlags image_usage, VkFormat format) { - return std::make_unique(*device, - image_extent, - format, - image_usage, - VMA_MEMORY_USAGE_GPU_ONLY, - VK_SAMPLE_COUNT_1_BIT); + vkb::core::ImageBuilder builder{image_extent}; + builder + .with_format(format) + .with_usage(image_usage) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + return std::make_unique(*device, builder); }; - shading_rate_image = create_shading_rate(VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | - static_cast(VK_BUFFER_USAGE_TRANSFER_DST_BIT), - VK_FORMAT_R8_UINT); + shading_rate_image = create_shading_rate( + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_FORMAT_R8_UINT); shading_rate_image_compute = create_shading_rate( - VK_IMAGE_USAGE_STORAGE_BIT | static_cast(VK_BUFFER_USAGE_TRANSFER_SRC_BIT), + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_FORMAT_R8_UINT); uint32_t fragment_shading_rate_count = 0; @@ -184,20 +184,18 @@ void FragmentShadingRateDynamic::create_shading_rate_attachment() VK_FORMAT_R8_UINT); // Create an attachment to store the frequency content of the rendered image during the render pass - VkExtent3D frequency_image_extent{}; - frequency_image_extent.width = this->width; - frequency_image_extent.height = this->height; - frequency_image_extent.depth = 1; - frequency_content_image = std::make_unique(*device, - frequency_image_extent, - VK_FORMAT_R8G8_UINT, - VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - frequency_content_image_view = std::make_unique(*frequency_content_image, - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_R8G8_UINT); + vkb::core::ImageBuilder builder{this->width, this->height}; + builder + .with_format(VK_FORMAT_R8G8_UINT) + .with_usage(VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + + frequency_content_image = std::make_unique(*device, builder); + frequency_content_image_view = std::make_unique(*frequency_content_image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8_UINT); { auto &_cmd = device->request_command_buffer(); diff --git a/samples/extensions/ray_tracing_basic/ray_tracing_basic.cpp b/samples/extensions/ray_tracing_basic/ray_tracing_basic.cpp index ab048f86e5..b8dc0f685b 100644 --- a/samples/extensions/ray_tracing_basic/ray_tracing_basic.cpp +++ b/samples/extensions/ray_tracing_basic/ray_tracing_basic.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -51,9 +51,8 @@ RaytracingBasic::~RaytracingBasic() vkDestroyPipeline(get_device().get_handle(), pipeline, nullptr); vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout, nullptr); vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layout, nullptr); - vkDestroyImageView(get_device().get_handle(), storage_image.view, nullptr); - vkDestroyImage(get_device().get_handle(), storage_image.image, nullptr); - vkFreeMemory(get_device().get_handle(), storage_image.memory, nullptr); + storage_image_view.reset(); + storage_image.reset(); delete_acceleration_structure(top_level_acceleration_structure); delete_acceleration_structure(bottom_level_acceleration_structure); vertex_buffer.reset(); @@ -79,46 +78,18 @@ void RaytracingBasic::request_gpu_features(vkb::PhysicalDevice &gpu) */ void RaytracingBasic::create_storage_image() { - storage_image.width = width; - storage_image.height = height; - - VkImageCreateInfo image = vkb::initializers::image_create_info(); - image.imageType = VK_IMAGE_TYPE_2D; - image.format = VK_FORMAT_B8G8R8A8_UNORM; - image.extent.width = storage_image.width; - image.extent.height = storage_image.height; - image.extent.depth = 1; - image.mipLevels = 1; - image.arrayLayers = 1; - image.samples = VK_SAMPLE_COUNT_1_BIT; - image.tiling = VK_IMAGE_TILING_OPTIMAL; - image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT; - image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VK_CHECK(vkCreateImage(get_device().get_handle(), &image, nullptr, &storage_image.image)); - - VkMemoryRequirements memory_requirements; - vkGetImageMemoryRequirements(get_device().get_handle(), storage_image.image, &memory_requirements); - VkMemoryAllocateInfo memory_allocate_info = vkb::initializers::memory_allocate_info(); - memory_allocate_info.allocationSize = memory_requirements.size; - memory_allocate_info.memoryTypeIndex = get_device().get_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK(vkAllocateMemory(get_device().get_handle(), &memory_allocate_info, nullptr, &storage_image.memory)); - VK_CHECK(vkBindImageMemory(get_device().get_handle(), storage_image.image, storage_image.memory, 0)); - - VkImageViewCreateInfo color_image_view = vkb::initializers::image_view_create_info(); - color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; - color_image_view.format = VK_FORMAT_B8G8R8A8_UNORM; - color_image_view.subresourceRange = {}; - color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - color_image_view.subresourceRange.baseMipLevel = 0; - color_image_view.subresourceRange.levelCount = 1; - color_image_view.subresourceRange.baseArrayLayer = 0; - color_image_view.subresourceRange.layerCount = 1; - color_image_view.image = storage_image.image; - VK_CHECK(vkCreateImageView(get_device().get_handle(), &color_image_view, nullptr, &storage_image.view)); + vkb::core::ImageBuilder image_builder{{width, height, 1}}; + image_builder + .with_format(VK_FORMAT_B8G8R8A8_UNORM) + .with_usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + + storage_image = std::make_unique(get_device(), image_builder); + storage_image_view = std::make_unique(*storage_image, VK_IMAGE_VIEW_TYPE_2D); VkCommandBuffer command_buffer = get_device().create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); vkb::image_layout_transition(command_buffer, - storage_image.image, + storage_image->get_handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, @@ -129,65 +100,6 @@ void RaytracingBasic::create_storage_image() get_device().flush_command_buffer(command_buffer, queue); } -/* - Gets the device address from a buffer that's needed in many places during the ray tracing setup -*/ -uint64_t RaytracingBasic::get_buffer_device_address(VkBuffer buffer) -{ - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = buffer; - return vkGetBufferDeviceAddressKHR(device->get_handle(), &buffer_device_address_info); -} - -/* - Create buffer and allocate memory for a temporary scratch buffer -*/ -ScratchBuffer RaytracingBasic::create_scratch_buffer(VkDeviceSize size) -{ - ScratchBuffer scratch_buffer{}; - - VkBufferCreateInfo buffer_create_info = {}; - buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_create_info.size = size; - buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VK_CHECK(vkCreateBuffer(device->get_handle(), &buffer_create_info, nullptr, &scratch_buffer.handle)); - - VkMemoryRequirements memory_requirements = {}; - vkGetBufferMemoryRequirements(device->get_handle(), scratch_buffer.handle, &memory_requirements); - - VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {}; - memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - - VkMemoryAllocateInfo memory_allocate_info = {}; - memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_allocate_info.pNext = &memory_allocate_flags_info; - memory_allocate_info.allocationSize = memory_requirements.size; - memory_allocate_info.memoryTypeIndex = device->get_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK(vkAllocateMemory(device->get_handle(), &memory_allocate_info, nullptr, &scratch_buffer.memory)); - VK_CHECK(vkBindBufferMemory(device->get_handle(), scratch_buffer.handle, scratch_buffer.memory, 0)); - - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = scratch_buffer.handle; - scratch_buffer.device_address = vkGetBufferDeviceAddressKHR(device->get_handle(), &buffer_device_address_info); - - return scratch_buffer; -} - -void RaytracingBasic::delete_scratch_buffer(ScratchBuffer &scratch_buffer) -{ - if (scratch_buffer.memory != VK_NULL_HANDLE) - { - vkFreeMemory(device->get_handle(), scratch_buffer.memory, nullptr); - } - if (scratch_buffer.handle != VK_NULL_HANDLE) - { - vkDestroyBuffer(device->get_handle(), scratch_buffer.handle, nullptr); - } -} - /* Create the bottom level acceleration structure that contains the scene's geometry (triangles) */ @@ -231,9 +143,9 @@ void RaytracingBasic::create_bottom_level_acceleration_structure() VkDeviceOrHostAddressConstKHR index_data_device_address{}; VkDeviceOrHostAddressConstKHR transform_matrix_device_address{}; - vertex_data_device_address.deviceAddress = get_buffer_device_address(vertex_buffer->get_handle()); - index_data_device_address.deviceAddress = get_buffer_device_address(index_buffer->get_handle()); - transform_matrix_device_address.deviceAddress = get_buffer_device_address(transform_matrix_buffer->get_handle()); + vertex_data_device_address.deviceAddress = vertex_buffer->get_device_address(); + index_data_device_address.deviceAddress = index_buffer->get_device_address(); + transform_matrix_device_address.deviceAddress = transform_matrix_buffer->get_device_address(); // The bottom level acceleration structure contains one set of triangles as the input geometry VkAccelerationStructureGeometryKHR acceleration_structure_geometry{}; @@ -286,7 +198,7 @@ void RaytracingBasic::create_bottom_level_acceleration_structure() // The actual build process starts here // Create a scratch buffer as a temporary storage for the acceleration structure build - ScratchBuffer scratch_buffer = create_scratch_buffer(acceleration_structure_build_sizes_info.buildScratchSize); + auto scratch_buffer = vkb::core::Buffer::create_scratch_buffer(get_device(), acceleration_structure_build_sizes_info.buildScratchSize); VkAccelerationStructureBuildGeometryInfoKHR acceleration_build_geometry_info{}; acceleration_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; @@ -296,7 +208,7 @@ void RaytracingBasic::create_bottom_level_acceleration_structure() acceleration_build_geometry_info.dstAccelerationStructure = bottom_level_acceleration_structure.handle; acceleration_build_geometry_info.geometryCount = 1; acceleration_build_geometry_info.pGeometries = &acceleration_structure_geometry; - acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer.device_address; + acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer.get_device_address(); VkAccelerationStructureBuildRangeInfoKHR acceleration_structure_build_range_info; acceleration_structure_build_range_info.primitiveCount = 1; @@ -315,8 +227,6 @@ void RaytracingBasic::create_bottom_level_acceleration_structure() acceleration_build_structure_range_infos.data()); get_device().flush_command_buffer(command_buffer, queue); - delete_scratch_buffer(scratch_buffer); - // Get the bottom acceleration structure's handle, which will be used during the top level acceleration build VkAccelerationStructureDeviceAddressInfoKHR acceleration_device_address_info{}; acceleration_device_address_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; @@ -349,7 +259,7 @@ void RaytracingBasic::create_top_level_acceleration_structure() instances_buffer->update(&acceleration_structure_instance, sizeof(VkAccelerationStructureInstanceKHR)); VkDeviceOrHostAddressConstKHR instance_data_device_address{}; - instance_data_device_address.deviceAddress = get_buffer_device_address(instances_buffer->get_handle()); + instance_data_device_address.deviceAddress = instances_buffer->get_device_address(); // The top level acceleration structure contains (bottom level) instance as the input geometry VkAccelerationStructureGeometryKHR acceleration_structure_geometry{}; @@ -396,7 +306,7 @@ void RaytracingBasic::create_top_level_acceleration_structure() // The actual build process starts here // Create a scratch buffer as a temporary storage for the acceleration structure build - ScratchBuffer scratch_buffer = create_scratch_buffer(acceleration_structure_build_sizes_info.buildScratchSize); + auto scratch_buffer = vkb::core::Buffer::create_scratch_buffer(get_device(), acceleration_structure_build_sizes_info.buildScratchSize); VkAccelerationStructureBuildGeometryInfoKHR acceleration_build_geometry_info{}; acceleration_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; @@ -406,7 +316,7 @@ void RaytracingBasic::create_top_level_acceleration_structure() acceleration_build_geometry_info.dstAccelerationStructure = top_level_acceleration_structure.handle; acceleration_build_geometry_info.geometryCount = 1; acceleration_build_geometry_info.pGeometries = &acceleration_structure_geometry; - acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer.device_address; + acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer.get_device_address(); VkAccelerationStructureBuildRangeInfoKHR acceleration_structure_build_range_info; acceleration_structure_build_range_info.primitiveCount = 1; @@ -425,8 +335,6 @@ void RaytracingBasic::create_top_level_acceleration_structure() acceleration_build_structure_range_infos.data()); get_device().flush_command_buffer(command_buffer, queue); - delete_scratch_buffer(scratch_buffer); - // Get the top acceleration structure's handle, which will be used to setup it's descriptor VkAccelerationStructureDeviceAddressInfoKHR acceleration_device_address_info{}; acceleration_device_address_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; @@ -464,19 +372,18 @@ void RaytracingBasic::create_scene() void RaytracingBasic::create_shader_binding_tables() { - const uint32_t handle_size = ray_tracing_pipeline_properties.shaderGroupHandleSize; - const uint32_t handle_size_aligned = aligned_size(ray_tracing_pipeline_properties.shaderGroupHandleSize, ray_tracing_pipeline_properties.shaderGroupHandleAlignment); - const uint32_t handle_alignment = ray_tracing_pipeline_properties.shaderGroupHandleAlignment; - const uint32_t group_count = static_cast(shader_groups.size()); - const uint32_t sbt_size = group_count * handle_size_aligned; - const VkBufferUsageFlags sbt_buffer_usage_flags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - const VmaMemoryUsage sbt_memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU; - - // Raygen - // Create binding table buffers for each shader type - raygen_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); - miss_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); - hit_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); + const uint32_t handle_size = ray_tracing_pipeline_properties.shaderGroupHandleSize; + const uint32_t handle_size_aligned = aligned_size(ray_tracing_pipeline_properties.shaderGroupHandleSize, ray_tracing_pipeline_properties.shaderGroupHandleAlignment); + const uint32_t group_count = static_cast(shader_groups.size()); + const uint32_t sbt_size = group_count * handle_size_aligned; + + vkb::core::BufferBuilder builder{handle_size}; + builder.with_vma_usage(VMA_MEMORY_USAGE_CPU_TO_GPU); + builder.with_usage(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + raygen_shader_binding_table = std::make_unique(get_device(), builder); + miss_shader_binding_table = std::make_unique(get_device(), builder); + hit_shader_binding_table = std::make_unique(get_device(), builder); // Copy the pipeline's shader handles into a host buffer std::vector shader_handle_storage(sbt_size); @@ -525,7 +432,7 @@ void RaytracingBasic::create_descriptor_sets() acceleration_structure_write.pNext = &descriptor_acceleration_structure_info; VkDescriptorImageInfo image_descriptor{}; - image_descriptor.imageView = storage_image.view; + image_descriptor.imageView = storage_image_view->get_handle(); image_descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; VkDescriptorBufferInfo buffer_descriptor = create_descriptor(*ubo); @@ -678,16 +585,15 @@ void RaytracingBasic::create_uniform_buffer() */ void RaytracingBasic::build_command_buffers() { - if (width != storage_image.width || height != storage_image.height) + if (width != storage_image->get_extent().width || height != storage_image->get_extent().height) { // If the view port size has changed, we need to recreate the storage image - vkDestroyImageView(get_device().get_handle(), storage_image.view, nullptr); - vkDestroyImage(get_device().get_handle(), storage_image.image, nullptr); - vkFreeMemory(get_device().get_handle(), storage_image.memory, nullptr); + storage_image_view.reset(); + storage_image.reset(); create_storage_image(); // The descriptor also needs to be updated to reference the new image VkDescriptorImageInfo image_descriptor{}; - image_descriptor.imageView = storage_image.view; + image_descriptor.imageView = storage_image_view->get_handle(); image_descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; VkWriteDescriptorSet result_image_write = vkb::initializers::write_descriptor_set(descriptor_set, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &image_descriptor); vkUpdateDescriptorSets(get_device().get_handle(), 1, &result_image_write, 0, VK_NULL_HANDLE); @@ -708,17 +614,17 @@ void RaytracingBasic::build_command_buffers() const uint32_t handle_size_aligned = aligned_size(ray_tracing_pipeline_properties.shaderGroupHandleSize, ray_tracing_pipeline_properties.shaderGroupHandleAlignment); VkStridedDeviceAddressRegionKHR raygen_shader_sbt_entry{}; - raygen_shader_sbt_entry.deviceAddress = get_buffer_device_address(raygen_shader_binding_table->get_handle()); + raygen_shader_sbt_entry.deviceAddress = raygen_shader_binding_table->get_device_address(); raygen_shader_sbt_entry.stride = handle_size_aligned; raygen_shader_sbt_entry.size = handle_size_aligned; VkStridedDeviceAddressRegionKHR miss_shader_sbt_entry{}; - miss_shader_sbt_entry.deviceAddress = get_buffer_device_address(miss_shader_binding_table->get_handle()); + miss_shader_sbt_entry.deviceAddress = miss_shader_binding_table->get_device_address(); miss_shader_sbt_entry.stride = handle_size_aligned; miss_shader_sbt_entry.size = handle_size_aligned; VkStridedDeviceAddressRegionKHR hit_shader_sbt_entry{}; - hit_shader_sbt_entry.deviceAddress = get_buffer_device_address(hit_shader_binding_table->get_handle()); + hit_shader_sbt_entry.deviceAddress = hit_shader_binding_table->get_device_address(); hit_shader_sbt_entry.stride = handle_size_aligned; hit_shader_sbt_entry.size = handle_size_aligned; @@ -752,7 +658,7 @@ void RaytracingBasic::build_command_buffers() // Prepare ray tracing output image as transfer source vkb::image_layout_transition(draw_cmd_buffers[i], - storage_image.image, + storage_image->get_handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, {}, @@ -767,7 +673,7 @@ void RaytracingBasic::build_command_buffers() copy_region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; copy_region.dstOffset = {0, 0, 0}; copy_region.extent = {width, height, 1}; - vkCmdCopyImage(draw_cmd_buffers[i], storage_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkCmdCopyImage(draw_cmd_buffers[i], storage_image->get_handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, get_render_context().get_swapchain().get_images()[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); // Transition swap chain image back for presentation @@ -778,7 +684,7 @@ void RaytracingBasic::build_command_buffers() // Transition ray tracing output image back to general layout vkb::image_layout_transition(draw_cmd_buffers[i], - storage_image.image, + storage_image->get_handle(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_READ_BIT, diff --git a/samples/extensions/ray_tracing_basic/ray_tracing_basic.h b/samples/extensions/ray_tracing_basic/ray_tracing_basic.h index 4e7f9d9e81..190fb74652 100644 --- a/samples/extensions/ray_tracing_basic/ray_tracing_basic.h +++ b/samples/extensions/ray_tracing_basic/ray_tracing_basic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -24,14 +24,6 @@ #include "api_vulkan_sample.h" #include "glsl_compiler.h" -// Holds data for a scratch buffer used as a temporary storage during acceleration structure builds -struct ScratchBuffer -{ - uint64_t device_address; - VkBuffer handle; - VkDeviceMemory memory; -}; - // Wraps all data required for an acceleration structure struct AccelerationStructure { @@ -58,15 +50,8 @@ class RaytracingBasic : public ApiVulkanSample std::unique_ptr miss_shader_binding_table; std::unique_ptr hit_shader_binding_table; - struct StorageImage - { - VkDeviceMemory memory; - VkImage image = VK_NULL_HANDLE; - VkImageView view; - VkFormat format; - uint32_t width; - uint32_t height; - } storage_image; + std::unique_ptr storage_image; + std::unique_ptr storage_image_view; struct UniformData { @@ -83,24 +68,21 @@ class RaytracingBasic : public ApiVulkanSample RaytracingBasic(); ~RaytracingBasic(); - void request_gpu_features(vkb::PhysicalDevice &gpu) override; - uint64_t get_buffer_device_address(VkBuffer buffer); - ScratchBuffer create_scratch_buffer(VkDeviceSize size); - void delete_scratch_buffer(ScratchBuffer &scratch_buffer); - void create_storage_image(); - void create_bottom_level_acceleration_structure(); - void create_top_level_acceleration_structure(); - void delete_acceleration_structure(AccelerationStructure &acceleration_structure); - void create_scene(); - void create_shader_binding_tables(); - void create_descriptor_sets(); - void create_ray_tracing_pipeline(); - void create_uniform_buffer(); - void build_command_buffers() override; - void update_uniform_buffers(); - void draw(); - bool prepare(const vkb::ApplicationOptions &options) override; - virtual void render(float delta_time) override; + void request_gpu_features(vkb::PhysicalDevice &gpu) override; + void create_storage_image(); + void create_bottom_level_acceleration_structure(); + void create_top_level_acceleration_structure(); + void delete_acceleration_structure(AccelerationStructure &acceleration_structure); + void create_scene(); + void create_shader_binding_tables(); + void create_descriptor_sets(); + void create_ray_tracing_pipeline(); + void create_uniform_buffer(); + void build_command_buffers() override; + void update_uniform_buffers(); + void draw(); + bool prepare(const vkb::ApplicationOptions &options) override; + virtual void render(float delta_time) override; }; std::unique_ptr create_ray_tracing_basic(); diff --git a/samples/extensions/ray_tracing_extended/ray_tracing_extended.cpp b/samples/extensions/ray_tracing_extended/ray_tracing_extended.cpp index ef87207d7e..5d99150e99 100644 --- a/samples/extensions/ray_tracing_extended/ray_tracing_extended.cpp +++ b/samples/extensions/ray_tracing_extended/ray_tracing_extended.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023 Holochip Corporation +/* Copyright (c) 2021-2024 Holochip Corporation * * SPDX-License-Identifier: Apache-2.0 * @@ -43,7 +43,8 @@ struct QuickTimer { if (print_on_exit) { - using namespace std::chrono; + using std::chrono::duration_cast; + using std::chrono::microseconds; const auto dur = duration_cast(clock::now() - start).count(); LOGI(fmt::format("{:s} duration: {:f} ms", name, dur / 1000.)) } @@ -534,7 +535,12 @@ void RaytracingExtended::create_bottom_level_acceleration_structure(bool is_upda VkTransformMatrixKHR RaytracingExtended::calculate_rotation(glm::vec3 pt, float scale, bool freeze_z) { - using namespace glm; + using glm::abs; + using glm::cross; + using glm::dot; + using glm::normalize; + using glm::vec3; + auto normal = normalize(pt + camera.position); if (freeze_z) { @@ -846,18 +852,20 @@ void RaytracingExtended::create_scene() void RaytracingExtended::create_shader_binding_tables() { - const uint32_t handle_size = ray_tracing_pipeline_properties.shaderGroupHandleSize; - const uint32_t handle_size_aligned = aligned_size(ray_tracing_pipeline_properties.shaderGroupHandleSize, ray_tracing_pipeline_properties.shaderGroupHandleAlignment); - auto group_count = static_cast(shader_groups.size()); - const uint32_t sbt_size = group_count * handle_size_aligned; - const VkBufferUsageFlags sbt_buffer_usage_flags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - const VmaMemoryUsage sbt_memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + const uint32_t handle_size = ray_tracing_pipeline_properties.shaderGroupHandleSize; + const uint32_t handle_size_aligned = aligned_size(ray_tracing_pipeline_properties.shaderGroupHandleSize, ray_tracing_pipeline_properties.shaderGroupHandleAlignment); + const uint32_t group_count = static_cast(shader_groups.size()); + const uint32_t sbt_size = group_count * handle_size_aligned; + + vkb::core::BufferBuilder builder{handle_size}; + builder.with_vma_usage(VMA_MEMORY_USAGE_CPU_TO_GPU); + builder.with_usage(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); // Raygen // Create binding table buffers for each shader type - raygen_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); - miss_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); - hit_shader_binding_table = std::make_unique(get_device(), handle_size, sbt_buffer_usage_flags, sbt_memory_usage, 0); + raygen_shader_binding_table = std::make_unique(get_device(), builder); + miss_shader_binding_table = std::make_unique(get_device(), builder); + hit_shader_binding_table = std::make_unique(get_device(), builder); // Copy the pipeline's shader handles into a host buffer std::vector shader_handle_storage(sbt_size); diff --git a/samples/extensions/ray_tracing_reflection/ray_tracing_reflection.cpp b/samples/extensions/ray_tracing_reflection/ray_tracing_reflection.cpp index eb96bffbd9..9d4d2f8361 100644 --- a/samples/extensions/ray_tracing_reflection/ray_tracing_reflection.cpp +++ b/samples/extensions/ray_tracing_reflection/ray_tracing_reflection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * SPDX-FileCopyrightText: Copyright (c) 2014-2023 NVIDIA CORPORATION + * SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION * SPDX-License-Identifier: Apache-2.0 */ @@ -570,13 +570,17 @@ void RaytracingReflection::create_shader_binding_tables() const uint32_t handle_alignment = ray_tracing_pipeline_properties.shaderGroupHandleAlignment; const uint32_t handle_size_aligned = aligned_size(handle_size, handle_alignment); - const VkBufferUsageFlags sbt_buffer_usage_flags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - const VmaMemoryUsage sbt_memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU; - // Create binding table buffers for each shader type - raygen_shader_binding_table = std::make_unique(get_device(), handle_size_aligned * rgen_index.size(), sbt_buffer_usage_flags, sbt_memory_usage, 0); - miss_shader_binding_table = std::make_unique(get_device(), handle_size_aligned * miss_index.size(), sbt_buffer_usage_flags, sbt_memory_usage, 0); - hit_shader_binding_table = std::make_unique(get_device(), handle_size_aligned * hit_index.size(), sbt_buffer_usage_flags, sbt_memory_usage, 0); + vkb::core::BufferBuilder builder{0}; + builder.with_vma_usage(VMA_MEMORY_USAGE_CPU_TO_GPU); + builder.with_usage(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + builder.create_info.size = handle_size_aligned * rgen_index.size(); + raygen_shader_binding_table = std::make_unique(get_device(), builder); + builder.create_info.size = handle_size_aligned * miss_index.size(); + miss_shader_binding_table = std::make_unique(get_device(), builder); + builder.create_info.size = handle_size_aligned * hit_index.size(); + hit_shader_binding_table = std::make_unique(get_device(), builder); // Copy the pipeline's shader handles into a host buffer const auto group_count = static_cast(rgen_index.size() + miss_index.size() + hit_index.size()); diff --git a/samples/extensions/synchronization_2/synchronization_2.cpp b/samples/extensions/synchronization_2/synchronization_2.cpp index 3980c2cff4..5779e3c42d 100644 --- a/samples/extensions/synchronization_2/synchronization_2.cpp +++ b/samples/extensions/synchronization_2/synchronization_2.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Sascha Willems +/* Copyright (c) 2021-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -307,8 +307,7 @@ void Synchronization2::prepare_storage_buffers() // Staging // SSBO won't be changed on the host after upload so copy to device local memory - vkb::core::Buffer staging_buffer{get_device(), storage_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY}; - staging_buffer.update(particle_buffer.data(), static_cast(storage_buffer_size)); + vkb::core::Buffer staging_buffer = vkb::core::Buffer::create_staging_buffer(get_device(), particle_buffer); compute.storage_buffer = std::make_unique(get_device(), storage_buffer_size, diff --git a/samples/performance/multi_draw_indirect/multi_draw_indirect.cpp b/samples/performance/multi_draw_indirect/multi_draw_indirect.cpp index 60d2b82eeb..ccdc4a37ab 100644 --- a/samples/performance/multi_draw_indirect/multi_draw_indirect.cpp +++ b/samples/performance/multi_draw_indirect/multi_draw_indirect.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Holochip Corporation +/* Copyright (c) 2021-2024, Holochip Corporation * * SPDX-License-Identifier: Apache-2.0 * @@ -320,21 +320,15 @@ void MultiDrawIndirect::load_scene() Texture texture; texture.n_mip_maps = static_cast(image->get_mipmaps().size()); assert(texture.n_mip_maps == 1); - texture.image = std::make_unique(*device, - image->get_extent(), - image->get_format(), - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VMA_MEMORY_USAGE_GPU_ONLY, - VK_SAMPLE_COUNT_1_BIT, - 1, - 1, - VK_IMAGE_TILING_OPTIMAL, - 0); - - const auto &data = image->get_data(); - auto data_buffer = std::make_unique(*device, data.size() * sizeof(data[0]), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU, VMA_ALLOCATION_CREATE_MAPPED_BIT, queue_families); - data_buffer->update(data.data(), data.size() * sizeof(data[0]), 0); - data_buffer->flush(); + + vkb::core::ImageBuilder builder{image->get_extent()}; + builder + .with_format(image->get_format()) + .with_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .with_vma_usage(VMA_MEMORY_USAGE_GPU_ONLY); + texture.image = std::make_unique(*device, builder); + + auto data_buffer = vkb::core::Buffer::create_staging_buffer(*device, image->get_data()); auto &texture_cmd = device->get_command_pool().request_command_buffer(); texture_cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, VK_NULL_HANDLE); @@ -355,7 +349,7 @@ void MultiDrawIndirect::load_scene() region.imageExtent = image->get_extent(); region.bufferOffset = offsets[0][0]; - texture_cmd.copy_buffer_to_image(*data_buffer, *texture.image, {region}); + texture_cmd.copy_buffer_to_image(data_buffer, *texture.image, {region}); texture_cmd.end(); auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 1f35a2c307..c7d1763536 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -378,7 +378,7 @@ set(CLI11_CUDA_TESTS OFF) set(CLI11_CLANG_TIDY OFF) add_subdirectory(cli11) if (TARGET CLI11) - set_property(TARGET CLI11 PROPERTY FOLDER "ThirdParty") + #set_property(TARGET CLI11 PROPERTY FOLDER "ThirdParty") endif() # OpenCL