Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rsx: Improve surface<->texture cache communication #13077

Merged
merged 7 commits into from
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions Utilities/stack_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,43 @@

namespace utils
{
namespace stack_trace
{
// Printing utilities

template <typename T>
concept Logger = requires (T& t, const std::string& msg)
{
{ t.print(msg) };
};

struct print_to_log
{
logs::channel& log;

public:
print_to_log(logs::channel& chan)
: log(chan)
{}

void print(const std::string& s)
{
log.error("%s", s);
}
};
}

std::vector<void*> get_backtrace(int max_depth = 255);
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack);

FORCE_INLINE void print_trace(logs::channel& logger, int max_depth = 255)
FORCE_INLINE void print_trace(stack_trace::Logger auto& logger, int max_depth = 255)
{
const auto trace = get_backtrace(max_depth);
const auto lines = get_backtrace_symbols(trace);

for (const auto& line : lines)
{
logger.error("%s", line);
logger.print(line);
}
}
}
83 changes: 80 additions & 3 deletions rpcs3/Emu/RSX/Common/surface_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ namespace rsx
};

template <typename image_storage_type>
struct render_target_descriptor
struct render_target_descriptor : public rsx::ref_counted
{
u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to
u32 base_addr = 0;
Expand Down Expand Up @@ -165,6 +165,13 @@ namespace rsx
}
format_info;

struct
{
u64 timestamp = 0;
bool locked = false;
}
texture_cache_metadata;

render_target_descriptor() {}

virtual ~render_target_descriptor()
Expand All @@ -178,7 +185,11 @@ namespace rsx

virtual image_storage_type get_surface(rsx::surface_access access_type) = 0;
virtual bool is_depth_surface() const = 0;
virtual void release_ref(image_storage_type) const = 0;

void reset()
{
texture_cache_metadata = {};
}

template<rsx::surface_metrics Metrics = rsx::surface_metrics::pixels, typename T = u32>
T get_surface_width() const
Expand Down Expand Up @@ -381,6 +392,9 @@ namespace rsx
ensure(native_pitch);
ensure(rsx_pitch);

// Clear metadata
reset();

base_addr = address;

const u32 size_x = (native_pitch > 8)? (native_pitch - 8) : 0u;
Expand Down Expand Up @@ -438,7 +452,7 @@ namespace rsx
{
for (auto &e : old_contents)
{
release_ref(e.source);
ensure(dynamic_cast<rsx::ref_counted*>(e.source))->release();
}

old_contents.clear();
Expand Down Expand Up @@ -696,5 +710,68 @@ namespace rsx
ensure(access_type.is_read() || access_type.is_transfer());
transform_samples_to_pixels(region);
}

void on_lock()
{
add_ref();
texture_cache_metadata.locked = true;
texture_cache_metadata.timestamp = rsx::get_shared_tag();
}

void on_unlock()
{
texture_cache_metadata.locked = false;
texture_cache_metadata.timestamp = rsx::get_shared_tag();
release();
}

void on_swap_out()
{
if (is_locked())
{
on_unlock();
}
else
{
release();
}
}

void on_swap_in(bool lock)
{
if (!is_locked() && lock)
{
on_lock();
}
else
{
add_ref();
}
}

void on_clone_from(const render_target_descriptor* ref)
{
if (ref->is_locked() && !is_locked())
{
// Propagate locked state only.
texture_cache_metadata = ref->texture_cache_metadata;
}

rsx_pitch = ref->get_rsx_pitch();
last_use_tag = ref->last_use_tag;
raster_type = ref->raster_type; // Can't actually cut up swizzled data
}

bool is_locked() const
{
return texture_cache_metadata.locked;
}

bool has_flushable_data() const
{
ensure(is_locked());
ensure(texture_cache_metadata.timestamp);
return (texture_cache_metadata.timestamp < last_use_tag);
}
};
}
1 change: 1 addition & 0 deletions rpcs3/Emu/RSX/Common/texture_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ namespace rsx
}

data.flushed = true;
update_cache_tag();
}


Expand Down
42 changes: 33 additions & 9 deletions rpcs3/Emu/RSX/Common/texture_cache_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,26 @@ namespace rsx
return (get_protection() == utils::protection::no);
}

bool is_synchronized() const
{
return synchronized;
}

bool is_flushed() const
{
return flushed;
}

bool should_flush() const
{
if (context == rsx::texture_upload_context::framebuffer_storage)
{
const auto surface = derived()->get_render_target();
return surface->has_flushable_data();
}

return true;
}

private:
/**
Expand Down Expand Up @@ -1355,18 +1375,18 @@ namespace rsx
if (context == rsx::texture_upload_context::framebuffer_storage && !Emu.IsStopped())
{
// Lock, unlock
auto surface = derived()->get_render_target();

if (prot == utils::protection::no && old_prot != utils::protection::no)
{
// Locked memory. We have to take ownership of the object in the surface cache as well
auto surface = derived()->get_render_target();
surface->add_ref();
surface->on_lock();
}
else if (old_prot == utils::protection::no && prot != utils::protection::no)
{
// Release the surface, the cache can remove it if needed
ensure(prot == utils::protection::rw);
auto surface = derived()->get_render_target();
surface->release();
surface->on_unlock();
}
}
}
Expand Down Expand Up @@ -1625,12 +1645,18 @@ namespace rsx
ensure(exists());
AUDIT(is_locked());

// If we are fully inside the flush exclusions regions, we just mark ourselves as flushed and return
if (get_confirmed_range().inside(flush_exclusions))
auto cleanup_flush = [&]()
{
flushed = true;
flush_exclusions.clear();
on_flush();
};

// If we are fully inside the flush exclusions regions, we just mark ourselves as flushed and return
// We apply the same skip if there is nothing new in the surface data
if (!should_flush() || get_confirmed_range().inside(flush_exclusions))
{
cleanup_flush();
return;
}

Expand All @@ -1642,10 +1668,8 @@ namespace rsx

// Finish up
// Its highly likely that this surface will be reused, so we just leave resources in place
flushed = true;
derived()->finish_flush();
flush_exclusions.clear();
on_flush();
cleanup_flush();
}

void add_flush_exclusion(const address_range& rng)
Expand Down
7 changes: 6 additions & 1 deletion rpcs3/Emu/RSX/GL/GLRenderTargets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,15 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
!!g_cfg.video.write_color_buffers;

if (lock &&
#ifdef TEXTURE_CACHE_DEBUG
!m_gl_texture_cache.is_protected(
base_addr,
surface->get_memory_range(),
rsx::texture_upload_context::framebuffer_storage))
rsx::texture_upload_context::framebuffer_storage)
#else
!surface->is_locked()
#endif
)
{
lock = false;
}
Expand Down
18 changes: 8 additions & 10 deletions rpcs3/Emu/RSX/GL/GLRenderTargets.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace rsx

namespace gl
{
class render_target : public viewable_image, public rsx::ref_counted, public rsx::render_target_descriptor<texture*>
class render_target : public viewable_image, public rsx::render_target_descriptor<texture*>
{
void clear_memory(gl::command_context& cmd);
void load_memory(gl::command_context& cmd);
Expand Down Expand Up @@ -81,11 +81,6 @@ namespace gl
return !!(aspect() & gl::image_aspect::depth);
}

void release_ref(texture* t) const override
{
static_cast<gl::render_target*>(t)->release();
}

viewable_image* get_surface(rsx::surface_access /*access_type*/) override
{
// TODO
Expand Down Expand Up @@ -118,6 +113,11 @@ namespace gl
{
return ensure(dynamic_cast<gl::render_target*>(t));
}

static inline const gl::render_target* as_rtt(const gl::texture* t)
{
return ensure(dynamic_cast<const gl::render_target*>(t));
}
}

struct gl_render_target_traits
Expand Down Expand Up @@ -215,7 +215,7 @@ struct gl_render_target_traits
sink->queue_tag(address);
}

prev.target = sink.get();
sink->on_clone_from(ref);

if (!sink->old_contents.empty())
{
Expand All @@ -230,10 +230,8 @@ struct gl_render_target_traits
}
}

sink->set_rsx_pitch(ref->get_rsx_pitch());
prev.target = sink.get();
sink->set_old_contents_region(prev, false);
sink->last_use_tag = ref->last_use_tag;
sink->raster_type = ref->raster_type; // Can't actually cut up swizzled data
}

static
Expand Down
26 changes: 3 additions & 23 deletions rpcs3/Emu/RSX/GL/GLTextureCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ namespace gl
if (vram_texture && !managed_texture && get_protection() == utils::protection::no)
{
// In-place image swap, still locked. Likely a color buffer that got rebound as depth buffer or vice-versa.
gl::as_rtt(vram_texture)->release();
gl::as_rtt(vram_texture)->on_swap_out();

if (!managed)
{
// Incoming is also an external resource, reference it immediately
gl::as_rtt(image)->add_ref();
gl::as_rtt(image)->on_swap_in(is_locked());
}
}

Expand Down Expand Up @@ -383,26 +383,6 @@ namespace gl
return format;
}

bool is_flushed() const
{
return flushed;
}

bool is_synchronized() const
{
return synchronized;
}

void set_flushed(bool state)
{
flushed = state;
}

bool is_empty() const
{
return vram_texture == nullptr;
}

gl::texture_view* get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap)
{
return vram_texture->get_view(remap_encoding, remap);
Expand All @@ -413,7 +393,7 @@ namespace gl
return managed_texture.get();
}

gl::render_target* get_render_target()
gl::render_target* get_render_target() const
{
return gl::as_rtt(vram_texture);
}
Expand Down
Loading