From 9dfe3eb4bcd26207a5b6723dcc40f2c7147b803d Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Wed, 10 Apr 2024 23:00:53 +0300 Subject: [PATCH] rasterizer_cache: Improve validation skip heuristic (#69) --- .../rasterizer_cache/rasterizer_cache.h | 31 ++++++------------- .../rasterizer_cache/rasterizer_cache_base.h | 3 -- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 16027fd93..b1871b3c8 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -1180,27 +1180,16 @@ bool RasterizerCache::ValidateByReinterpretation(Surface& surface, SurfacePar } // No surfaces were found in the cache that had a matching bit-width. - // If there's a surface with invalid format it means the region was cleared - // so we don't want to skip validation in that case. - const bool has_invalid = IntervalHasInvalidPixelFormat(params, interval); - const bool is_gpu_modified = boost::icl::contains(dirty_regions, interval); - return !has_invalid && is_gpu_modified; -} - -template -bool RasterizerCache::IntervalHasInvalidPixelFormat(const SurfaceParams& params, - SurfaceInterval interval) { - bool invalid_format_found = false; - const PAddr addr = boost::icl::lower(interval); - const u32 size = boost::icl::length(interval); - ForEachSurfaceInRegion(addr, size, [&](SurfaceId surface_id, Surface& surface) { - if (surface.pixel_format == PixelFormat::Invalid) { - invalid_format_found = true; - return true; - } - return false; - }); - return invalid_format_found; + // Before entering the slow path, check if part of the interval is owned + // by a gpu modified surface with a different stride than ours. This is indicative + // of texture aliasing by the guest, which for the vast majority of cases we don't + // need to validate. + // TODO: While this works for the vast majority of cases, in Fire Emblem: Shadows of Valentia + // the warping effect when running in dugeons relies on this stride reinterpretation. + // In the future this transformation should be properly implemented with a GPU shader. + const auto it = dirty_regions.find(interval); + return it != dirty_regions.end() && it->second && + slot_surfaces[it->second].stride != surface.stride; } template diff --git a/src/video_core/rasterizer_cache/rasterizer_cache_base.h b/src/video_core/rasterizer_cache/rasterizer_cache_base.h index 13d9682a0..afd3625be 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache_base.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache_base.h @@ -193,9 +193,6 @@ private: bool ValidateByReinterpretation(Surface& surface, SurfaceParams params, const SurfaceInterval& interval); - /// Return true if a surface with an invalid pixel format exists at the interval - bool IntervalHasInvalidPixelFormat(const SurfaceParams& params, SurfaceInterval interval); - /// Create a new surface SurfaceId CreateSurface(const SurfaceParams& params);