Skip to content
Snippets Groups Projects
Verified Commit 292eb1de authored by Tobias Frisch's avatar Tobias Frisch
Browse files

[#59] Implemented VMA into buffer and image managers

parent 11c4ea48
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@
#include <vector>
#include <vulkan/vulkan.hpp>
#include <vk_mem_alloc.hpp>
#include "Handles.hpp"
......@@ -30,9 +31,8 @@ namespace vkcv
struct Buffer
{
vk::Buffer m_handle;
vk::DeviceMemory m_memory;
vma::Allocation m_allocation;
size_t m_size = 0;
void* m_mapped = nullptr;
bool m_mappable = false;
};
......
......@@ -28,32 +28,6 @@ namespace vkcv {
}
}
/**
* @brief searches memory type index for buffer allocation, combines requirements of buffer and application
* @param physicalMemoryProperties Memory Properties of physical device
* @param typeBits Bit field for suitable memory types
* @param requirements Property flags that are required
* @return memory type index for Buffer
*/
uint32_t searchBufferMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) {
const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount;
for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
const uint32_t memoryTypeBits = (1 << memoryIndex);
const bool isRequiredMemoryType = typeBits & memoryTypeBits;
const vk::MemoryPropertyFlags properties =
physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags;
const bool hasRequiredProperties =
(properties & requirements) == requirements;
if (isRequiredMemoryType && hasRequiredProperties)
return static_cast<int32_t>(memoryIndex);
}
// failed to find memory type
return -1;
}
BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) {
vk::BufferCreateFlags createFlags;
vk::BufferUsageFlags usageFlags;
......@@ -83,43 +57,48 @@ namespace vkcv {
usageFlags |= vk::BufferUsageFlagBits::eTransferDst;
}
const vk::Device& device = m_core->getContext().getDevice();
vk::Buffer buffer = device.createBuffer(
vk::BufferCreateInfo(createFlags, size, usageFlags)
);
const vk::MemoryRequirements requirements = device.getBufferMemoryRequirements(buffer);
const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice();
const vma::Allocator& allocator = m_core->getContext().getAllocator();
vk::MemoryPropertyFlags memoryTypeFlags;
vma::MemoryUsage memoryUsage;
bool mappable = false;
switch (memoryType) {
case BufferMemoryType::DEVICE_LOCAL:
memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal;
memoryUsage = vma::MemoryUsage::eGpuOnly;
mappable = false;
break;
case BufferMemoryType::HOST_VISIBLE:
memoryTypeFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
memoryUsage = vma::MemoryUsage::eCpuOnly;
mappable = true;
break;
default:
// TODO: maybe an issue
vkcv_log(LogLevel::WARNING, "Unknown buffer memory type");
memoryUsage = vma::MemoryUsage::eUnknown;
mappable = false;
break;
}
const uint32_t memoryTypeIndex = searchBufferMemoryType(
physicalDevice.getMemoryProperties(),
requirements.memoryTypeBits,
memoryTypeFlags
auto bufferAllocation = allocator.createBuffer(
vk::BufferCreateInfo(createFlags, size, usageFlags),
vma::AllocationCreateInfo(
vma::AllocationCreateFlags(),
memoryUsage,
memoryTypeFlags,
memoryTypeFlags,
0,
vma::Pool(),
nullptr
)
);
vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex));
device.bindBufferMemory(buffer, memory, 0);
vk::Buffer buffer = bufferAllocation.first;
vma::Allocation allocation = bufferAllocation.second;
const uint64_t id = m_buffers.size();
m_buffers.push_back({ buffer, memory, size, nullptr, mappable });
m_buffers.push_back({ buffer, allocation, size, mappable });
return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); });
}
......@@ -130,7 +109,7 @@ namespace vkcv {
vk::Buffer buffer;
vk::Buffer stagingBuffer;
vk::DeviceMemory stagingMemory;
vma::Allocation stagingAllocation;
size_t stagingLimit;
size_t stagingPosition;
......@@ -150,11 +129,11 @@ namespace vkcv {
const size_t remaining = info.size - info.stagingPosition;
const size_t mapped_size = std::min(remaining, info.stagingLimit);
const vk::Device& device = core->getContext().getDevice();
const vma::Allocator& allocator = core->getContext().getAllocator();
void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size);
void* mapped = allocator.mapMemory(info.stagingAllocation);
memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size);
device.unmapMemory(info.stagingMemory);
allocator.unmapMemory(info.stagingAllocation);
SubmitInfo submitInfo;
submitInfo.queueType = QueueType::Transfer;
......@@ -216,7 +195,13 @@ namespace vkcv {
auto& buffer = m_buffers[id];
return buffer.m_memory;
const vma::Allocator& allocator = m_core->getContext().getAllocator();
auto info = allocator.getAllocationInfo(
buffer.m_allocation
);
return info.deviceMemory;
}
void BufferManager::fillBuffer(const BufferHandle& handle, const void *data, size_t size, size_t offset) {
......@@ -232,11 +217,7 @@ namespace vkcv {
auto& buffer = m_buffers[id];
if (buffer.m_mapped) {
return;
}
const vk::Device& device = m_core->getContext().getDevice();
const vma::Allocator& allocator = m_core->getContext().getAllocator();
if (offset > buffer.m_size) {
return;
......@@ -245,9 +226,9 @@ namespace vkcv {
const size_t max_size = std::min(size, buffer.m_size - offset);
if (buffer.m_mappable) {
void* mapped = device.mapMemory(buffer.m_memory, offset, max_size);
memcpy(mapped, data, max_size);
device.unmapMemory(buffer.m_memory);
void* mapped = allocator.mapMemory(buffer.m_allocation);
memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size);
allocator.unmapMemory(buffer.m_allocation);
} else {
auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ];
......@@ -258,11 +239,9 @@ namespace vkcv {
info.buffer = buffer.m_handle;
info.stagingBuffer = stagingBuffer.m_handle;
info.stagingMemory = stagingBuffer.m_memory;
info.stagingAllocation = stagingBuffer.m_allocation;
const vk::MemoryRequirements stagingRequirements = device.getBufferMemoryRequirements(stagingBuffer.m_handle);
info.stagingLimit = stagingRequirements.size;
info.stagingLimit = stagingBuffer.m_size;
info.stagingPosition = 0;
copyFromStagingBuffer(m_core, info);
......@@ -282,19 +261,13 @@ namespace vkcv {
auto& buffer = m_buffers[id];
if (buffer.m_mapped) {
return nullptr;
}
const vk::Device& device = m_core->getContext().getDevice();
const vma::Allocator& allocator = m_core->getContext().getAllocator();
if (offset > buffer.m_size) {
return nullptr;
}
const size_t max_size = std::min(size, buffer.m_size - offset);
buffer.m_mapped = device.mapMemory(buffer.m_memory, offset, max_size);
return buffer.m_mapped;
return reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation)) + offset;
}
void BufferManager::unmapBuffer(const BufferHandle& handle) {
......@@ -306,14 +279,9 @@ namespace vkcv {
auto& buffer = m_buffers[id];
if (buffer.m_mapped == nullptr) {
return;
}
const vk::Device& device = m_core->getContext().getDevice();
const vma::Allocator& allocator = m_core->getContext().getAllocator();
device.unmapMemory(buffer.m_memory);
buffer.m_mapped = nullptr;
allocator.unmapMemory(buffer.m_allocation);
}
void BufferManager::destroyBufferById(uint64_t id) {
......@@ -323,16 +291,13 @@ namespace vkcv {
auto& buffer = m_buffers[id];
const vk::Device& device = m_core->getContext().getDevice();
if (buffer.m_memory) {
device.freeMemory(buffer.m_memory);
buffer.m_memory = nullptr;
}
const vma::Allocator& allocator = m_core->getContext().getAllocator();
if (buffer.m_handle) {
device.destroyBuffer(buffer.m_handle);
allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation);
buffer.m_handle = nullptr;
buffer.m_allocation = nullptr;
}
}
......
......@@ -12,26 +12,6 @@
namespace vkcv {
ImageManager::Image::Image(
vk::Image handle,
vk::DeviceMemory memory,
std::vector<vk::ImageView> views,
uint32_t width,
uint32_t height,
uint32_t depth,
vk::Format format,
uint32_t layers)
:
m_handle(handle),
m_memory(memory),
m_viewPerMip(views),
m_width(width),
m_height(height),
m_depth(depth),
m_format(format),
m_layers(layers)
{}
/**
* @brief searches memory type index for image allocation, combines requirements of image and application
* @param physicalMemoryProperties Memory Properties of physical device
......@@ -124,7 +104,7 @@ namespace vkcv {
imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
}
const vk::Device& device = m_core->getContext().getDevice();
const vma::Allocator& allocator = m_core->getContext().getAllocator();
vk::ImageType imageType = vk::ImageType::e3D;
vk::ImageViewType imageViewType = vk::ImageViewType::e3D;
......@@ -158,7 +138,7 @@ namespace vkcv {
vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa);
const vk::ImageCreateInfo imageCreateInfo(
const vk::ImageCreateInfo imageCreateInfo (
createFlags,
imageType,
format,
......@@ -172,21 +152,22 @@ namespace vkcv {
{},
vk::ImageLayout::eUndefined
);
vk::Image image = device.createImage(imageCreateInfo);
const vk::MemoryRequirements requirements = device.getImageMemoryRequirements(image);
vk::MemoryPropertyFlags memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal;
const uint32_t memoryTypeIndex = searchImageMemoryType(
physicalDevice.getMemoryProperties(),
requirements.memoryTypeBits,
memoryTypeFlags
auto imageAllocation = allocator.createImage(
imageCreateInfo,
vma::AllocationCreateInfo(
vma::AllocationCreateFlags(),
vma::MemoryUsage::eGpuOnly,
vk::MemoryPropertyFlagBits::eDeviceLocal,
vk::MemoryPropertyFlagBits::eDeviceLocal,
0,
vma::Pool(),
nullptr
)
);
vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex));
device.bindImageMemory(image, memory, 0);
vk::Image image = imageAllocation.first;
vma::Allocation allocation = imageAllocation.second;
vk::ImageAspectFlags aspectFlags;
......@@ -196,6 +177,8 @@ namespace vkcv {
aspectFlags = vk::ImageAspectFlagBits::eColor;
}
const vk::Device& device = m_core->getContext().getDevice();
std::vector<vk::ImageView> views;
for (uint32_t mip = 0; mip < mipCount; mip++) {
const vk::ImageViewCreateInfo imageViewCreateInfo(
......@@ -222,11 +205,11 @@ namespace vkcv {
}
const uint64_t id = m_images.size();
m_images.push_back(Image(image, memory, views, width, height, depth, format, arrayLayers));
m_images.push_back({ image, allocation, views, width, height, depth, format, arrayLayers, vk::ImageLayout::eUndefined });
return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); });
}
ImageHandle ImageManager::createSwapchainImage() {
ImageHandle ImageManager::createSwapchainImage() const {
return ImageHandle::createSwapchainImageHandle();
}
......@@ -262,10 +245,16 @@ namespace vkcv {
auto& image = m_images[id];
return image.m_memory;
const vma::Allocator& allocator = m_core->getContext().getAllocator();
auto info = allocator.getAllocationInfo(
image.m_allocation
);
return info.deviceMemory;
}
vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, const size_t mipLevel) const {
vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel) const {
if (handle.isSwapchainImage()) {
return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0];
......@@ -626,15 +615,14 @@ namespace vkcv {
view = nullptr;
}
}
if (image.m_memory) {
device.freeMemory(image.m_memory);
image.m_memory = nullptr;
}
const vma::Allocator& allocator = m_core->getContext().getAllocator();
if (image.m_handle) {
device.destroyImage(image.m_handle);
allocator.destroyImage(image.m_handle, image.m_allocation);
image.m_handle = nullptr;
image.m_allocation = nullptr;
}
}
......@@ -670,11 +658,11 @@ namespace vkcv {
m_currentSwapchainInputImage = index;
}
void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views,
void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views,
uint32_t width, uint32_t height, vk::Format format) {
// destroy old views
for (auto image : m_swapchainImages) {
for (const auto& image : m_swapchainImages) {
for (const auto& view : image.m_viewPerMip) {
m_core->getContext().getDevice().destroyImageView(view);
}
......@@ -683,7 +671,17 @@ namespace vkcv {
assert(images.size() == views.size());
m_swapchainImages.clear();
for (size_t i = 0; i < images.size(); i++) {
m_swapchainImages.push_back(Image(images[i], nullptr, { views[i] }, width, height, 1, format, 1));
m_swapchainImages.push_back({
images[i],
nullptr,
{ views[i] },
width,
height,
1,
format,
1,
vk::ImageLayout::eUndefined
});
}
}
......
......@@ -6,6 +6,7 @@
*/
#include <vector>
#include <vulkan/vulkan.hpp>
#include <vk_mem_alloc.hpp>
#include "vkcv/BufferManager.hpp"
#include "vkcv/Handles.hpp"
......@@ -20,28 +21,16 @@ namespace vkcv {
struct Image
{
vk::Image m_handle;
vk::DeviceMemory m_memory;
vma::Allocation m_allocation;
std::vector<vk::ImageView> m_viewPerMip;
uint32_t m_width = 0;
uint32_t m_height = 0;
uint32_t m_depth = 0;
uint32_t m_width;
uint32_t m_height;
uint32_t m_depth;
vk::Format m_format;
uint32_t m_layers = 1;
vk::ImageLayout m_layout = vk::ImageLayout::eUndefined;
uint32_t m_layers;
vk::ImageLayout m_layout;
private:
// struct is public so utility functions can access members, but only ImageManager can create Image
friend ImageManager;
Image(
vk::Image handle,
vk::DeviceMemory memory,
std::vector<vk::ImageView> views,
uint32_t width,
uint32_t height,
uint32_t depth,
vk::Format format,
uint32_t layers);
Image();
};
private:
......@@ -52,7 +41,7 @@ namespace vkcv {
std::vector<Image> m_swapchainImages;
int m_currentSwapchainInputImage;
ImageManager(BufferManager& bufferManager) noexcept;
explicit ImageManager(BufferManager& bufferManager) noexcept;
/**
* Destroys and deallocates image represented by a given
......@@ -82,7 +71,8 @@ namespace vkcv {
bool supportColorAttachment,
Multisampling msaa);
ImageHandle createSwapchainImage();
[[nodiscard]]
ImageHandle createSwapchainImage() const;
[[nodiscard]]
vk::Image getVulkanImage(const ImageHandle& handle) const;
......@@ -91,7 +81,7 @@ namespace vkcv {
vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const;
[[nodiscard]]
vk::ImageView getVulkanImageView(const ImageHandle& handle, const size_t mipLevel = 0) const;
vk::ImageView getVulkanImageView(const ImageHandle& handle, size_t mipLevel = 0) const;
void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout);
void recordImageLayoutTransition(
......@@ -124,8 +114,9 @@ namespace vkcv {
uint32_t getImageMipCount(const ImageHandle& handle) const;
void setCurrentSwapchainImageIndex(int index);
void setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views,
uint32_t width, uint32_t height, vk::Format format);
void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views,
uint32_t width, uint32_t height, vk::Format format);
};
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment