Added VMA
This commit is contained in:
@@ -28,26 +28,32 @@ Buffer::Buffer(Device& device, vk::DeviceSize instanceSize, u32 instanceCount,
|
||||
alignmentSize = getAlignment(instanceSize, minOffsetAlignment);
|
||||
bufferSize = alignmentSize * instanceCount;
|
||||
device.createBuffer(bufferSize, usageFlags, memoryPropertyFlags, buffer,
|
||||
memory);
|
||||
allocation);
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
unmap();
|
||||
this->device.get()->destroyBuffer(this->buffer);
|
||||
this->device.get()->freeMemory(this->memory);
|
||||
vmaDestroyBuffer(this->device.getAllocator(), this->buffer, this->allocation);
|
||||
}
|
||||
|
||||
// VMA always maps the whole allocation, so `size` only exists to keep the
|
||||
// interface; `offset` is applied to the returned pointer.
|
||||
vk::Result Buffer::map(vk::DeviceSize size, vk::DeviceSize offset) {
|
||||
SOPHIA_ASSERT(buffer && memory, "Called map on buffer before create");
|
||||
SOPHIA_ASSERT(buffer && allocation, "Called map on buffer before create");
|
||||
(void)size;
|
||||
|
||||
vk::MemoryMapFlags emptyFlag{};
|
||||
return this->device.get()->mapMemory(this->memory, offset, size, emptyFlag,
|
||||
&this->mapped);
|
||||
void* base = nullptr;
|
||||
vk::Result result = static_cast<vk::Result>(
|
||||
vmaMapMemory(this->device.getAllocator(), this->allocation, &base));
|
||||
if (result == vk::Result::eSuccess) {
|
||||
this->mapped = static_cast<char*>(base) + offset;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Buffer::unmap() {
|
||||
if (mapped) {
|
||||
this->device.get()->unmapMemory(this->memory);
|
||||
vmaUnmapMemory(this->device.getAllocator(), this->allocation);
|
||||
mapped = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -66,19 +72,13 @@ void Buffer::writeToBuffer(void* data, vk::DeviceSize size,
|
||||
}
|
||||
|
||||
vk::Result Buffer::flush(vk::DeviceSize size, vk::DeviceSize offset) {
|
||||
vk::MappedMemoryRange mappedRange = {};
|
||||
mappedRange.memory = memory;
|
||||
mappedRange.offset = offset;
|
||||
mappedRange.size = size;
|
||||
return this->device.get()->flushMappedMemoryRanges(1, &mappedRange);
|
||||
return static_cast<vk::Result>(vmaFlushAllocation(
|
||||
this->device.getAllocator(), this->allocation, offset, size));
|
||||
}
|
||||
|
||||
vk::Result Buffer::invalidate(vk::DeviceSize size, vk::DeviceSize offset) {
|
||||
vk::MappedMemoryRange mappedRange = {};
|
||||
mappedRange.memory = memory;
|
||||
mappedRange.offset = offset;
|
||||
mappedRange.size = size;
|
||||
return this->device.get()->invalidateMappedMemoryRanges(1, &mappedRange);
|
||||
return static_cast<vk::Result>(vmaInvalidateAllocation(
|
||||
this->device.getAllocator(), this->allocation, offset, size));
|
||||
}
|
||||
|
||||
vk::DescriptorBufferInfo Buffer::descriptorInfo(vk::DeviceSize size,
|
||||
|
||||
@@ -55,7 +55,7 @@ class Buffer {
|
||||
Device& device;
|
||||
void* mapped = nullptr;
|
||||
vk::Buffer buffer = VK_NULL_HANDLE;
|
||||
vk::DeviceMemory memory = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
|
||||
vk::DeviceSize bufferSize;
|
||||
uint32_t instanceCount;
|
||||
|
||||
@@ -69,10 +69,14 @@ Device::Device(Window* window)
|
||||
}
|
||||
pickPhysicalDevice();
|
||||
createLogicalDevice();
|
||||
createAllocator();
|
||||
createCommandPool();
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
vmaDestroyAllocator(this->allocator);
|
||||
log::trace("destroyed VmaAllocator");
|
||||
|
||||
if (this->enableValidationLayers) {
|
||||
destroyDebugUtilsMessengerEXT(this->instance.get(), this->debugMessenger,
|
||||
nullptr);
|
||||
@@ -88,22 +92,6 @@ Device::~Device() {
|
||||
}
|
||||
}
|
||||
|
||||
u32 Device::findMemoryType(u32 typeFilter, vk::MemoryPropertyFlags properties) {
|
||||
vk::PhysicalDeviceMemoryProperties memoryProperties =
|
||||
this->physicalDevice.getMemoryProperties();
|
||||
|
||||
for (u32 i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) &&
|
||||
(memoryProperties.memoryTypes[i].propertyFlags & properties) ==
|
||||
properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
log::fatal("failed to find suitable memory type");
|
||||
throw std::runtime_error("failed to find suitable memory type");
|
||||
}
|
||||
|
||||
vk::Format Device::findSupportedFormat(
|
||||
const std::vector<vk::Format>& candidates, vk::ImageTiling tiling,
|
||||
vk::FormatFeatureFlags features) {
|
||||
@@ -125,35 +113,26 @@ vk::Format Device::findSupportedFormat(
|
||||
|
||||
void Device::createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage,
|
||||
vk::MemoryPropertyFlags properties,
|
||||
vk::Buffer& buffer, vk::DeviceMemory& bufferMemory) {
|
||||
vk::Buffer& buffer, VmaAllocation& allocation) {
|
||||
vk::BufferCreateInfo bufferInfo = {};
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = usage;
|
||||
bufferInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||
|
||||
try {
|
||||
buffer = this->device->createBuffer(bufferInfo);
|
||||
} catch (const vk::SystemError& error) {
|
||||
log::fatal("failed to create vertex buffer");
|
||||
throw std::runtime_error("failed to create vertex buffer");
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.requiredFlags = static_cast<VkMemoryPropertyFlags>(properties);
|
||||
|
||||
VkBuffer rawBuffer = VK_NULL_HANDLE;
|
||||
VkResult result = vmaCreateBuffer(
|
||||
this->allocator, &static_cast<const VkBufferCreateInfo&>(bufferInfo),
|
||||
&allocInfo, &rawBuffer, &allocation, nullptr);
|
||||
if (result != VK_SUCCESS) {
|
||||
log::fatal("failed to create buffer. Error: ",
|
||||
vk::to_string(static_cast<vk::Result>(result)));
|
||||
throw std::runtime_error("failed to create buffer");
|
||||
}
|
||||
|
||||
vk::MemoryRequirements memoryRequirements =
|
||||
this->device->getBufferMemoryRequirements(buffer);
|
||||
|
||||
vk::MemoryAllocateInfo allocInfo = {};
|
||||
allocInfo.allocationSize = memoryRequirements.size;
|
||||
allocInfo.memoryTypeIndex =
|
||||
findMemoryType(memoryRequirements.memoryTypeBits, properties);
|
||||
|
||||
try {
|
||||
bufferMemory = this->device->allocateMemory(allocInfo);
|
||||
} catch (const vk::SystemError& error) {
|
||||
log::fatal("failed to allocate vertex buffer memory");
|
||||
throw std::runtime_error("failed to allocate vertex buffer memory");
|
||||
}
|
||||
|
||||
this->device->bindBufferMemory(buffer, bufferMemory, 0);
|
||||
buffer = rawBuffer;
|
||||
}
|
||||
|
||||
vk::CommandBuffer Device::beginSingleTimeCommands() {
|
||||
@@ -220,43 +199,21 @@ void Device::copyBuffer(vk::Buffer sourceBuffer, vk::Buffer destinationBuffer,
|
||||
|
||||
void Device::createImageWithInfo(const vk::ImageCreateInfo& imageInfo,
|
||||
vk::MemoryPropertyFlags properties,
|
||||
vk::Image& image,
|
||||
vk::DeviceMemory& imageMemory) {
|
||||
try {
|
||||
vk::Result result = this->device->createImage(&imageInfo, nullptr, &image);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
throw vk::SystemError(result);
|
||||
}
|
||||
} catch (const vk::SystemError& error) {
|
||||
log::fatal("failed to create image. Error: ", error.what());
|
||||
vk::Image& image, VmaAllocation& allocation) {
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.requiredFlags = static_cast<VkMemoryPropertyFlags>(properties);
|
||||
|
||||
VkImage rawImage = VK_NULL_HANDLE;
|
||||
VkResult result = vmaCreateImage(
|
||||
this->allocator, &static_cast<const VkImageCreateInfo&>(imageInfo),
|
||||
&allocInfo, &rawImage, &allocation, nullptr);
|
||||
if (result != VK_SUCCESS) {
|
||||
log::fatal("failed to create image. Error: ",
|
||||
vk::to_string(static_cast<vk::Result>(result)));
|
||||
throw std::runtime_error("failed to create image");
|
||||
}
|
||||
|
||||
vk::MemoryRequirements memoryRequirements =
|
||||
this->device->getImageMemoryRequirements(image);
|
||||
|
||||
vk::MemoryAllocateInfo allocateInfo{};
|
||||
allocateInfo.allocationSize = memoryRequirements.size;
|
||||
allocateInfo.memoryTypeIndex =
|
||||
findMemoryType(memoryRequirements.memoryTypeBits, properties);
|
||||
|
||||
try {
|
||||
vk::Result result =
|
||||
this->device->allocateMemory(&allocateInfo, nullptr, &imageMemory);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
throw vk::SystemError(result);
|
||||
}
|
||||
} catch (const vk::SystemError& error) {
|
||||
log::fatal("failed to allocate image memory. Error: ", error.what());
|
||||
throw std::runtime_error("failed to allocate image memory");
|
||||
}
|
||||
|
||||
try {
|
||||
this->device->bindImageMemory(image, imageMemory, 0);
|
||||
} catch (const vk::SystemError& error) {
|
||||
log::fatal("failed to bind image memory. Error: ", error.what());
|
||||
throw std::runtime_error("failed to bind image memory");
|
||||
}
|
||||
image = rawImage;
|
||||
}
|
||||
|
||||
void Device::populateImGuiInitInfo(ImGui_ImplVulkan_InitInfo& initInfo) {
|
||||
@@ -514,6 +471,20 @@ void Device::createLogicalDevice() {
|
||||
}
|
||||
}
|
||||
|
||||
void Device::createAllocator() {
|
||||
VmaAllocatorCreateInfo createInfo = {};
|
||||
createInfo.vulkanApiVersion = SOPHIA_VULKAN_API_VERSION;
|
||||
createInfo.instance = this->instance.get();
|
||||
createInfo.physicalDevice = this->physicalDevice;
|
||||
createInfo.device = this->device.get();
|
||||
|
||||
if (vmaCreateAllocator(&createInfo, &this->allocator) != VK_SUCCESS) {
|
||||
log::fatal("failed to create VmaAllocator");
|
||||
throw std::runtime_error("failed to create VmaAllocator");
|
||||
}
|
||||
log::trace("created VmaAllocator");
|
||||
}
|
||||
|
||||
SwapchainSupportDetails Device::querySwapchainSupport(
|
||||
vk::PhysicalDevice device) {
|
||||
SwapchainSupportDetails details;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui_impl_vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -47,6 +48,7 @@ class Device {
|
||||
|
||||
void waitIdle() { this->device->waitIdle(); }
|
||||
|
||||
VmaAllocator getAllocator() const { return this->allocator; }
|
||||
vk::CommandPool getCommandPool() const { return this->commandPool; }
|
||||
vk::SurfaceKHR getSurface() const { return surface; }
|
||||
vk::Queue getGraphicsQueue() const { return graphicsQueue; }
|
||||
@@ -60,15 +62,13 @@ class Device {
|
||||
return querySwapchainSupport(this->physicalDevice);
|
||||
}
|
||||
|
||||
u32 findMemoryType(u32 typeFilter, vk::MemoryPropertyFlags properties);
|
||||
|
||||
vk::Format findSupportedFormat(const std::vector<vk::Format>& candidates,
|
||||
vk::ImageTiling tiling,
|
||||
vk::FormatFeatureFlags features);
|
||||
|
||||
void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage,
|
||||
vk::MemoryPropertyFlags properties, vk::Buffer& buffer,
|
||||
vk::DeviceMemory& bufferMemory);
|
||||
VmaAllocation& allocation);
|
||||
|
||||
vk::CommandBuffer beginSingleTimeCommands();
|
||||
|
||||
@@ -79,7 +79,7 @@ class Device {
|
||||
|
||||
void createImageWithInfo(const vk::ImageCreateInfo& imageInfo,
|
||||
vk::MemoryPropertyFlags properties, vk::Image& image,
|
||||
vk::DeviceMemory& imageMemory);
|
||||
VmaAllocation& allocation);
|
||||
|
||||
void populateImGuiInitInfo(ImGui_ImplVulkan_InitInfo& initInfo);
|
||||
|
||||
@@ -100,6 +100,7 @@ class Device {
|
||||
SwapchainSupportDetails querySwapchainSupport(vk::PhysicalDevice device);
|
||||
|
||||
void createLogicalDevice();
|
||||
void createAllocator();
|
||||
void createCommandPool();
|
||||
|
||||
vk::UniqueInstance instance;
|
||||
@@ -111,6 +112,8 @@ class Device {
|
||||
vk::PhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
vk::UniqueDevice device;
|
||||
|
||||
VmaAllocator allocator = VK_NULL_HANDLE;
|
||||
|
||||
vk::Queue graphicsQueue;
|
||||
vk::Queue presentQueue;
|
||||
|
||||
|
||||
+34
-20
@@ -3,11 +3,35 @@
|
||||
#include <cstring>
|
||||
#include <sophia/util/logger.hpp>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "vulkan/device.hpp"
|
||||
|
||||
namespace sophia {
|
||||
|
||||
Image::Image(Image&& other) noexcept
|
||||
: device{other.device},
|
||||
externalImage{other.externalImage},
|
||||
image{std::exchange(other.image, nullptr)},
|
||||
allocation{std::exchange(other.allocation, VK_NULL_HANDLE)},
|
||||
view{std::move(other.view)},
|
||||
sampler{std::move(other.sampler)},
|
||||
format{other.format},
|
||||
extent{other.extent},
|
||||
aspectMask{other.aspectMask},
|
||||
mipLevels{other.mipLevels},
|
||||
arrayLayers{other.arrayLayers},
|
||||
layout{other.layout} {}
|
||||
|
||||
Image::~Image() {
|
||||
this->sampler.reset();
|
||||
this->view.reset();
|
||||
|
||||
if (this->image) {
|
||||
vmaDestroyImage(this->device.getAllocator(), this->image, this->allocation);
|
||||
}
|
||||
}
|
||||
|
||||
vk::ImageSubresourceRange Image::getSubresourceRange() const {
|
||||
return vk::ImageSubresourceRange{this->aspectMask, 0, this->mipLevels, 0,
|
||||
this->arrayLayers};
|
||||
@@ -194,35 +218,26 @@ std::unique_ptr<Image> Image::Builder::build() {
|
||||
imageInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||
imageInfo.samples = this->samples;
|
||||
|
||||
result->image = this->device.get()->createImageUnique(imageInfo);
|
||||
|
||||
vk::MemoryRequirements memoryRequirements =
|
||||
this->device.get()->getImageMemoryRequirements(result->image.get());
|
||||
|
||||
vk::MemoryAllocateInfo allocInfo{};
|
||||
allocInfo.allocationSize = memoryRequirements.size;
|
||||
allocInfo.memoryTypeIndex = this->device.findMemoryType(
|
||||
memoryRequirements.memoryTypeBits, this->memoryProperties);
|
||||
|
||||
result->memory = this->device.get()->allocateMemoryUnique(allocInfo);
|
||||
this->device.get()->bindImageMemory(result->image.get(),
|
||||
result->memory.get(), 0);
|
||||
this->device.createImageWithInfo(imageInfo, this->memoryProperties,
|
||||
result->image, result->allocation);
|
||||
}
|
||||
|
||||
if (!this->isExternalImage && this->initialData != nullptr) {
|
||||
VmaAllocator allocator = this->device.getAllocator();
|
||||
|
||||
vk::Buffer stagingBuffer;
|
||||
vk::DeviceMemory stagingMemory;
|
||||
VmaAllocation stagingAllocation;
|
||||
this->device.createBuffer(this->initialDataSize,
|
||||
vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
||||
vk::MemoryPropertyFlagBits::eHostCoherent,
|
||||
stagingBuffer, stagingMemory);
|
||||
stagingBuffer, stagingAllocation);
|
||||
|
||||
void* mapped =
|
||||
this->device.get()->mapMemory(stagingMemory, 0, this->initialDataSize);
|
||||
void* mapped = nullptr;
|
||||
vmaMapMemory(allocator, stagingAllocation, &mapped);
|
||||
memcpy(mapped, this->initialData,
|
||||
static_cast<size_t>(this->initialDataSize));
|
||||
this->device.get()->unmapMemory(stagingMemory);
|
||||
vmaUnmapMemory(allocator, stagingAllocation);
|
||||
|
||||
vk::BufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
@@ -247,8 +262,7 @@ std::unique_ptr<Image> Image::Builder::build() {
|
||||
}
|
||||
this->device.endSingleTimeCommands(commandBuffer);
|
||||
|
||||
this->device.get()->destroyBuffer(stagingBuffer);
|
||||
this->device.get()->freeMemory(stagingMemory);
|
||||
vmaDestroyBuffer(allocator, stagingBuffer, stagingAllocation);
|
||||
}
|
||||
|
||||
if (this->createView) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sophia/types.hpp>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
@@ -16,11 +18,12 @@ class Image {
|
||||
|
||||
Image(const Image&) = delete;
|
||||
Image& operator=(const Image&) = delete;
|
||||
Image(Image&&) = default;
|
||||
Image(Image&& other) noexcept;
|
||||
Image& operator=(Image&&) = delete;
|
||||
~Image();
|
||||
|
||||
vk::Image get() const {
|
||||
return this->image ? this->image.get() : this->externalImage;
|
||||
return this->image ? this->image : this->externalImage;
|
||||
}
|
||||
vk::ImageView getView() const { return this->view.get(); }
|
||||
vk::Sampler getSampler() const { return this->sampler.get(); }
|
||||
@@ -56,8 +59,8 @@ class Image {
|
||||
Device& device;
|
||||
|
||||
vk::Image externalImage;
|
||||
vk::UniqueImage image;
|
||||
vk::UniqueDeviceMemory memory;
|
||||
vk::Image image;
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
vk::UniqueImageView view;
|
||||
vk::UniqueSampler sampler;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <vk_mem_alloc.h>
|
||||
Reference in New Issue
Block a user