vk: Introduce the concept of VRAM allocation pools

- Each buffer or image has to declare which pool it belongs to. This will aid with memory management down the line.
This commit is contained in:
kd-11 2021-07-14 00:26:02 +03:00 committed by kd-11
parent 71a5e5333a
commit 88abf3a6ba
20 changed files with 220 additions and 143 deletions

View File

@ -67,7 +67,8 @@ namespace vk
allocated_memory = std::make_unique<vk::buffer>(dev, size,
dev.get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0);
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0,
VMM_ALLOCATION_POOL_UNDEFINED);
s_allocated_dma_pool_size += allocated_memory->size();
}

View File

@ -481,7 +481,7 @@ VKGSRender::VKGSRender() : GSRender()
}
const auto& memory_map = m_device->get_memory_mapping();
null_buffer = std::make_unique<vk::buffer>(*m_device, 32, memory_map.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0);
null_buffer = std::make_unique<vk::buffer>(*m_device, 32, memory_map.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
null_buffer_view = std::make_unique<vk::buffer_view>(*m_device, null_buffer->value, VK_FORMAT_R8_UINT, 0, 32);
vk::initialize_compiler_context();
@ -2461,7 +2461,7 @@ void VKGSRender::begin_conditional_rendering(const std::vector<rsx::reports::occ
m_cond_render_buffer = std::make_unique<vk::buffer>(
*m_device, 4,
memory_props.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
usage_flags, 0);
usage_flags, 0, VMM_ALLOCATION_POOL_UNDEFINED);
}
VkPipelineStageFlags dst_stage;

View File

@ -365,6 +365,8 @@ private:
deadlock = 2
};
using enum vk::vmm_allocation_pool;
private:
VKFragmentProgram m_fragment_prog;
VKVertexProgram m_vertex_prog;

View File

@ -514,7 +514,7 @@ namespace vk
auto tex = std::make_unique<vk::image>(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
0);
0, VMM_ALLOCATION_POOL_UNDEFINED);
if (pixel_src && data_size)
std::memcpy(addr, pixel_src, data_size);

View File

@ -655,8 +655,8 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
const usz sshot_size = buffer_height * buffer_width * 4;
vk::buffer sshot_vkbuf(*m_device, utils::align(sshot_size, 0x100000), m_device->get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0);
vk::buffer sshot_vkbuf(*m_device, utils::align(sshot_size, 0x100000), m_device->get_memory_mapping().host_visible_coherent,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
VkBufferImageCopy copy_info;
copy_info.bufferOffset = 0;

View File

@ -26,6 +26,7 @@ namespace vk
VK_IMAGE_TILING_OPTIMAL,
usage,
0,
VMM_ALLOCATION_POOL_SURFACE_CACHE,
format_class()));
resolve_surface->native_component_map = native_component_map;

View File

@ -9,6 +9,7 @@
#include "vkutils/data_heap.h"
#include "vkutils/device.h"
#include "vkutils/image.h"
#include "vkutils/memory.h"
#include "vkutils/scratch.h"
#include <span>
@ -120,7 +121,7 @@ namespace rsx
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL,
usage_flags,
0, RSX_FORMAT_CLASS_COLOR);
0, vk::VMM_ALLOCATION_POOL_SURFACE_CACHE, RSX_FORMAT_CLASS_COLOR);
rtt->set_debug_name(fmt::format("RTV @0x%x", address));
rtt->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@ -181,7 +182,7 @@ namespace rsx
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL,
usage_flags,
0, rsx::classify_format(format));
0, vk::VMM_ALLOCATION_POOL_SURFACE_CACHE, rsx::classify_format(format));
ds->set_debug_name(fmt::format("DSV @0x%x", address));
ds->change_layout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
@ -223,6 +224,7 @@ namespace rsx
VK_IMAGE_TILING_OPTIMAL,
ref->info.usage,
ref->info.flags,
vk::VMM_ALLOCATION_POOL_SURFACE_CACHE,
ref->format_class());
sink->add_ref();

View File

@ -54,7 +54,7 @@ namespace vk
return size / (1024.f * 1024.f * 1024.f);
}
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size)
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size, vmm_allocation_pool pool)
{
auto key = reinterpret_cast<uptr>(handle);
const vmm_allocation_t info = { memory_size, memory_type };

View File

@ -264,8 +264,8 @@ namespace vk
//At worst case, 1 char = 16*16*8 bytes (average about 24*8), so ~256K for 128 chars. Allocating 512k for verts
//uniform params are 8k in size, allocating for 120 lines (max lines at 4k, one column per row. Can be expanded
m_vertex_buffer = std::make_unique<vk::buffer>(dev, 524288, dev.get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 0);
m_uniforms_buffer = std::make_unique<vk::buffer>(dev, 983040, dev.get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 0);
m_vertex_buffer = std::make_unique<vk::buffer>(dev, 524288, dev.get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
m_uniforms_buffer = std::make_unique<vk::buffer>(dev, 983040, dev.get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
m_render_pass = render_pass;
m_uniform_buffer_size = 983040;

View File

@ -576,7 +576,7 @@ namespace vk
dst_format,
w, h, d, mips, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags,
rsx::classify_format(gcm_format));
VMM_ALLOCATION_POOL_TEXTURE_CACHE, rsx::classify_format(gcm_format));
}
//This method is almost exclusively used to work on framebuffer resources
@ -871,7 +871,7 @@ namespace vk
vk_format,
width, height, depth, mipmaps, layer, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, usage_flags, is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
rsx::classify_format(gcm_format));
VMM_ALLOCATION_POOL_TEXTURE_CACHE, rsx::classify_format(gcm_format));
// New section, we must prepare it
region.reset(rsx_range);
@ -1220,7 +1220,8 @@ namespace vk
VK_IMAGE_TYPE_2D,
format,
width, height, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0);
VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
0, VMM_ALLOCATION_POOL_TEXTURE_CACHE);
VkImageSubresource subresource{};
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;

View File

@ -5,7 +5,7 @@
namespace vk
{
buffer_view::buffer_view(VkDevice dev, VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size)
: m_device(dev)
: m_device(dev)
{
info.buffer = buffer;
info.format = format;
@ -39,97 +39,97 @@ namespace vk
return false;
}
buffer::buffer(const vk::render_device& dev, u64 size, u32 memory_type_index, u32 access_flags, VkBufferUsageFlags usage, VkBufferCreateFlags flags)
: m_device(dev)
buffer::buffer(const vk::render_device& dev, u64 size, u32 memory_type_index, u32 access_flags, VkBufferUsageFlags usage, VkBufferCreateFlags flags, vmm_allocation_pool allocation_pool)
: m_device(dev)
{
info.size = size;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.flags = flags;
info.usage = usage;
CHECK_RESULT(vkCreateBuffer(m_device, &info, nullptr, &value));
// Allocate vram for this buffer
VkMemoryRequirements memory_reqs;
vkGetBufferMemoryRequirements(m_device, value, &memory_reqs);
if (!(memory_reqs.memoryTypeBits & (1 << memory_type_index)))
{
info.size = size;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.flags = flags;
info.usage = usage;
CHECK_RESULT(vkCreateBuffer(m_device, &info, nullptr, &value));
//Allocate vram for this buffer
VkMemoryRequirements memory_reqs;
vkGetBufferMemoryRequirements(m_device, value, &memory_reqs);
if (!(memory_reqs.memoryTypeBits & (1 << memory_type_index)))
{
//Suggested memory type is incompatible with this memory type.
//Go through the bitset and test for requested props.
if (!dev.get_compatible_memory_type(memory_reqs.memoryTypeBits, access_flags, &memory_type_index))
fmt::throw_exception("No compatible memory type was found!");
}
memory = std::make_unique<memory_block>(m_device, memory_reqs.size, memory_reqs.alignment, memory_type_index);
vkBindBufferMemory(dev, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset());
}
buffer::buffer(const vk::render_device& dev, VkBufferUsageFlags usage, void* host_pointer, u64 size)
: m_device(dev)
{
info.size = size;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.flags = 0;
info.usage = usage;
VkExternalMemoryBufferCreateInfoKHR ex_info;
ex_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR;
ex_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
ex_info.pNext = nullptr;
info.pNext = &ex_info;
CHECK_RESULT(vkCreateBuffer(m_device, &info, nullptr, &value));
auto& memory_map = dev.get_memory_mapping();
u32 memory_type_index = memory_map.host_visible_coherent;
VkFlags access_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
ensure(memory_map._vkGetMemoryHostPointerPropertiesEXT);
VkMemoryHostPointerPropertiesEXT memory_properties{};
memory_properties.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;
CHECK_RESULT(memory_map._vkGetMemoryHostPointerPropertiesEXT(dev, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, host_pointer, &memory_properties));
VkMemoryRequirements memory_reqs;
vkGetBufferMemoryRequirements(m_device, value, &memory_reqs);
auto required_memory_type_bits = memory_reqs.memoryTypeBits & memory_properties.memoryTypeBits;
if (!required_memory_type_bits)
{
// AMD driver bug. Buffers created with external memory extension return type bits of 0
rsx_log.warning("Could not match buffer requirements and host pointer properties.");
required_memory_type_bits = memory_properties.memoryTypeBits;
}
if (!dev.get_compatible_memory_type(required_memory_type_bits, access_flags, &memory_type_index))
{
// Suggested memory type is incompatible with this memory type.
// Go through the bitset and test for requested props.
if (!dev.get_compatible_memory_type(memory_reqs.memoryTypeBits, access_flags, &memory_type_index))
fmt::throw_exception("No compatible memory type was found!");
}
memory = std::make_unique<memory_block_host>(m_device, host_pointer, size, memory_type_index);
CHECK_RESULT(vkBindBufferMemory(dev, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset()));
}
buffer::~buffer()
memory = std::make_unique<memory_block>(m_device, memory_reqs.size, memory_reqs.alignment, memory_type_index, allocation_pool);
vkBindBufferMemory(dev, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset());
}
buffer::buffer(const vk::render_device& dev, VkBufferUsageFlags usage, void* host_pointer, u64 size)
: m_device(dev)
{
info.size = size;
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.flags = 0;
info.usage = usage;
VkExternalMemoryBufferCreateInfoKHR ex_info;
ex_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR;
ex_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
ex_info.pNext = nullptr;
info.pNext = &ex_info;
CHECK_RESULT(vkCreateBuffer(m_device, &info, nullptr, &value));
auto& memory_map = dev.get_memory_mapping();
u32 memory_type_index = memory_map.host_visible_coherent;
VkFlags access_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
ensure(memory_map._vkGetMemoryHostPointerPropertiesEXT);
VkMemoryHostPointerPropertiesEXT memory_properties{};
memory_properties.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;
CHECK_RESULT(memory_map._vkGetMemoryHostPointerPropertiesEXT(dev, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, host_pointer, &memory_properties));
VkMemoryRequirements memory_reqs;
vkGetBufferMemoryRequirements(m_device, value, &memory_reqs);
auto required_memory_type_bits = memory_reqs.memoryTypeBits & memory_properties.memoryTypeBits;
if (!required_memory_type_bits)
{
vkDestroyBuffer(m_device, value, nullptr);
// AMD driver bug. Buffers created with external memory extension return type bits of 0
rsx_log.warning("Could not match buffer requirements and host pointer properties.");
required_memory_type_bits = memory_properties.memoryTypeBits;
}
void* buffer::map(u64 offset, u64 size)
if (!dev.get_compatible_memory_type(required_memory_type_bits, access_flags, &memory_type_index))
{
return memory->map(offset, size);
fmt::throw_exception("No compatible memory type was found!");
}
void buffer::unmap()
{
memory->unmap();
}
memory = std::make_unique<memory_block_host>(m_device, host_pointer, size, memory_type_index);
CHECK_RESULT(vkBindBufferMemory(dev, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset()));
}
u32 buffer::size() const
{
return static_cast<u32>(info.size);
}
buffer::~buffer()
{
vkDestroyBuffer(m_device, value, nullptr);
}
void* buffer::map(u64 offset, u64 size)
{
return memory->map(offset, size);
}
void buffer::unmap()
{
memory->unmap();
}
u32 buffer::size() const
{
return static_cast<u32>(info.size);
}
}

View File

@ -29,7 +29,7 @@ namespace vk
VkBufferCreateInfo info = {};
std::unique_ptr<vk::memory_block> memory;
buffer(const vk::render_device& dev, u64 size, u32 memory_type_index, u32 access_flags, VkBufferUsageFlags usage, VkBufferCreateFlags flags);
buffer(const vk::render_device& dev, u64 size, u32 memory_type_index, u32 access_flags, VkBufferUsageFlags usage, VkBufferCreateFlags flags, vmm_allocation_pool allocation_pool);
buffer(const vk::render_device& dev, VkBufferUsageFlags usage, void* host_pointer, u64 size);
~buffer();

View File

@ -26,13 +26,13 @@ namespace vk
{
rsx_log.warning("Buffer usage %u is not heap-compatible using this driver, explicit staging buffer in use", usage);
shadow = std::make_unique<buffer>(*g_render_device, size, memory_index, memory_flags, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0);
shadow = std::make_unique<buffer>(*g_render_device, size, memory_index, memory_flags, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0, VMM_ALLOCATION_POOL_SYSTEM);
usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
memory_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
memory_index = memory_map.device_local;
}
heap = std::make_unique<buffer>(*g_render_device, size, memory_index, memory_flags, usage, 0);
heap = std::make_unique<buffer>(*g_render_device, size, memory_index, memory_flags, usage, 0, VMM_ALLOCATION_POOL_SYSTEM);
initial_size = size;
notify_on_grow = bool(notify);
@ -87,7 +87,7 @@ namespace vk
// Discard old heap and create a new one. Old heap will be garbage collected when no longer needed
get_resource_manager()->dispose(heap);
heap = std::make_unique<buffer>(*g_render_device, aligned_new_size, memory_index, memory_flags, usage, 0);
heap = std::make_unique<buffer>(*g_render_device, aligned_new_size, memory_index, memory_flags, usage, 0, VMM_ALLOCATION_POOL_SYSTEM);
if (notify_on_grow)
{

View File

@ -53,9 +53,9 @@ namespace vk
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags image_flags,
vmm_allocation_pool allocation_pool,
rsx::format_class format_class)
: current_layout(initial_layout)
, m_device(dev)
: m_device(dev)
{
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = image_type;
@ -70,23 +70,7 @@ namespace vk
info.initialLayout = initial_layout;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
validate(dev, info);
CHECK_RESULT(vkCreateImage(m_device, &info, nullptr, &value));
VkMemoryRequirements memory_req;
vkGetImageMemoryRequirements(m_device, value, &memory_req);
if (!(memory_req.memoryTypeBits & (1 << memory_type_index)))
{
//Suggested memory type is incompatible with this memory type.
//Go through the bitset and test for requested props.
if (!dev.get_compatible_memory_type(memory_req.memoryTypeBits, access_flags, &memory_type_index))
fmt::throw_exception("No compatible memory type was found!");
}
memory = std::make_shared<vk::memory_block>(m_device, memory_req.size, memory_req.alignment, memory_type_index);
CHECK_RESULT(vkBindImageMemory(m_device, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset()));
create_impl(dev, access_flags, memory_type_index, allocation_pool);
m_storage_aspect = get_aspect_flags(format);
if (format_class == RSX_FORMAT_CLASS_UNDEFINED)
@ -111,6 +95,30 @@ namespace vk
vkDestroyImage(m_device, value, nullptr);
}
void image::create_impl(const vk::render_device& dev, u32 access_flags, u32 memory_type_index, vmm_allocation_pool allocation_pool)
{
ensure(!value && !memory);
validate(dev, info);
CHECK_RESULT(vkCreateImage(m_device, &info, nullptr, &value));
VkMemoryRequirements memory_req;
vkGetImageMemoryRequirements(m_device, value, &memory_req);
if (!(memory_req.memoryTypeBits & (1 << memory_type_index)))
{
//Suggested memory type is incompatible with this memory type.
//Go through the bitset and test for requested props.
if (!dev.get_compatible_memory_type(memory_req.memoryTypeBits, access_flags, &memory_type_index))
fmt::throw_exception("No compatible memory type was found!");
}
memory = std::make_shared<vk::memory_block>(m_device, memory_req.size, memory_req.alignment, memory_type_index, allocation_pool);
CHECK_RESULT(vkBindImageMemory(m_device, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset()));
current_layout = info.initialLayout;
}
u32 image::width() const
{
return info.extent.width;
@ -330,6 +338,20 @@ namespace vk
#endif
}
viewable_image* viewable_image::clone()
{
// Destructive cloning. The clone grabs the GPU objects owned by this instance.
// This instance can be rebuilt in-place by calling create_impl() which will create a duplicate now owned by this.
auto result = new viewable_image();
result->m_device = this->m_device;
result->info = this->info;
result->value = this->value;
result->memory = std::move(this->memory);
result->views = std::move(this->views);
this->value = VK_NULL_HANDLE;
return result;
}
image_view* viewable_image::get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, VkImageAspectFlags mask)
{
if (remap_encoding == VK_REMAP_IDENTITY)

View File

@ -35,6 +35,10 @@ namespace vk
void validate(const vk::render_device& dev, const VkImageCreateInfo& info) const;
protected:
image() = default;
void create_impl(const vk::render_device& dev, u32 access_flags, u32 memory_type_index, vmm_allocation_pool allocation_pool);
public:
VkImage value = VK_NULL_HANDLE;
VkComponentMapping native_component_map = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
@ -55,6 +59,7 @@ namespace vk
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags image_flags,
vmm_allocation_pool allocation_pool,
rsx::format_class format_class = RSX_FORMAT_CLASS_UNDEFINED);
virtual ~image();
@ -84,7 +89,7 @@ namespace vk
// Debug utils
void set_debug_name(const std::string& name);
private:
protected:
VkDevice m_device;
};
@ -118,8 +123,9 @@ namespace vk
class viewable_image : public image
{
private:
protected:
std::unordered_multimap<u32, std::unique_ptr<vk::image_view>> views;
viewable_image* clone();
public:
using image::image;

View File

@ -22,7 +22,10 @@ namespace vk
allocatorInfo.physicalDevice = pdev;
allocatorInfo.device = dev;
vmaCreateAllocator(&allocatorInfo, &m_allocator);
CHECK_RESULT(vmaCreateAllocator(&allocatorInfo, &m_allocator));
// Allow fastest possible allocation on start
set_fastest_allocation_flags();
}
void mem_allocator_vma::destroy()
@ -30,7 +33,7 @@ namespace vk
vmaDestroyAllocator(m_allocator);
}
mem_allocator_vk::mem_handle_t mem_allocator_vma::alloc(u64 block_sz, u64 alignment, u32 memory_type_index)
mem_allocator_vk::mem_handle_t mem_allocator_vma::alloc(u64 block_sz, u64 alignment, u32 memory_type_index, vmm_allocation_pool pool)
{
VmaAllocation vma_alloc;
VkMemoryRequirements mem_req = {};
@ -40,7 +43,7 @@ namespace vk
mem_req.size = ::align2(block_sz, alignment);
mem_req.alignment = alignment;
create_info.memoryTypeBits = 1u << memory_type_index;
create_info.flags = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
create_info.flags = m_allocation_flags;
if (VkResult result = vmaAllocateMemory(m_allocator, &mem_req, &create_info, &vma_alloc, nullptr);
result != VK_SUCCESS)
@ -62,7 +65,7 @@ namespace vk
}
}
vmm_notify_memory_allocated(vma_alloc, memory_type_index, block_sz);
vmm_notify_memory_allocated(vma_alloc, memory_type_index, block_sz, pool);
return vma_alloc;
}
@ -123,7 +126,17 @@ namespace vk
return max_usage;
}
mem_allocator_vk::mem_handle_t mem_allocator_vk::alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index)
void mem_allocator_vma::set_safest_allocation_flags()
{
m_allocation_flags = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;
}
void mem_allocator_vma::set_fastest_allocation_flags()
{
m_allocation_flags = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
}
mem_allocator_vk::mem_handle_t mem_allocator_vk::alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index, vmm_allocation_pool pool)
{
VkDeviceMemory memory;
VkMemoryAllocateInfo info = {};
@ -149,7 +162,7 @@ namespace vk
}
}
vmm_notify_memory_allocated(memory, memory_type_index, block_sz);
vmm_notify_memory_allocated(memory, memory_type_index, block_sz, pool);
return memory;
}
@ -191,11 +204,11 @@ namespace vk
return g_render_device->get_allocator();
}
memory_block::memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index)
: m_device(dev)
memory_block::memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index, vmm_allocation_pool pool)
: m_device(dev), m_size(block_sz)
{
m_mem_allocator = get_current_mem_allocator();
m_mem_handle = m_mem_allocator->alloc(block_sz, alignment, memory_type_index);
m_mem_handle = m_mem_allocator->alloc(block_sz, alignment, memory_type_index, pool);
}
memory_block::~memory_block()
@ -259,6 +272,11 @@ namespace vk
return m_mem_allocator->get_vk_device_memory_offset(m_mem_handle);
}
u64 memory_block::size() const
{
return m_size;
}
void* memory_block::map(u64 offset, u64 size)
{
return m_mem_allocator->map(m_mem_handle, offset, size);

View File

@ -8,17 +8,27 @@
namespace vk
{
enum vmm_allocation_pool
{
VMM_ALLOCATION_POOL_UNDEFINED = 0,
VMM_ALLOCATION_POOL_SYSTEM,
VMM_ALLOCATION_POOL_SURFACE_CACHE,
VMM_ALLOCATION_POOL_TEXTURE_CACHE,
VMM_ALLOCATION_POOL_SWAPCHAIN,
VMM_ALLOCATION_POOL_SCRATCH,
};
class mem_allocator_base
{
public:
using mem_handle_t = void*;
mem_allocator_base(VkDevice dev, VkPhysicalDevice /*pdev*/) : m_device(dev) {}
mem_allocator_base(VkDevice dev, VkPhysicalDevice /*pdev*/) : m_device(dev), m_allocation_flags(0) {}
virtual ~mem_allocator_base() = default;
virtual void destroy() = 0;
virtual mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index) = 0;
virtual mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index, vmm_allocation_pool pool) = 0;
virtual void free(mem_handle_t mem_handle) = 0;
virtual void* map(mem_handle_t mem_handle, u64 offset, u64 size) = 0;
virtual void unmap(mem_handle_t mem_handle) = 0;
@ -26,8 +36,12 @@ namespace vk
virtual u64 get_vk_device_memory_offset(mem_handle_t mem_handle) = 0;
virtual f32 get_memory_usage() = 0;
virtual void set_safest_allocation_flags() {}
virtual void set_fastest_allocation_flags() {}
protected:
VkDevice m_device;
VkFlags m_allocation_flags;
};
@ -42,7 +56,7 @@ namespace vk
void destroy() override;
mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index) override;
mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index, vmm_allocation_pool pool) override;
void free(mem_handle_t mem_handle) override;
void* map(mem_handle_t mem_handle, u64 offset, u64 /*size*/) override;
@ -52,6 +66,9 @@ namespace vk
u64 get_vk_device_memory_offset(mem_handle_t mem_handle) override;
f32 get_memory_usage() override;
void set_safest_allocation_flags() override;
void set_fastest_allocation_flags() override;
private:
VmaAllocator m_allocator;
std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> stats;
@ -68,7 +85,7 @@ namespace vk
void destroy() override {}
mem_handle_t alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index) override;
mem_handle_t alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index, vmm_allocation_pool pool) override;
void free(mem_handle_t mem_handle) override;
void* map(mem_handle_t mem_handle, u64 offset, u64 size) override;
@ -81,7 +98,7 @@ namespace vk
struct memory_block
{
memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index);
memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index, vmm_allocation_pool pool);
virtual ~memory_block();
virtual VkDeviceMemory get_vk_device_memory();
@ -90,6 +107,8 @@ namespace vk
virtual void* map(u64 offset, u64 size);
virtual void unmap();
u64 size() const;
memory_block(const memory_block&) = delete;
memory_block(memory_block&&) = delete;
@ -100,6 +119,7 @@ namespace vk
VkDevice m_device;
vk::mem_allocator_base* m_mem_allocator = nullptr;
mem_allocator_base::mem_handle_t m_mem_handle;
u64 m_size;
};
struct memory_block_host : public memory_block
@ -122,11 +142,14 @@ namespace vk
void* m_host_pointer;
};
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size);
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size, vmm_allocation_pool pool);
void vmm_notify_memory_freed(void* handle);
void vmm_reset();
void vmm_check_memory_usage();
u64 vmm_get_application_memory_usage(u32 memory_type);
u64 vmm_get_application_pool_usage(vmm_allocation_pool pool);
bool vmm_handle_memory_pressure(rsx::problem_severity severity);
rsx::problem_severity vmm_determine_memory_load_severity();
mem_allocator_base* get_current_mem_allocator();
}

View File

@ -97,7 +97,7 @@ namespace vk
auto& tex = g_null_image_views[type];
tex = std::make_unique<viewable_image>(*g_render_device, g_render_device->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
image_type, VK_FORMAT_B8G8R8A8_UNORM, size, size, 1, 1, num_layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, flags);
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, flags, VMM_ALLOCATION_POOL_SCRATCH);
// Initialize memory to transparent black
tex->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@ -122,7 +122,7 @@ namespace vk
return new vk::image(*g_render_device, g_render_device->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, new_width, new_height, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0);
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0, VMM_ALLOCATION_POOL_SCRATCH);
};
const u32 key = (format_class << 24u) | format;
@ -160,7 +160,7 @@ namespace vk
scratch_buffer = std::make_unique<vk::buffer>(*g_render_device, alloc_size,
g_render_device->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 0);
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_SCRATCH);
}
return scratch_buffer.get();

View File

@ -27,14 +27,14 @@ namespace vk
swapchain_image_RPCS3(render_device& dev, const memory_type_mapping& memory_map, u32 width, u32 height)
:image(dev, memory_map.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, width, height, 1, 1, 1,
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0)
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, VMM_ALLOCATION_POOL_SWAPCHAIN)
{
m_width = width;
m_height = height;
current_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
m_dma_buffer = std::make_unique<buffer>(dev, m_width * m_height * 4, memory_map.host_visible_coherent,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0);
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0, VMM_ALLOCATION_POOL_SWAPCHAIN);
}
void do_dma_transfer(command_buffer& cmd)

View File

@ -84,7 +84,8 @@ namespace vk
dev.get_memory_mapping().host_visible_coherent,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
0
0,
VMM_ALLOCATION_POOL_SYSTEM
);
m_value = reinterpret_cast<u32*>(m_buffer->map(0, 4));