mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 04:32:35 +01:00
vk: Allow creating temporary subresources to fail if we run out of memory.
This commit is contained in:
parent
92d1534917
commit
9d11c8cbb5
@ -505,8 +505,14 @@ namespace vk
|
||||
image_type,
|
||||
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,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags | VK_IMAGE_CREATE_ALLOW_NULL,
|
||||
VMM_ALLOCATION_POOL_TEXTURE_CACHE, rsx::classify_format(gcm_format));
|
||||
|
||||
if (!image->value)
|
||||
{
|
||||
// OOM, bail
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is almost exclusively used to work on framebuffer resources
|
||||
@ -572,6 +578,12 @@ namespace vk
|
||||
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
|
||||
VK_IMAGE_VIEW_TYPE_CUBE, gcm_format, 0, 0, size, size, 1, 1, remap_vector, false);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// Failed to create temporary object, bail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto image = result->image();
|
||||
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
|
||||
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 6 };
|
||||
@ -601,6 +613,12 @@ namespace vk
|
||||
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_3D,
|
||||
VK_IMAGE_VIEW_TYPE_3D, gcm_format, 0, 0, width, height, depth, 1, remap_vector, false);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// Failed to create temporary object, bail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto image = result->image();
|
||||
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
|
||||
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 };
|
||||
@ -630,6 +648,12 @@ namespace vk
|
||||
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
|
||||
VK_IMAGE_VIEW_TYPE_2D, gcm_format, 0, 0, width, height, 1, 1, remap_vector, false);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// Failed to create temporary object, bail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto image = result->image();
|
||||
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
|
||||
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 };
|
||||
@ -660,6 +684,12 @@ namespace vk
|
||||
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
|
||||
VK_IMAGE_VIEW_TYPE_2D, gcm_format, 0, 0, width, height, 1, mipmaps, remap_vector, false);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// Failed to create temporary object, bail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto image = result->image();
|
||||
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
|
||||
VkImageSubresourceRange dst_range = { dst_aspect, 0, mipmaps, 0, 1 };
|
||||
|
@ -100,6 +100,9 @@ namespace vk
|
||||
ensure(!value && !memory);
|
||||
validate(dev, info);
|
||||
|
||||
const bool nullable = !!(info.flags & VK_IMAGE_CREATE_ALLOW_NULL);
|
||||
info.flags &= ~VK_IMAGE_CREATE_ALLOW_NULL;
|
||||
|
||||
CHECK_RESULT(vkCreateImage(m_device, &info, nullptr, &value));
|
||||
|
||||
VkMemoryRequirements memory_req;
|
||||
@ -111,10 +114,19 @@ namespace vk
|
||||
fmt::throw_exception("No compatible memory type was found!");
|
||||
}
|
||||
|
||||
memory = std::make_shared<vk::memory_block>(m_device, memory_req.size, memory_req.alignment, allocation_type_info, allocation_pool);
|
||||
CHECK_RESULT(vkBindImageMemory(m_device, value, memory->get_vk_device_memory(), memory->get_vk_device_memory_offset()));
|
||||
|
||||
current_layout = info.initialLayout;
|
||||
memory = std::make_shared<vk::memory_block>(m_device, memory_req.size, memory_req.alignment, allocation_type_info, allocation_pool, nullable);
|
||||
if (auto device_mem = memory->get_vk_device_memory();
|
||||
device_mem != VK_NULL_HANDLE) [[likely]]
|
||||
{
|
||||
CHECK_RESULT(vkBindImageMemory(m_device, value, device_mem, memory->get_vk_device_memory_offset()));
|
||||
current_layout = info.initialLayout;
|
||||
}
|
||||
else
|
||||
{
|
||||
ensure(nullable);
|
||||
vkDestroyImage(m_device, value, nullptr);
|
||||
value = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
u32 image::width() const
|
||||
|
@ -23,7 +23,8 @@ namespace vk
|
||||
enum : u32// special remap_encoding enums
|
||||
{
|
||||
VK_REMAP_IDENTITY = 0xCAFEBABE, // Special view encoding to return an identity image view
|
||||
VK_REMAP_VIEW_MULTISAMPLED = 0xDEADBEEF // Special encoding for multisampled images; returns a multisampled image view
|
||||
VK_REMAP_VIEW_MULTISAMPLED = 0xDEADBEEF, // Special encoding for multisampled images; returns a multisampled image view
|
||||
VK_IMAGE_CREATE_ALLOW_NULL = 0x80000000, // Special flag that allows null images to be created if there is no memory
|
||||
};
|
||||
|
||||
class image
|
||||
|
@ -150,7 +150,7 @@ namespace vk
|
||||
vmaDestroyAllocator(m_allocator);
|
||||
}
|
||||
|
||||
mem_allocator_vk::mem_handle_t mem_allocator_vma::alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool)
|
||||
mem_allocator_vk::mem_handle_t mem_allocator_vma::alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool, bool throw_on_fail)
|
||||
{
|
||||
VmaAllocation vma_alloc;
|
||||
VkMemoryRequirements mem_req = {};
|
||||
@ -187,8 +187,9 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
const auto severity = (throw_on_fail) ? rsx::problem_severity::fatal : rsx::problem_severity::severe;
|
||||
if (error_code == VK_ERROR_OUT_OF_DEVICE_MEMORY &&
|
||||
vmm_handle_memory_pressure(rsx::problem_severity::fatal))
|
||||
vmm_handle_memory_pressure(severity))
|
||||
{
|
||||
// Out of memory. Try again.
|
||||
const auto [status, type] = do_vma_alloc();
|
||||
@ -200,6 +201,11 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
if (!throw_on_fail)
|
||||
{
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
die_with_error(error_code);
|
||||
fmt::throw_exception("Unreachable! Error_code=0x%x", static_cast<u32>(error_code));
|
||||
}
|
||||
@ -228,8 +234,12 @@ namespace vk
|
||||
|
||||
VkDeviceMemory mem_allocator_vma::get_vk_device_memory(mem_handle_t mem_handle)
|
||||
{
|
||||
VmaAllocationInfo alloc_info;
|
||||
if (!mem_handle)
|
||||
{
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VmaAllocationInfo alloc_info;
|
||||
vmaGetAllocationInfo(m_allocator, static_cast<VmaAllocation>(mem_handle), &alloc_info);
|
||||
return alloc_info.deviceMemory;
|
||||
}
|
||||
@ -271,7 +281,7 @@ namespace vk
|
||||
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*/, const memory_type_info& memory_type, vmm_allocation_pool pool)
|
||||
mem_allocator_vk::mem_handle_t mem_allocator_vk::alloc(u64 block_sz, u64 /*alignment*/, const memory_type_info& memory_type, vmm_allocation_pool pool, bool throw_on_fail)
|
||||
{
|
||||
VkResult error_code;
|
||||
VkDeviceMemory memory;
|
||||
@ -304,8 +314,9 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
const auto severity = (throw_on_fail) ? rsx::problem_severity::fatal : rsx::problem_severity::severe;
|
||||
if (error_code == VK_ERROR_OUT_OF_DEVICE_MEMORY &&
|
||||
vmm_handle_memory_pressure(rsx::problem_severity::fatal))
|
||||
vmm_handle_memory_pressure(severity))
|
||||
{
|
||||
// Out of memory. Try again.
|
||||
const auto [status, type] = do_vk_alloc();
|
||||
@ -317,6 +328,11 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
if (!throw_on_fail)
|
||||
{
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
die_with_error(error_code);
|
||||
fmt::throw_exception("Unreachable! Error_code=0x%x", static_cast<u32>(error_code));
|
||||
}
|
||||
@ -359,16 +375,16 @@ namespace vk
|
||||
return g_render_device->get_allocator();
|
||||
}
|
||||
|
||||
memory_block::memory_block(VkDevice dev, u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool)
|
||||
memory_block::memory_block(VkDevice dev, u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool, bool nullable)
|
||||
: 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, pool);
|
||||
m_mem_handle = m_mem_allocator->alloc(block_sz, alignment, memory_type, pool, !nullable);
|
||||
}
|
||||
|
||||
memory_block::~memory_block()
|
||||
{
|
||||
if (m_mem_allocator)
|
||||
if (m_mem_allocator && m_mem_handle)
|
||||
{
|
||||
m_mem_allocator->free(m_mem_handle);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace vk
|
||||
|
||||
virtual void destroy() = 0;
|
||||
|
||||
virtual mem_handle_t alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool) = 0;
|
||||
virtual mem_handle_t alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool, bool throw_on_fail) = 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;
|
||||
@ -86,7 +86,7 @@ namespace vk
|
||||
|
||||
void destroy() override;
|
||||
|
||||
mem_handle_t alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool) override;
|
||||
mem_handle_t alloc(u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool, bool throw_on_fail) override;
|
||||
|
||||
void free(mem_handle_t mem_handle) override;
|
||||
void* map(mem_handle_t mem_handle, u64 offset, u64 /*size*/) override;
|
||||
@ -115,7 +115,7 @@ namespace vk
|
||||
|
||||
void destroy() override {}
|
||||
|
||||
mem_handle_t alloc(u64 block_sz, u64 /*alignment*/, const memory_type_info& memory_type, vmm_allocation_pool pool) override;
|
||||
mem_handle_t alloc(u64 block_sz, u64 /*alignment*/, const memory_type_info& memory_type, vmm_allocation_pool pool, bool throw_on_fail) override;
|
||||
|
||||
void free(mem_handle_t mem_handle) override;
|
||||
void* map(mem_handle_t mem_handle, u64 offset, u64 size) override;
|
||||
@ -128,7 +128,7 @@ namespace vk
|
||||
|
||||
struct memory_block
|
||||
{
|
||||
memory_block(VkDevice dev, u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool);
|
||||
memory_block(VkDevice dev, u64 block_sz, u64 alignment, const memory_type_info& memory_type, vmm_allocation_pool pool, bool nullable = false);
|
||||
virtual ~memory_block();
|
||||
|
||||
virtual VkDeviceMemory get_vk_device_memory();
|
||||
|
@ -97,7 +97,14 @@ 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, VMM_ALLOCATION_POOL_SCRATCH);
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, flags | VK_IMAGE_CREATE_ALLOW_NULL, VMM_ALLOCATION_POOL_SCRATCH);
|
||||
|
||||
if (!tex->value)
|
||||
{
|
||||
// If we cannot create a 1x1 placeholder, things are truly hopeless.
|
||||
// The null view is 'nullable' because it is meant for use in emergency situations and we do not wish to invalidate any handles.
|
||||
fmt::throw_exception("Renderer is out of memory. We could not even squeeze in a 1x1 texture, things are bad.");
|
||||
}
|
||||
|
||||
// Initialize memory to transparent black
|
||||
tex->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
Loading…
Reference in New Issue
Block a user