Skip to content

Commit

Permalink
Allocated refactor (#906)
Browse files Browse the repository at this point in the history
* Common VMA base class

* Use staging buffer convenience method where possible
  • Loading branch information
jherico authored Mar 11, 2024
1 parent 187e806 commit 002fa05
Show file tree
Hide file tree
Showing 52 changed files with 1,400 additions and 1,403 deletions.
7 changes: 3 additions & 4 deletions framework/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,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
Expand All @@ -250,9 +251,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
Expand Down Expand Up @@ -292,6 +292,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
Expand All @@ -301,9 +302,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
Expand Down
21 changes: 3 additions & 18 deletions framework/api_vulkan_sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -999,12 +999,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<VkBufferImageCopy> bufferCopyRegions;
Expand Down Expand Up @@ -1095,12 +1090,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<VkBufferImageCopy> buffer_copy_regions;
Expand Down Expand Up @@ -1194,12 +1184,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<VkBufferImageCopy> buffer_copy_regions;
Expand Down
10 changes: 7 additions & 3 deletions framework/core/acceleration_structure.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2021, Sascha Willems
/* Copyright (c) 2021-2024, Sascha Willems
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -23,7 +23,7 @@ namespace vkb
{
namespace core
{
AccelerationStructure::AccelerationStructure(Device & device,
AccelerationStructure::AccelerationStructure(Device &device,
VkAccelerationStructureTypeKHR type) :
device{device},
type{type}
Expand Down Expand Up @@ -202,7 +202,11 @@ 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<vkb::core::ScratchBuffer>(device, build_sizes_info.buildScratchSize);
scratch_buffer = std::make_unique<vkb::core::Buffer>(
device,
build_sizes_info.buildScratchSize,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VMA_MEMORY_USAGE_GPU_ONLY);

build_geometry_info.scratchData.deviceAddress = scratch_buffer->get_device_address();
build_geometry_info.dstAccelerationStructure = handle;
Expand Down
9 changes: 4 additions & 5 deletions framework/core/acceleration_structure.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2021, Sascha Willems
/* Copyright (c) 2021-2024, Sascha Willems
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -20,7 +20,6 @@
#include "common/helpers.h"
#include "common/vk_common.h"
#include "core/buffer.h"
#include "core/scratch_buffer.h"

namespace vkb
{
Expand All @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -149,7 +148,7 @@ class AccelerationStructure
bool updated = false;
};

std::unique_ptr<vkb::core::ScratchBuffer> scratch_buffer;
std::unique_ptr<vkb::core::Buffer> scratch_buffer;

std::map<uint64_t, Geometry> geometries{};

Expand Down
233 changes: 233 additions & 0 deletions framework/core/allocated.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/* 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;
}
}

AllocatedBase::AllocatedBase(const VmaAllocationCreateInfo &alloc_create_info) :
alloc_create_info(alloc_create_info)
{
}

AllocatedBase::AllocatedBase(AllocatedBase &&other) noexcept :
alloc_create_info(std::exchange(other.alloc_create_info, {})),
allocation(std::exchange(other.allocation, {})),
mapped_data(std::exchange(other.mapped_data, {})),
coherent(std::exchange(other.coherent, {})),
persistent(std::exchange(other.persistent, {}))
{
}

const uint8_t *AllocatedBase::get_data() const
{
return mapped_data;
}

VkDeviceMemory AllocatedBase::get_memory() const
{
VmaAllocationInfo alloc_info;
vmaGetAllocationInfo(get_memory_allocator(), allocation, &alloc_info);
return alloc_info.deviceMemory;
}

void AllocatedBase::flush(VkDeviceSize offset, VkDeviceSize size)
{
if (!coherent)
{
vmaFlushAllocation(get_memory_allocator(), allocation, offset, size);
}
}

uint8_t *AllocatedBase::map()
{
if (!persistent && !mapped())
{
VK_CHECK(vmaMapMemory(get_memory_allocator(), allocation, reinterpret_cast<void **>(&mapped_data)));
assert(mapped_data);
}
return mapped_data;
}

void AllocatedBase::unmap()
{
if (!persistent && mapped())
{
vmaUnmapMemory(get_memory_allocator(), allocation);
mapped_data = nullptr;
}
}

size_t AllocatedBase::update(const uint8_t *data, size_t size, 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();
}
return size;
}

size_t AllocatedBase::update(void const *data, size_t size, size_t offset)
{
return update(reinterpret_cast<const uint8_t *>(data), size, offset);
}

void AllocatedBase::post_create(VmaAllocationInfo const &allocation_info)
{
VkMemoryPropertyFlags memory_properties;
vmaGetAllocationMemoryProperties(get_memory_allocator(), allocation, &memory_properties);
coherent = (memory_properties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
mapped_data = static_cast<uint8_t *>(allocation_info.pMappedData);
persistent = mapped();
}

[[nodiscard]] VkBuffer AllocatedBase::create_buffer(VkBufferCreateInfo const &create_info)
{
VkBuffer handleResult = VK_NULL_HANDLE;
VmaAllocationInfo allocation_info{};

auto result = vmaCreateBuffer(
get_memory_allocator(),
&create_info,
&alloc_create_info,
&handleResult,
&allocation,
&allocation_info);

if (result != VK_SUCCESS)
{
throw VulkanException{result, "Cannot create Buffer"};
}
post_create(allocation_info);
return handleResult;
}

[[nodiscard]] VkImage AllocatedBase::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{};

#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(
get_memory_allocator(),
&create_info,
&alloc_create_info,
&handleResult,
&allocation,
&allocation_info);

if (result != VK_SUCCESS)
{
throw VulkanException{result, "Cannot create Image"};
}

post_create(allocation_info);
return handleResult;
}

void AllocatedBase::destroy_buffer(VkBuffer handle)
{
if (handle != VK_NULL_HANDLE && allocation != VK_NULL_HANDLE)
{
unmap();
vmaDestroyBuffer(get_memory_allocator(), handle, allocation);
clear();
}
}

void AllocatedBase::destroy_image(VkImage image)
{
if (image != VK_NULL_HANDLE && allocation != VK_NULL_HANDLE)
{
unmap();
vmaDestroyImage(get_memory_allocator(), image, allocation);
clear();
}
}

bool AllocatedBase::mapped() const
{
return mapped_data != nullptr;
}

void AllocatedBase::clear()
{
mapped_data = nullptr;
persistent = false;
alloc_create_info = {};
}

} // namespace allocated
} // namespace vkb
Loading

0 comments on commit 002fa05

Please sign in to comment.