vk: Refactor surface cache by moving code to cpp file

This commit is contained in:
kd-11 2021-07-14 01:14:39 +03:00 committed by kd-11
parent 2ffa8f4623
commit 000414c47d
3 changed files with 169 additions and 54 deletions

View File

@ -1075,14 +1075,24 @@ namespace rsx
{
return false;
}
else
else if (m_active_memory_used > (max_safe_memory * 3) / 2)
{
rsx_log.warning("Surface cache is using too much memory! (%dM)", m_active_memory_used / 0x100000);
return true;
}
else
{
rsx_log.trace("Surface cache is using too much memory! (%dM)", m_active_memory_used / 0x100000);
}
return true;
}
bool handle_memory_pressure(command_list_type cmd, problem_severity /*severity*/)
virtual bool can_collapse_surface(const surface_storage_type&)
{
return true;
}
virtual bool handle_memory_pressure(command_list_type cmd, problem_severity severity)
{
auto process_list_function = [&](std::unordered_map<u32, surface_storage_type>& data)
{
@ -1092,18 +1102,22 @@ namespace rsx
if (surface->dirty())
{
// Force memory barrier to release some resources
surface->memory_barrier(cmd, rsx::surface_access::shader_read);
if (can_collapse_surface(It->second))
{
// NOTE: Do not call memory_barrier under fatal conditions as it can create allocations!
// It would be safer to leave the resources hanging around and spill them instead
surface->memory_barrier(cmd, rsx::surface_access::memory_read);
}
}
else if (!surface->test())
{
// Remove this
invalidate(It->second);
It = data.erase(It);
continue;
}
else
{
++It;
}
++It;
}
};

View File

@ -1,7 +1,128 @@
#include "VKRenderTargets.h"
#include "VKResourceManager.h"
namespace vk
{
void surface_cache::destroy()
{
invalidate_all();
invalidated_resources.clear();
}
u64 surface_cache::get_surface_cache_memory_quota(u64 total_device_memory)
{
total_device_memory /= 0x100000;
u64 quota = 0;
if (total_device_memory >= 2048)
{
quota = std::min(6144ull, (total_device_memory * 40) / 100);
}
else if (total_device_memory >= 1024)
{
quota = 768;
}
else if (total_device_memory >= 768)
{
quota = 256;
}
else
{
// Remove upto 128MB but at least aim for half of available VRAM
quota = std::min(128ull, total_device_memory / 2);
}
return quota * 0x100000;
}
bool surface_cache::can_collapse_surface(const std::unique_ptr<vk::render_target>& surface)
{
if (surface->samples() == 1)
{
return true;
}
// MSAA surface, check if we have the memory for this...
return vk::vmm_determine_memory_load_severity() < rsx::problem_severity::fatal;
}
bool surface_cache::handle_memory_pressure(vk::command_buffer& cmd, rsx::problem_severity severity)
{
bool any_released = rsx::surface_store<surface_cache_traits>::handle_memory_pressure(cmd, severity);
if (severity >= rsx::problem_severity::fatal)
{
// TODO
}
return any_released;
}
void surface_cache::free_invalidated(vk::command_buffer& cmd, rsx::problem_severity memory_pressure)
{
// Do not allow more than 300M of RSX memory to be used by RTTs.
// The actual boundary is 256M but we need to give some overallocation for performance reasons.
if (check_memory_usage(300 * 0x100000))
{
if (!cmd.is_recording())
{
cmd.begin();
}
const auto severity = std::max(memory_pressure, rsx::problem_severity::moderate);
handle_memory_pressure(cmd, severity);
}
const u64 last_finished_frame = vk::get_last_completed_frame_id();
invalidated_resources.remove_if([&](std::unique_ptr<vk::render_target>& rtt)
{
ensure(rtt->frame_tag != 0);
if (rtt->has_refs())
{
// Actively in use, likely for a reading pass.
// Call handle_memory_pressure before calling this method.
return false;
}
if (memory_pressure >= rsx::problem_severity::severe)
{
if (rtt->resolve_surface)
{
// We do not need to keep resolve targets around if things are bad.
vk::get_resource_manager()->dispose(rtt->resolve_surface);
}
}
if (rtt->frame_tag >= last_finished_frame)
{
// RTT itself still in use by the frame.
return false;
}
switch (memory_pressure)
{
case rsx::problem_severity::low:
return (rtt->unused_check_count() >= 2);
case rsx::problem_severity::moderate:
return (rtt->unused_check_count() >= 1);
case rsx::problem_severity::severe:
case rsx::problem_severity::fatal:
// We're almost dead anyway. Remove forcefully.
return true;
default:
fmt::throw_exception("Unreachable");
}
});
}
bool surface_cache::is_overallocated()
{
const auto surface_cache_vram_load = vmm_get_application_pool_usage(VMM_ALLOCATION_POOL_SURFACE_CACHE);
const auto surface_cache_allocation_quota = get_surface_cache_memory_quota(get_current_renderer()->get_memory_mapping().device_local_total_bytes);
return (surface_cache_vram_load > surface_cache_allocation_quota);
}
// Get the linear resolve target bound to this surface. Initialize if none exists
vk::viewable_image* render_target::get_resolve_target_safe(vk::command_buffer& cmd)
{

View File

@ -6,10 +6,10 @@
#include "VKFormats.h"
#include "VKHelpers.h"
#include "vkutils/barriers.h"
#include "vkutils/buffer_object.h"
#include "vkutils/data_heap.h"
#include "vkutils/device.h"
#include "vkutils/image.h"
#include "vkutils/memory.h"
#include "vkutils/scratch.h"
#include <span>
@ -42,6 +42,7 @@ namespace vk
public:
u64 frame_tag = 0; // frame id when invalidated, 0 if not invalid
using viewable_image::viewable_image;
vk::viewable_image* get_surface(rsx::surface_access access_type) override;
@ -78,7 +79,7 @@ namespace vk
rsx::surface_color_format format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias,
vk::render_device &device, vk::command_buffer& cmd)
vk::render_device& device, vk::command_buffer& cmd)
{
const auto fmt = vk::get_compatible_surface_format(format);
VkFormat requested_format = fmt.first;
@ -118,7 +119,7 @@ namespace vk
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL,
usage_flags,
0, vk::VMM_ALLOCATION_POOL_SURFACE_CACHE, RSX_FORMAT_CLASS_COLOR);
0, 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);
@ -144,7 +145,7 @@ namespace vk
rsx::surface_depth_format2 format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias,
vk::render_device &device, vk::command_buffer& cmd)
vk::render_device& device, vk::command_buffer& cmd)
{
const VkFormat requested_format = vk::get_compatible_depth_surface_format(device.get_formats_support(), format);
VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
@ -179,7 +180,7 @@ namespace vk
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL,
usage_flags,
0, vk::VMM_ALLOCATION_POOL_SURFACE_CACHE, rsx::classify_format(format));
0, 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);
@ -187,7 +188,7 @@ namespace vk
ds->set_format(format);
ds->set_aa_mode(antialias);
ds->sample_layout = sample_layout;
ds->memory_usage_flags= rsx::surface_usage_flags::attachment;
ds->memory_usage_flags = rsx::surface_usage_flags::attachment;
ds->state_flags = rsx::surface_state_flags::erase_bkgnd;
ds->native_component_map = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R };
ds->native_pitch = static_cast<u16>(width) * get_format_block_size_in_bytes(format) * ds->samples_x;
@ -221,7 +222,7 @@ namespace vk
VK_IMAGE_TILING_OPTIMAL,
ref->info.usage,
ref->info.flags,
vk::VMM_ALLOCATION_POOL_SURFACE_CACHE,
VMM_ALLOCATION_POOL_SURFACE_CACHE,
ref->format_class());
sink->add_ref();
@ -274,7 +275,7 @@ namespace vk
surface->get_surface_height() >= height);
}
static void prepare_surface_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
static void prepare_surface_for_drawing(vk::command_buffer& cmd, vk::render_target* surface)
{
if (surface->aspect() == VK_IMAGE_ASPECT_COLOR_BIT)
{
@ -292,12 +293,12 @@ namespace vk
static void prepare_surface_for_sampling(vk::command_buffer& /*cmd*/, vk::render_target* /*surface*/)
{}
static bool surface_is_pitch_compatible(const std::unique_ptr<vk::render_target> &surface, usz pitch)
static bool surface_is_pitch_compatible(const std::unique_ptr<vk::render_target>& surface, usz pitch)
{
return surface->rsx_pitch == pitch;
}
static void invalidate_surface_contents(vk::command_buffer& /*cmd*/, vk::render_target *surface, u32 address, usz pitch)
static void invalidate_surface_contents(vk::command_buffer& /*cmd*/, vk::render_target* surface, u32 address, usz pitch)
{
surface->rsx_pitch = static_cast<u16>(pitch);
surface->queue_tag(address);
@ -307,7 +308,7 @@ namespace vk
surface->raster_type = rsx::surface_raster_type::linear;
}
static void notify_surface_invalidated(const std::unique_ptr<vk::render_target> &surface)
static void notify_surface_invalidated(const std::unique_ptr<vk::render_target>& surface)
{
surface->frame_tag = vk::get_current_frame_id();
if (!surface->frame_tag) surface->frame_tag = 1;
@ -324,14 +325,14 @@ namespace vk
static void notify_surface_persist(const std::unique_ptr<vk::render_target>& /*surface*/)
{}
static void notify_surface_reused(const std::unique_ptr<vk::render_target> &surface)
static void notify_surface_reused(const std::unique_ptr<vk::render_target>& surface)
{
surface->state_flags |= rsx::surface_state_flags::erase_bkgnd;
surface->add_ref();
}
static bool int_surface_matches_properties(
const std::unique_ptr<vk::render_target> &surface,
const std::unique_ptr<vk::render_target>& surface,
VkFormat format,
usz width, usz height,
rsx::surface_antialiasing antialias,
@ -349,7 +350,7 @@ namespace vk
}
static bool surface_matches_properties(
const std::unique_ptr<vk::render_target> &surface,
const std::unique_ptr<vk::render_target>& surface,
rsx::surface_color_format format,
usz width, usz height,
rsx::surface_antialiasing antialias,
@ -360,7 +361,7 @@ namespace vk
}
static bool surface_matches_properties(
const std::unique_ptr<vk::render_target> &surface,
const std::unique_ptr<vk::render_target>& surface,
rsx::surface_depth_format2 format,
usz width, usz height,
rsx::surface_antialiasing antialias,
@ -371,43 +372,22 @@ namespace vk
return int_surface_matches_properties(surface, vk_format, width, height, antialias, check_refs);
}
static vk::render_target *get(const std::unique_ptr<vk::render_target> &tex)
static vk::render_target* get(const std::unique_ptr<vk::render_target>& tex)
{
return tex.get();
}
};
struct surface_cache : public rsx::surface_store<vk::surface_cache_traits>
class surface_cache : public rsx::surface_store<vk::surface_cache_traits>
{
void destroy()
{
invalidate_all();
invalidated_resources.clear();
}
private:
u64 get_surface_cache_memory_quota(u64 total_device_memory);
void free_invalidated(vk::command_buffer& cmd)
{
// Do not allow more than 256M of RSX memory to be used by RTTs
if (check_memory_usage(256 * 0x100000))
{
if (!cmd.is_recording())
{
cmd.begin();
}
handle_memory_pressure(cmd, rsx::problem_severity::moderate);
}
const u64 last_finished_frame = vk::get_last_completed_frame_id();
invalidated_resources.remove_if([&](std::unique_ptr<vk::render_target> &rtt)
{
ensure(rtt->frame_tag != 0);
if (rtt->unused_check_count() >= 2 && rtt->frame_tag < last_finished_frame)
return true;
return false;
});
}
public:
void destroy();
bool is_overallocated();
bool can_collapse_surface(const std::unique_ptr<vk::render_target>& surface) override;
bool handle_memory_pressure(vk::command_buffer& cmd, rsx::problem_severity severity) override;
void free_invalidated(vk::command_buffer& cmd, rsx::problem_severity memory_pressure);
};
}