blob: e623340ad8dbb630b646a644fe6cfc48e7154c21 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "lib/escher/vk/vma_gpu_allocator.h"
#include "lib/escher/util/image_utils.h"
namespace {
class VmaGpuMem : public escher::GpuMem {
public:
VmaGpuMem(VmaAllocator allocator, VmaAllocation allocation,
VmaAllocationInfo info)
: GpuMem(info.deviceMemory, info.size, info.offset,
static_cast<uint8_t*>(info.pMappedData)),
allocator_(allocator),
allocation_(allocation) {}
~VmaGpuMem() { vmaFreeMemory(allocator_, allocation_); }
private:
VmaAllocator allocator_;
VmaAllocation allocation_;
};
class VmaBuffer : public escher::Buffer {
public:
VmaBuffer(escher::ResourceManager* manager, VmaAllocator allocator,
VmaAllocation allocation, VmaAllocationInfo info, vk::Buffer buffer)
: Buffer(manager, buffer, info.size,
static_cast<uint8_t*>(info.pMappedData)),
allocator_(allocator),
allocation_(allocation) {}
~VmaBuffer() { vmaDestroyBuffer(allocator_, vk(), allocation_); }
private:
VmaAllocator allocator_;
VmaAllocation allocation_;
};
// Vma objects (i.e., buffers, images) with mapped memory are cleaned up by
// destroying the original object, not by destroying a separate memory
// allocation object. However, we can request mapped pointers from vma objects.
// Therefore, we implement an 'out_mem' GpuMem object by keeping a strong
// reference to the original vma object, and wrapping only the mapped pointer,
// offset, and size parameters.
class VmaMappedGpuMem : public escher::GpuMem {
public:
VmaMappedGpuMem(VmaAllocationInfo info,
const fxl::RefPtr<escher::WaitableResource>& keep_alive)
: GpuMem(info.deviceMemory, info.size, info.offset,
static_cast<uint8_t*>(info.pMappedData)),
keep_alive_(keep_alive) {}
private:
const fxl::RefPtr<escher::WaitableResource> keep_alive_;
};
class VmaImage : public escher::Image {
public:
VmaImage(escher::ResourceManager* manager, escher::ImageInfo image_info,
vk::Image image, VmaAllocator allocator, VmaAllocation allocation,
VmaAllocationInfo allocation_info)
: Image(manager, image_info, image, allocation_info.size,
static_cast<uint8_t*>(allocation_info.pMappedData)),
allocator_(allocator),
allocation_(allocation) {}
~VmaImage() { vmaDestroyImage(allocator_, vk(), allocation_); }
private:
VmaAllocator allocator_;
VmaAllocation allocation_;
};
} // namespace
namespace escher {
VmaGpuAllocator::VmaGpuAllocator(const VulkanContext& context) {
FXL_DCHECK(context.device);
FXL_DCHECK(context.physical_device);
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = context.physical_device;
allocatorInfo.device = context.device;
allocatorInfo.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
vmaCreateAllocator(&allocatorInfo, &allocator_);
}
VmaGpuAllocator::~VmaGpuAllocator() { vmaDestroyAllocator(allocator_); }
GpuMemPtr VmaGpuAllocator::AllocateMemory(vk::MemoryRequirements reqs,
vk::MemoryPropertyFlags flags) {
// Needed so we have a pointer to the C-style type.
VkMemoryRequirements c_reqs = reqs;
// VMA specific allocation parameters.
VmaAllocationCreateInfo create_info = {
VMA_ALLOCATION_CREATE_MAPPED_BIT,
VMA_MEMORY_USAGE_UNKNOWN,
static_cast<VkMemoryPropertyFlags>(flags),
0u,
0u,
VK_NULL_HANDLE,
nullptr};
// Output structs.
VmaAllocation allocation;
VmaAllocationInfo allocation_info;
auto status = vmaAllocateMemory(allocator_, &c_reqs, &create_info,
&allocation, &allocation_info);
FXL_DCHECK(status == VK_SUCCESS)
<< "vmaAllocateMemory failed with status code " << status;
if (status != VK_SUCCESS)
return nullptr;
return fxl::AdoptRef(new VmaGpuMem(allocator_, allocation, allocation_info));
}
BufferPtr VmaGpuAllocator::AllocateBuffer(
ResourceManager* manager, vk::DeviceSize size,
vk::BufferUsageFlags usage_flags,
vk::MemoryPropertyFlags memory_property_flags, GpuMemPtr* out_ptr) {
vk::BufferCreateInfo info;
info.size = size;
info.usage = usage_flags;
info.sharingMode = vk::SharingMode::eExclusive;
// Needed so we can have a pointer to the C-style type.
VkBufferCreateInfo c_buffer_info = info;
VmaAllocationCreateInfo create_info = {
VMA_ALLOCATION_CREATE_MAPPED_BIT,
VMA_MEMORY_USAGE_UNKNOWN,
static_cast<VkMemoryPropertyFlags>(memory_property_flags),
0u,
0u,
VK_NULL_HANDLE,
nullptr};
if (out_ptr) {
create_info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
}
// Output structs.
VkBuffer buffer;
VmaAllocation allocation;
VmaAllocationInfo allocation_info;
auto status = vmaCreateBuffer(allocator_, &c_buffer_info, &create_info,
&buffer, &allocation, &allocation_info);
FXL_DCHECK(status == VK_SUCCESS)
<< "vmaAllocateMemory failed with status code " << status;
if (status != VK_SUCCESS)
return nullptr;
auto retval = fxl::AdoptRef(
new VmaBuffer(manager, allocator_, allocation, allocation_info, buffer));
if (out_ptr) {
FXL_DCHECK(allocation_info.offset == 0);
*out_ptr = fxl::AdoptRef(new VmaMappedGpuMem(allocation_info, retval));
}
return retval;
}
ImagePtr VmaGpuAllocator::AllocateImage(ResourceManager* manager,
const ImageInfo& info,
GpuMemPtr* out_ptr) {
// Needed so we have a pointer to the C-style type.
VkImageCreateInfo c_image_info = image_utils::CreateVkImageCreateInfo(info);
VmaAllocationCreateInfo create_info = {
VMA_ALLOCATION_CREATE_MAPPED_BIT,
VMA_MEMORY_USAGE_UNKNOWN,
static_cast<VkMemoryPropertyFlags>(info.memory_flags),
0u,
0u,
VK_NULL_HANDLE,
nullptr};
if (out_ptr) {
create_info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
}
// Output structs.
VkImage image;
VmaAllocation allocation;
VmaAllocationInfo allocation_info;
auto status = vmaCreateImage(allocator_, &c_image_info, &create_info, &image,
&allocation, &allocation_info);
FXL_DCHECK(status == VK_SUCCESS)
<< "vmaAllocateMemory failed with status code " << status;
if (status != VK_SUCCESS)
return nullptr;
auto retval = fxl::AdoptRef(new VmaImage(manager, info, image, allocator_,
allocation, allocation_info));
if (out_ptr) {
FXL_DCHECK(allocation_info.offset == 0);
*out_ptr = fxl::AdoptRef(new VmaMappedGpuMem(allocation_info, retval));
}
return retval;
}
uint32_t VmaGpuAllocator::GetTotalBytesAllocated() const {
VmaStats stats;
vmaCalculateStats(allocator_, &stats);
return stats.total.usedBytes;
}
} // namespace escher