mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-06-07 07:35:02 -06:00
vk: Dynamic heap management to potentially fix ring buffer overflows
- Allows checking one heap type at a time, on demand - Should avoid OOM situations unless inside an uninterruptible block
This commit is contained in:
parent
a4495c35b7
commit
12dc3c1872
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ring buffer memory helper :
|
* Ring buffer memory helper :
|
||||||
@ -106,7 +106,7 @@ public:
|
|||||||
return (m_put_pos - 1 > 0) ? m_put_pos - 1 : m_size - 1;
|
return (m_put_pos - 1 > 0) ? m_put_pos - 1 : m_size - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_critical()
|
bool is_critical() const
|
||||||
{
|
{
|
||||||
const size_t guard_length = std::max(m_min_guard_size, m_largest_allocated_pool);
|
const size_t guard_length = std::max(m_min_guard_size, m_largest_allocated_pool);
|
||||||
return (m_current_allocated_size + guard_length) >= m_size;
|
return (m_current_allocated_size + guard_length) >= m_size;
|
||||||
|
|||||||
@ -939,17 +939,67 @@ void VKGSRender::notify_tile_unbound(u32 tile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGSRender::check_heap_status()
|
void VKGSRender::check_heap_status(u32 flags)
|
||||||
{
|
{
|
||||||
if (m_attrib_ring_info.is_critical() ||
|
bool heap_critical;
|
||||||
m_texture_upload_buffer_ring_info.is_critical() ||
|
if (flags == VK_HEAP_CHECK_ALL)
|
||||||
m_fragment_env_ring_info.is_critical() ||
|
{
|
||||||
m_vertex_env_ring_info.is_critical() ||
|
heap_critical = m_attrib_ring_info.is_critical() ||
|
||||||
m_fragment_texture_params_ring_info.is_critical() ||
|
m_texture_upload_buffer_ring_info.is_critical() ||
|
||||||
m_vertex_layout_ring_info.is_critical() ||
|
m_fragment_env_ring_info.is_critical() ||
|
||||||
m_fragment_constants_ring_info.is_critical() ||
|
m_vertex_env_ring_info.is_critical() ||
|
||||||
m_transform_constants_ring_info.is_critical() ||
|
m_fragment_texture_params_ring_info.is_critical() ||
|
||||||
m_index_buffer_ring_info.is_critical())
|
m_vertex_layout_ring_info.is_critical() ||
|
||||||
|
m_fragment_constants_ring_info.is_critical() ||
|
||||||
|
m_transform_constants_ring_info.is_critical() ||
|
||||||
|
m_index_buffer_ring_info.is_critical();
|
||||||
|
}
|
||||||
|
else if (flags)
|
||||||
|
{
|
||||||
|
heap_critical = false;
|
||||||
|
u32 test = 1 << utils::cnttz32(flags, true);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
switch (flags & test)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE:
|
||||||
|
heap_critical = m_texture_upload_buffer_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_VERTEX_STORAGE:
|
||||||
|
heap_critical = m_attrib_ring_info.is_critical() || m_index_buffer_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_VERTEX_ENV_STORAGE:
|
||||||
|
heap_critical = m_vertex_env_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_FRAGMENT_ENV_STORAGE:
|
||||||
|
heap_critical = m_fragment_env_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_TEXTURE_ENV_STORAGE:
|
||||||
|
heap_critical = m_fragment_texture_params_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_VERTEX_LAYOUT_STORAGE:
|
||||||
|
heap_critical = m_vertex_layout_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_TRANSFORM_CONSTANTS_STORAGE:
|
||||||
|
heap_critical = m_transform_constants_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
case VK_HEAP_CHECK_FRAGMENT_CONSTANTS_STORAGE:
|
||||||
|
heap_critical = m_fragment_constants_ring_info.is_critical();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fmt::throw_exception("Unexpected heap flag set! (0x%X)", test);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags &= ~test;
|
||||||
|
test <<= 1;
|
||||||
|
}
|
||||||
|
while (flags && !heap_critical);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heap_critical)
|
||||||
{
|
{
|
||||||
std::chrono::time_point<steady_clock> submit_start = steady_clock::now();
|
std::chrono::time_point<steady_clock> submit_start = steady_clock::now();
|
||||||
|
|
||||||
@ -1144,8 +1194,6 @@ void VKGSRender::begin()
|
|||||||
|
|
||||||
if (!framebuffer_status_valid)
|
if (!framebuffer_status_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
check_heap_status();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGSRender::update_draw_state()
|
void VKGSRender::update_draw_state()
|
||||||
@ -1454,6 +1502,8 @@ void VKGSRender::end()
|
|||||||
|
|
||||||
if (rsx::method_registers.fragment_textures[i].enabled())
|
if (rsx::method_registers.fragment_textures[i].enabled())
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE);
|
||||||
|
|
||||||
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, rsx::method_registers.fragment_textures[i], m_rtts);
|
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, rsx::method_registers.fragment_textures[i], m_rtts);
|
||||||
|
|
||||||
const u32 texture_format = rsx::method_registers.fragment_textures[i].format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN);
|
const u32 texture_format = rsx::method_registers.fragment_textures[i].format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN);
|
||||||
@ -1742,6 +1792,9 @@ void VKGSRender::end()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Final heap check...
|
||||||
|
check_heap_status(VK_HEAP_CHECK_VERTEX_STORAGE | VK_HEAP_CHECK_VERTEX_LAYOUT_STORAGE);
|
||||||
|
|
||||||
// While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point
|
// While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point
|
||||||
// Only textures are synchronized tightly with the GPU and they have been read back above
|
// Only textures are synchronized tightly with the GPU and they have been read back above
|
||||||
vk::enter_uninterruptible();
|
vk::enter_uninterruptible();
|
||||||
@ -2633,6 +2686,8 @@ void VKGSRender::load_program_env()
|
|||||||
|
|
||||||
if (update_vertex_env)
|
if (update_vertex_env)
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_VERTEX_ENV_STORAGE);
|
||||||
|
|
||||||
// Vertex state
|
// Vertex state
|
||||||
const auto mem = m_vertex_env_ring_info.alloc<256>(256);
|
const auto mem = m_vertex_env_ring_info.alloc<256>(256);
|
||||||
auto buf = (u8*)m_vertex_env_ring_info.map(mem, 144);
|
auto buf = (u8*)m_vertex_env_ring_info.map(mem, 144);
|
||||||
@ -2650,6 +2705,8 @@ void VKGSRender::load_program_env()
|
|||||||
|
|
||||||
if (update_transform_constants)
|
if (update_transform_constants)
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_TRANSFORM_CONSTANTS_STORAGE);
|
||||||
|
|
||||||
// Transform constants
|
// Transform constants
|
||||||
auto mem = m_transform_constants_ring_info.alloc<256>(8192);
|
auto mem = m_transform_constants_ring_info.alloc<256>(8192);
|
||||||
auto buf = m_transform_constants_ring_info.map(mem, 8192);
|
auto buf = m_transform_constants_ring_info.map(mem, 8192);
|
||||||
@ -2661,6 +2718,8 @@ void VKGSRender::load_program_env()
|
|||||||
|
|
||||||
if (update_fragment_constants)
|
if (update_fragment_constants)
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_FRAGMENT_CONSTANTS_STORAGE);
|
||||||
|
|
||||||
// Fragment constants
|
// Fragment constants
|
||||||
if (fragment_constants_size)
|
if (fragment_constants_size)
|
||||||
{
|
{
|
||||||
@ -2681,6 +2740,8 @@ void VKGSRender::load_program_env()
|
|||||||
|
|
||||||
if (update_fragment_env)
|
if (update_fragment_env)
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_FRAGMENT_ENV_STORAGE);
|
||||||
|
|
||||||
auto mem = m_fragment_env_ring_info.alloc<256>(256);
|
auto mem = m_fragment_env_ring_info.alloc<256>(256);
|
||||||
auto buf = m_fragment_env_ring_info.map(mem, 32);
|
auto buf = m_fragment_env_ring_info.map(mem, 32);
|
||||||
|
|
||||||
@ -2691,6 +2752,8 @@ void VKGSRender::load_program_env()
|
|||||||
|
|
||||||
if (update_fragment_texture_env)
|
if (update_fragment_texture_env)
|
||||||
{
|
{
|
||||||
|
check_heap_status(VK_HEAP_CHECK_TEXTURE_ENV_STORAGE);
|
||||||
|
|
||||||
auto mem = m_fragment_texture_params_ring_info.alloc<256>(256);
|
auto mem = m_fragment_texture_params_ring_info.alloc<256>(256);
|
||||||
auto buf = m_fragment_texture_params_ring_info.map(mem, 256);
|
auto buf = m_fragment_texture_params_ring_info.map(mem, 256);
|
||||||
|
|
||||||
@ -2733,9 +2796,9 @@ void VKGSRender::update_vertex_env(const vk::vertex_upload_info& vertex_info)
|
|||||||
|
|
||||||
void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool skip_reading)
|
void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool skip_reading)
|
||||||
{
|
{
|
||||||
//Clear any pending swap requests
|
// Clear any pending swap requests
|
||||||
//TODO: Decide on what to do if we circle back to a new frame before the previous frame waiting on it is still pending
|
// TODO: Decide on what to do if we circle back to a new frame before the previous frame waiting on it is still pending
|
||||||
//Dropping the frame would in theory allow the thread to advance faster
|
// Dropping the frame would in theory allow the thread to advance faster
|
||||||
for (auto &ctx : frame_context_storage)
|
for (auto &ctx : frame_context_storage)
|
||||||
{
|
{
|
||||||
if (ctx.swap_command_buffer)
|
if (ctx.swap_command_buffer)
|
||||||
@ -3490,8 +3553,8 @@ bool VKGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst
|
|||||||
if (renderer_unavailable)
|
if (renderer_unavailable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Verify enough memory exists before attempting to handle data transfer
|
// Verify enough memory exists before attempting to handle data transfer
|
||||||
check_heap_status();
|
check_heap_status(VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE);
|
||||||
|
|
||||||
if (m_texture_cache.blit(src, dst, interpolate, m_rtts, *m_current_command_buffer))
|
if (m_texture_cache.blit(src, dst, interpolate, m_rtts, *m_current_command_buffer))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -48,6 +48,21 @@ namespace vk
|
|||||||
|
|
||||||
extern u64 get_system_time();
|
extern u64 get_system_time();
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE = 0x1,
|
||||||
|
VK_HEAP_CHECK_VERTEX_STORAGE = 0x2,
|
||||||
|
VK_HEAP_CHECK_VERTEX_ENV_STORAGE = 0x4,
|
||||||
|
VK_HEAP_CHECK_FRAGMENT_ENV_STORAGE = 0x8,
|
||||||
|
VK_HEAP_CHECK_TEXTURE_ENV_STORAGE = 0x10,
|
||||||
|
VK_HEAP_CHECK_VERTEX_LAYOUT_STORAGE = 0x20,
|
||||||
|
VK_HEAP_CHECK_TRANSFORM_CONSTANTS_STORAGE = 0x40,
|
||||||
|
VK_HEAP_CHECK_FRAGMENT_CONSTANTS_STORAGE = 0x80,
|
||||||
|
|
||||||
|
VK_HEAP_CHECK_MAX_ENUM = VK_HEAP_CHECK_FRAGMENT_CONSTANTS_STORAGE,
|
||||||
|
VK_HEAP_CHECK_ALL = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
struct command_buffer_chunk: public vk::command_buffer
|
struct command_buffer_chunk: public vk::command_buffer
|
||||||
{
|
{
|
||||||
VkFence submit_fence = VK_NULL_HANDLE;
|
VkFence submit_fence = VK_NULL_HANDLE;
|
||||||
@ -414,7 +429,7 @@ private:
|
|||||||
|
|
||||||
void update_draw_state();
|
void update_draw_state();
|
||||||
|
|
||||||
void check_heap_status();
|
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
||||||
|
|
||||||
void check_descriptors();
|
void check_descriptors();
|
||||||
VkDescriptorSet allocate_descriptor_set();
|
VkDescriptorSet allocate_descriptor_set();
|
||||||
|
|||||||
@ -68,7 +68,7 @@ namespace vk
|
|||||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||||
{
|
{
|
||||||
verify(HERE), region.imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
verify(HERE), region.imageSubresource.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||||
|
|
||||||
const u32 out_w = region.bufferRowLength? region.bufferRowLength : region.imageExtent.width;
|
const u32 out_w = region.bufferRowLength? region.bufferRowLength : region.imageExtent.width;
|
||||||
const u32 out_h = region.bufferImageHeight? region.bufferImageHeight : region.imageExtent.height;
|
const u32 out_h = region.bufferImageHeight? region.bufferImageHeight : region.imageExtent.height;
|
||||||
@ -76,7 +76,7 @@ namespace vk
|
|||||||
const u32 in_depth_size = packed_length;
|
const u32 in_depth_size = packed_length;
|
||||||
const u32 in_stencil_size = out_w * out_h;
|
const u32 in_stencil_size = out_w * out_h;
|
||||||
|
|
||||||
const u32 allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
const auto allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
||||||
verify(HERE), dst->size() >= allocation_end;
|
verify(HERE), dst->size() >= allocation_end;
|
||||||
|
|
||||||
const VkDeviceSize z_offset = align<VkDeviceSize>(region.bufferOffset + packed_length, 256);
|
const VkDeviceSize z_offset = align<VkDeviceSize>(region.bufferOffset + packed_length, 256);
|
||||||
@ -134,7 +134,7 @@ namespace vk
|
|||||||
const u32 in_depth_size = packed_length;
|
const u32 in_depth_size = packed_length;
|
||||||
const u32 in_stencil_size = out_w * out_h;
|
const u32 in_stencil_size = out_w * out_h;
|
||||||
|
|
||||||
const u32 allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
const auto allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
||||||
verify(HERE), src->size() >= allocation_end;
|
verify(HERE), src->size() >= allocation_end;
|
||||||
|
|
||||||
const VkDeviceSize z_offset = align<VkDeviceSize>(region.bufferOffset + packed_length, 256);
|
const VkDeviceSize z_offset = align<VkDeviceSize>(region.bufferOffset + packed_length, 256);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user