renderer_vulkan: Use VMA for images

merge-requests/60/head
GPUCode 2023-05-24 22:39:58 +07:00
parent c60eed36b7
commit 48e39756f1
16 changed files with 119 additions and 91 deletions

@ -173,7 +173,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
return;
}
const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{
vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@ -196,7 +196,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal);
const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,

@ -1071,12 +1071,8 @@ void BlitScreen::ReleaseRawImages() {
scheduler.Wait(tick);
}
raw_images.clear();
raw_buffer_commits.clear();
aa_image_view.reset();
aa_image.reset();
aa_commit = MemoryCommit{};
buffer.reset();
buffer_commit = MemoryCommit{};
}
@ -1101,13 +1097,12 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer
void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
raw_images.resize(image_count);
raw_image_views.resize(image_count);
raw_buffer_commits.resize(image_count);
const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1,
u32 down_shift = 0) {
u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
: VK_IMAGE_USAGE_TRANSFER_DST_BIT;
return device.GetLogical().CreateImage(VkImageCreateInfo{
return memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@ -1130,9 +1125,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
};
const auto create_commit = [&](vk::Image& image) {
return memory_allocator.Commit(image, MemoryUsage::DeviceLocal);
};
const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) {
return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -1161,7 +1153,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
for (size_t i = 0; i < image_count; ++i) {
raw_images[i] = create_image();
raw_buffer_commits[i] = create_commit(raw_images[i]);
raw_image_views[i] = create_image_view(raw_images[i]);
}
@ -1169,7 +1160,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
const u32 up_scale = Settings::values.resolution_info.up_scale;
const u32 down_shift = Settings::values.resolution_info.down_shift;
aa_image = create_image(true, up_scale, down_shift);
aa_commit = create_commit(aa_image);
aa_image_view = create_image_view(aa_image, true);
VkExtent2D size{
.width = (up_scale * framebuffer.width) >> down_shift,

@ -148,7 +148,6 @@ private:
std::vector<vk::Image> raw_images;
std::vector<vk::ImageView> raw_image_views;
std::vector<MemoryCommit> raw_buffer_commits;
vk::DescriptorPool aa_descriptor_pool;
vk::DescriptorSetLayout aa_descriptor_set_layout;
@ -159,7 +158,6 @@ private:
vk::DescriptorSets aa_descriptor_sets;
vk::Image aa_image;
vk::ImageView aa_image_view;
MemoryCommit aa_commit;
u32 raw_width = 0;
u32 raw_height = 0;

@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() {
void FSR::CreateImages() {
images.resize(image_count * 2);
image_views.resize(image_count * 2);
buffer_commits.resize(image_count * 2);
for (size_t i = 0; i < image_count * 2; ++i) {
images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{
images[i] = memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@ -231,7 +230,6 @@ void FSR::CreateImages() {
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal);
image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,

@ -47,7 +47,6 @@ private:
vk::Sampler sampler;
std::vector<vk::Image> images;
std::vector<vk::ImageView> image_views;
std::vector<MemoryCommit> buffer_commits;
};
} // namespace Vulkan

@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
frame->height = height;
frame->is_srgb = is_srgb;
frame->image = dld.CreateImage({
frame->image = memory_allocator.CreateImage({
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal);
frame->image_view = dld.CreateImageView({
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,

@ -29,7 +29,6 @@ struct Frame {
vk::Image image;
vk::ImageView image_view;
vk::Framebuffer framebuffer;
MemoryCommit image_commit;
vk::CommandBuffer cmdbuf;
vk::Semaphore render_ready;
vk::Fence present_done;

@ -25,9 +25,7 @@ namespace {
#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
MemoryAllocator& allocator,
VkExtent2D dimensions, VkFormat format) {
vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) {
const VkImageCreateInfo image_ci{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
@ -46,11 +44,7 @@ std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
auto image = device.GetLogical().CreateImage(image_ci);
auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal);
return std::make_pair(std::move(image), std::move(commit));
return allocator.CreateImage(image_ci);
}
void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
@ -531,10 +525,8 @@ void SMAA::CreateImages() {
static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
std::tie(m_static_images[Area], m_static_buffer_commits[Area]) =
CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
std::tie(m_static_images[Search], m_static_buffer_commits[Search]) =
CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_image_views[Area] =
CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
@ -544,12 +536,11 @@ void SMAA::CreateImages() {
for (u32 i = 0; i < m_image_count; i++) {
Images& images = m_dynamic_images.emplace_back();
std::tie(images.images[Blend], images.buffer_commits[Blend]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
std::tie(images.images[Edges], images.buffer_commits[Edges]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
std::tie(images.images[Output], images.buffer_commits[Output]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.images[Blend] =
CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
images.images[Output] =
CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Blend] =
CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);

@ -66,13 +66,11 @@ private:
std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{};
std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{};
std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits;
std::array<vk::Image, MaxStaticImage> m_static_images{};
std::array<vk::ImageView, MaxStaticImage> m_static_image_views{};
struct Images {
vk::DescriptorSets descriptor_sets{};
std::array<MemoryCommit, MaxDynamicImage> buffer_commits;
std::array<vk::Image, MaxDynamicImage> images{};
std::array<vk::ImageView, MaxDynamicImage> image_views{};
std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{};

@ -15,7 +15,6 @@
#include "video_core/renderer_vulkan/blit_image.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@ -163,11 +162,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
};
}
[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) {
[[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator,
const ImageInfo& info) {
if (info.type == ImageType::Buffer) {
return vk::Image{};
}
return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info));
return allocator.CreateImage(MakeImageCreateInfo(device, info));
}
[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
@ -1266,8 +1266,8 @@ void TextureCacheRuntime::TickFrame() {}
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
runtime{&runtime_}, original_image(MakeImage(runtime_.device, info)),
commit(runtime_.memory_allocator.Commit(original_image, MemoryUsage::DeviceLocal)),
runtime{&runtime_},
original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info)),
aspect_mask(ImageAspectMask(info.format)) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
if (Settings::values.async_astc.GetValue()) {
@ -1467,9 +1467,7 @@ bool Image::ScaleUp(bool ignore) {
auto scaled_info = info;
scaled_info.size.width = scaled_width;
scaled_info.size.height = scaled_height;
scaled_image = MakeImage(runtime->device, scaled_info);
auto& allocator = runtime->memory_allocator;
scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal));
scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info);
ignore = false;
}
current_image = *scaled_image;

@ -180,12 +180,10 @@ private:
TextureCacheRuntime* runtime{};
vk::Image original_image;
MemoryCommit commit;
std::vector<vk::ImageView> storage_image_views;
VkImageAspectFlags aspect_mask = 0;
bool initialized = false;
vk::Image scaled_image{};
MemoryCommit scaled_commit{};
VkImage current_image{};
std::unique_ptr<Framebuffer> scale_framebuffer;

@ -210,6 +210,11 @@ public:
return dld;
}
/// Returns the VMA allocator.
VmaAllocator GetAllocator() const {
return allocator;
}
/// Returns the logical device.
const vk::Device& GetLogical() const {
return logical;

@ -15,6 +15,10 @@
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include <vk_mem_alloc.h>
namespace Vulkan {
namespace {
struct Range {
@ -180,6 +184,24 @@ MemoryAllocator::MemoryAllocator(const Device& device_)
MemoryAllocator::~MemoryAllocator() = default;
vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
const VmaAllocationCreateInfo alloc_info = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
.requiredFlags = 0,
.preferredFlags = 0,
.pool = VK_NULL_HANDLE,
.pUserData = nullptr,
};
VkImage handle{};
VmaAllocation allocation{};
vk::Check(
vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr));
return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation,
device.GetDispatchLoader());
}
MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
// Find the fastest memory flags we can afford with the current requirements
const u32 type_mask = requirements.memoryTypeBits;
@ -205,14 +227,6 @@ MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage
return commit;
}
MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) {
VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image);
requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity);
auto commit = Commit(requirements, usage);
image.BindMemory(commit.Memory(), commit.Offset());
return commit;
}
bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
const u32 type = FindType(flags, type_mask).value();
vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({

@ -80,6 +80,8 @@ public:
MemoryAllocator& operator=(const MemoryAllocator&) = delete;
MemoryAllocator(const MemoryAllocator&) = delete;
vk::Image CreateImage(const VkImageCreateInfo& ci) const;
/**
* Commits a memory with the specified requirements.
*
@ -93,9 +95,6 @@ public:
/// Commits memory required by the buffer and binds it.
MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage);
/// Commits memory required by the image and binds it.
MemoryCommit Commit(const vk::Image& image, MemoryUsage usage);
private:
/// Tries to allocate a chunk of memory.
bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size);

@ -12,6 +12,10 @@
#include "video_core/vulkan_common/vulkan_wrapper.h"
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include <vk_mem_alloc.h>
namespace Vulkan::vk {
namespace {
@ -547,6 +551,16 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
return DebugUtilsMessenger(object, handle, *dld);
}
void Image::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
}
void Image::Release() const noexcept {
if (handle) {
vmaDestroyImage(allocator, handle, allocation);
}
}
void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
}
@ -559,14 +573,6 @@ void BufferView::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
}
void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
Check(dld->vkBindImageMemory(owner, handle, memory, offset));
}
void Image::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
}
void ImageView::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name);
}
@ -713,12 +719,6 @@ BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
return BufferView(object, handle, *dld);
}
Image Device::CreateImage(const VkImageCreateInfo& ci) const {
VkImage object;
Check(dld->vkCreateImage(handle, &ci, nullptr, &object));
return Image(object, handle, *dld);
}
ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
VkImageView object;
Check(dld->vkCreateImageView(handle, &ci, nullptr, &object));

@ -32,6 +32,9 @@
#pragma warning(disable : 26812) // Disable prefer enum class over enum
#endif
VK_DEFINE_HANDLE(VmaAllocator)
VK_DEFINE_HANDLE(VmaAllocation)
namespace Vulkan::vk {
/**
@ -616,6 +619,60 @@ public:
}
};
class Image {
public:
explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_,
VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept
: handle{handle_}, owner{owner_}, allocator{allocator_},
allocation{allocation_}, dld{&dld_} {}
Image() = default;
Image(const Image&) = delete;
Image& operator=(const Image&) = delete;
Image(Image&& rhs) noexcept
: handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
allocation{rhs.allocation}, dld{rhs.dld} {}
Image& operator=(Image&& rhs) noexcept {
Release();
handle = std::exchange(rhs.handle, nullptr);
owner = rhs.owner;
allocator = rhs.allocator;
allocation = rhs.allocation;
dld = rhs.dld;
return *this;
}
~Image() noexcept {
Release();
}
VkImage operator*() const noexcept {
return handle;
}
void reset() noexcept {
Release();
handle = nullptr;
}
explicit operator bool() const noexcept {
return handle != nullptr;
}
void SetObjectNameEXT(const char* name) const;
private:
void Release() const noexcept;
VkImage handle = nullptr;
VkDevice owner = nullptr;
VmaAllocator allocator = nullptr;
VmaAllocation allocation = nullptr;
const DeviceDispatch* dld = nullptr;
};
class Queue {
public:
/// Construct an empty queue handle.
@ -658,17 +715,6 @@ public:
void SetObjectNameEXT(const char* name) const;
};
class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
public:
/// Attaches a memory allocation.
void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
/// Set object name.
void SetObjectNameEXT(const char* name) const;
};
class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> {
using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle;
@ -844,8 +890,6 @@ public:
BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
Image CreateImage(const VkImageCreateInfo& ci) const;
ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
Semaphore CreateSemaphore() const;