Skip to content

Commit

Permalink
merian: MemoryAllocation add methods for flush and invalidate
Browse files Browse the repository at this point in the history
  • Loading branch information
LDAP committed Nov 4, 2024
1 parent 8a53ceb commit 55920e2
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 63 deletions.
23 changes: 15 additions & 8 deletions include/merian/vk/memory/memory_allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,10 @@ inline std::string format_as(const MemoryAllocationInfo& alloc_info) {
*/
class MemoryAllocation : public std::enable_shared_from_this<MemoryAllocation> {
public:
MemoryAllocation(const ContextHandle& context) : context(context) {}
MemoryAllocation(const ContextHandle& context);

// unmaps and frees the memory when called
virtual ~MemoryAllocation() = default;

// ------------------------------------------------------------------------------------

// can only be called once
virtual void free() = 0;
virtual ~MemoryAllocation();

// ------------------------------------------------------------------------------------

Expand All @@ -133,7 +128,19 @@ class MemoryAllocation : public std::enable_shared_from_this<MemoryAllocation> {
return (T*)map();
}

// Maps device memory to system memory.
// Invalidates memory of a allocation. Call this before reading from non host-coherent memory
// type or before reading from persistently mapped host-coherent memory.
// Map does not do that automatically, internally this is a call to
// vkInvalidateMappedMemoryRanges
virtual void invalidate(const VkDeviceSize offset = 0, const VkDeviceSize size = VK_WHOLE_SIZE) = 0;

// Call this after writing to non host-coherent memory
// or after writing to persistently mapped host-coherent memory.
// Map does not do that automatically, internally this is a call to vkFlushMappedMemoryRanges
virtual void flush(const VkDeviceSize offset = 0, const VkDeviceSize size = VK_WHOLE_SIZE) = 0;

// Maps device memory to system memory. This should return the same pointer if called multiple
// times before "unmap".
virtual void* map() = 0;

// Unmap memHandle
Expand Down
27 changes: 14 additions & 13 deletions include/merian/vk/memory/memory_allocator_vma.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ class VMAMemoryAllocation : public MemoryAllocation {

// ------------------------------------------------------------------------------------

void free() override;
void invalidate(const VkDeviceSize offset = 0, const VkDeviceSize size = VK_WHOLE_SIZE) override;

// ------------------------------------------------------------------------------------
void flush(const VkDeviceSize offset = 0, const VkDeviceSize size = VK_WHOLE_SIZE) override;

// Maps device memory to system memory.
void* map() override;

// Unmap memHandle
void unmap() override;

// ------------------------------------------------------------------------------------
Expand All @@ -52,7 +50,7 @@ class VMAMemoryAllocation : public MemoryAllocation {
MemoryAllocationInfo get_memory_info() const override;

// ------------------------------------------------------------------------------------

ImageHandle create_aliasing_image(const vk::ImageCreateInfo& image_create_info) override;

BufferHandle create_aliasing_buffer(const vk::BufferCreateInfo& buffer_create_info) override;
Expand All @@ -68,11 +66,13 @@ class VMAMemoryAllocation : public MemoryAllocation {
void properties(Properties& props) override;

private:
void free();

const std::shared_ptr<VMAMemoryAllocator> allocator;
const MemoryMappingType mapping_type;
VmaAllocation m_allocation;
mutable std::mutex allocation_mutex;
bool is_mapped = false;
void* mapped_memory = nullptr;
};

class VMAMemoryAllocator : public MemoryAllocator {
Expand All @@ -95,13 +95,14 @@ class VMAMemoryAllocator : public MemoryAllocator {

// ------------------------------------------------------------------------------------

MemoryAllocationHandle allocate_memory(const vk::MemoryPropertyFlags required_flags,
const vk::MemoryRequirements& requirements,
const std::string& debug_name = {},
const MemoryMappingType mapping_type = MemoryMappingType::NONE,
const vk::MemoryPropertyFlags preferred_flags = {},
const bool dedicated = false,
const float dedicated_priority = 1.0) override;
MemoryAllocationHandle
allocate_memory(const vk::MemoryPropertyFlags required_flags,
const vk::MemoryRequirements& requirements,
const std::string& debug_name = {},
const MemoryMappingType mapping_type = MemoryMappingType::NONE,
const vk::MemoryPropertyFlags preferred_flags = {},
const bool dedicated = false,
const float dedicated_priority = 1.0) override;

BufferHandle
create_buffer(const vk::BufferCreateInfo buffer_create_info,
Expand Down
5 changes: 5 additions & 0 deletions src/merian/vk/memory/memory_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ uint32_t getMemoryType(const vk::PhysicalDeviceMemoryProperties& memoryPropertie
return ~0u;
}

MemoryAllocation::MemoryAllocation(const ContextHandle& context) : context(context) {}

// unmaps and frees the memory when called
MemoryAllocation::~MemoryAllocation() {}

} // namespace merian
98 changes: 56 additions & 42 deletions src/merian/vk/memory/memory_allocator_vma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,58 @@ namespace merian {

VMAMemoryAllocation::~VMAMemoryAllocation() {
SPDLOG_TRACE("destroy VMA allocation ({})", fmt::ptr(this));
if (is_mapped) {
unmap();
}
unmap();
free();
};

// ------------------------------------------------------------------------------------

void VMAMemoryAllocation::free() {
std::lock_guard<std::mutex> lock(allocation_mutex);
assert(m_allocation);

if (m_allocation) {
SPDLOG_TRACE("freeing memory ({})", fmt::ptr(this));
vmaFreeMemory(allocator->vma_allocator, m_allocation);
m_allocation = nullptr;
} else {
SPDLOG_WARN("VMA allocation ({}) was already freed", fmt::ptr(this));
}
SPDLOG_TRACE("freeing memory ({})", fmt::ptr(this));
vmaFreeMemory(allocator->vma_allocator, m_allocation);
m_allocation = nullptr;
};

// ------------------------------------------------------------------------------------

void VMAMemoryAllocation::invalidate(const VkDeviceSize offset, const VkDeviceSize size) {
vmaInvalidateAllocation(allocator->vma_allocator, m_allocation, offset, size);
};

void VMAMemoryAllocation::flush(const VkDeviceSize offset, const VkDeviceSize size) {
vmaFlushAllocation(allocator->vma_allocator, m_allocation, offset, size);
};

// Maps device memory to system memory.
void* VMAMemoryAllocation::map() {
std::lock_guard<std::mutex> lock(allocation_mutex);

assert(m_allocation); // freed?
assert(mapping_type != MemoryMappingType::NONE);

void* ptr;
check_result(vmaMapMemory(allocator->vma_allocator, m_allocation, &ptr),
if (mapped_memory != nullptr) {
return mapped_memory;
}

check_result(vmaMapMemory(allocator->vma_allocator, m_allocation, &mapped_memory),
"mapping memory failed");
is_mapped = true;
return ptr;
return mapped_memory;
};

// Unmap memHandle
void VMAMemoryAllocation::unmap() {
std::lock_guard<std::mutex> lock(allocation_mutex);
assert(m_allocation); // freed?
assert(m_allocation);

if (mapped_memory == nullptr) {
return;
}

vmaUnmapMemory(allocator->vma_allocator, m_allocation);
is_mapped = false;
mapped_memory = nullptr;
};

// ------------------------------------------------------------------------------------
Expand Down Expand Up @@ -87,10 +97,10 @@ VMAMemoryAllocation::create_aliasing_buffer(const vk::BufferCreateInfo& buffer_c
MemoryAllocationInfo VMAMemoryAllocation::get_memory_info() const {
const std::lock_guard<std::mutex> lock(allocation_mutex);

VmaAllocationInfo allocInfo;
vmaGetAllocationInfo(allocator->vma_allocator, m_allocation, &allocInfo);
return MemoryAllocationInfo{allocInfo.deviceMemory, allocInfo.offset, allocInfo.size,
allocInfo.pName};
VmaAllocationInfo alloc_info;
vmaGetAllocationInfo(allocator->vma_allocator, m_allocation, &alloc_info);
return MemoryAllocationInfo{alloc_info.deviceMemory, alloc_info.offset, alloc_info.size,
alloc_info.pName};
};

MemoryAllocatorHandle VMAMemoryAllocation::get_allocator() const {
Expand All @@ -99,7 +109,11 @@ MemoryAllocatorHandle VMAMemoryAllocation::get_allocator() const {

void VMAMemoryAllocation::properties(Properties& props) {
MemoryAllocation::properties(props);
props.output_text(fmt::format("Mapped: {}", is_mapped));

props.output_text(fmt::format("Mapped: {}", mapped_memory != nullptr));
if (mapped_memory != nullptr) {
props.output_text(fmt::format("Mapped at: {}", fmt::ptr(mapped_memory)));
}
}

//--------------------------------------------------------------------------------------------------
Expand All @@ -124,23 +138,23 @@ VMAMemoryAllocator::make_allocator(const ContextHandle& context,
VMAMemoryAllocator::VMAMemoryAllocator(const ContextHandle& context,
const VmaAllocatorCreateFlags flags)
: MemoryAllocator(context) {
VmaAllocatorCreateInfo allocatorInfo = {.flags = flags,
.physicalDevice =
context->physical_device.physical_device,
.device = context->device,
.preferredLargeHeapBlockSize = 0,
.pAllocationCallbacks = nullptr,
.pDeviceMemoryCallbacks = nullptr,
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = nullptr,
.instance = context->instance,
.vulkanApiVersion = context->vk_api_version,
VmaAllocatorCreateInfo allocator_info = {.flags = flags,
.physicalDevice =
context->physical_device.physical_device,
.device = context->device,
.preferredLargeHeapBlockSize = 0,
.pAllocationCallbacks = nullptr,
.pDeviceMemoryCallbacks = nullptr,
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = nullptr,
.instance = context->instance,
.vulkanApiVersion = context->vk_api_version,
#if VMA_EXTERNAL_MEMORY
.pTypeExternalMemoryHandleTypes = nullptr
.pTypeExternalMemoryHandleTypes = nullptr
#endif
};
SPDLOG_DEBUG("create VMA allocator ({})", fmt::ptr(this));
vmaCreateAllocator(&allocatorInfo, &vma_allocator);
vmaCreateAllocator(&allocator_info, &vma_allocator);
}

VMAMemoryAllocator::~VMAMemoryAllocator() {
Expand All @@ -151,7 +165,7 @@ VMAMemoryAllocator::~VMAMemoryAllocator() {
// ----------------------------------------------------------------------------------------------

void log_allocation([[maybe_unused]] const VmaAllocationInfo& info,
[[maybe_unused]] const MemoryAllocationHandle memory,
[[maybe_unused]] const MemoryAllocationHandle& memory,
[[maybe_unused]] const std::string& name) {
if (!name.empty())
SPDLOG_TRACE("allocated {} of memory at offset {} ({}, {})", format_size(info.size),
Expand All @@ -176,7 +190,7 @@ VmaAllocationCreateInfo make_create_info(const VmaMemoryUsage usage,
const MemoryMappingType mapping_type,
const bool dedicated,
const float dedicated_priority) {
VmaAllocationCreateInfo vmaAllocInfo{
VmaAllocationCreateInfo vma_alloc_info{
.flags = {},
.usage = usage,
.requiredFlags = static_cast<VkMemoryPropertyFlags>(required_flags),
Expand All @@ -187,11 +201,11 @@ VmaAllocationCreateInfo make_create_info(const VmaMemoryUsage usage,
.priority = dedicated_priority,
};
// clang-format off
vmaAllocInfo.flags |= dedicated ? VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT : 0;
vmaAllocInfo.flags |= mapping_type == MemoryMappingType::HOST_ACCESS_RANDOM ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0;
vmaAllocInfo.flags |= mapping_type == MemoryMappingType::HOST_ACCESS_SEQUENTIAL_WRITE ? VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT : 0;
vma_alloc_info.flags |= dedicated ? VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT : 0;
vma_alloc_info.flags |= mapping_type == MemoryMappingType::HOST_ACCESS_RANDOM ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0;
vma_alloc_info.flags |= mapping_type == MemoryMappingType::HOST_ACCESS_SEQUENTIAL_WRITE ? VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT : 0;
// clang-format on
return vmaAllocInfo;
return vma_alloc_info;
}

MemoryAllocationHandle
Expand All @@ -202,7 +216,7 @@ VMAMemoryAllocator::allocate_memory(const vk::MemoryPropertyFlags required_flags
const vk::MemoryPropertyFlags preferred_flags,
const bool dedicated,
const float dedicated_priority) {
VmaAllocationCreateInfo vmaAllocInfo =
VmaAllocationCreateInfo vma_alloc_info =
make_create_info(VMA_MEMORY_USAGE_UNKNOWN, required_flags, preferred_flags, mapping_type,
dedicated, dedicated_priority);

Expand All @@ -211,7 +225,7 @@ VMAMemoryAllocator::allocate_memory(const vk::MemoryPropertyFlags required_flags
VmaAllocationInfo allocation_info;
VmaAllocation allocation;
check_result(
vmaAllocateMemory(vma_allocator, &mem_reqs, &vmaAllocInfo, &allocation, &allocation_info),
vmaAllocateMemory(vma_allocator, &mem_reqs, &vma_alloc_info, &allocation, &allocation_info),
"could not allocate memory");

if (!debug_name.empty())
Expand Down

0 comments on commit 55920e2

Please sign in to comment.