From 4e2071b6d9b414fa0152deb5e9d55674d636afe4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 8 May 2019 17:45:59 -0400 Subject: texture_cache: Correct premature texceptions Due to our current infrastructure, it is possible for a mipmap to be set on as a render target before a texception of that mipmap's superset be set afterwards. This is problematic as we rely on texture views to set up texceptions and protecting render targets targets for 3D texture rendering. One simple solution is to configure framebuffers after texture setup but this brings other problems. This solution, forces a reconfiguration of the framebuffers after such event happens. --- src/video_core/texture_cache/surface_base.h | 17 ++++++++++++++--- src/video_core/texture_cache/texture_cache.h | 26 ++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'src/video_core/texture_cache') diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 017ee999e..179e80ddb 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -55,6 +55,11 @@ public: return (cache_addr < end) && (cache_addr_end > start); } + bool IsInside(const GPUVAddr other_start, const GPUVAddr other_end) { + const GPUVAddr gpu_addr_end = gpu_addr + guest_memory_size; + return (gpu_addr <= other_start && other_end <= gpu_addr_end); + } + // Use only when recycling a surface void SetGpuAddr(const GPUVAddr new_addr) { gpu_addr = new_addr; @@ -105,6 +110,12 @@ public: return params.target == target; } + bool MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const { + return std::tie(gpu_addr, params.target, params.num_levels) == + std::tie(other_gpu_addr, rhs.target, rhs.num_levels) && + params.target == SurfaceTarget::Texture2D && params.num_levels == 1; + } + bool MatchesTopology(const SurfaceParams& rhs) const { const u32 src_bpp{params.GetBytesPerPixel()}; const u32 dst_bpp{rhs.GetBytesPerPixel()}; @@ -121,9 +132,9 @@ public: } // Tiled surface if (std::tie(params.height, params.depth, params.block_width, params.block_height, - params.block_depth, params.tile_width_spacing) == + params.block_depth, params.tile_width_spacing, params.num_levels) == std::tie(rhs.height, rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth, - rhs.tile_width_spacing)) { + rhs.tile_width_spacing, rhs.num_levels)) { if (params.width == rhs.width) { return MatchStructureResult::FullMatch; } @@ -259,7 +270,7 @@ public: std::optional EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) { if (view_addr < gpu_addr || params.target == SurfaceTarget::Texture3D || - view_params.target == SurfaceTarget::Texture3D) { + params.num_levels == 1 || view_params.target == SurfaceTarget::Texture3D) { return {}; } const auto layer_mipmap{GetLayerMipmap(view_addr)}; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 422bf3e58..96d108147 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -120,6 +120,10 @@ public: return {}; } + if (regs.color_mask[index].raw == 0) { + return {}; + } + auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), preserve_contents); if (render_targets[index].target) @@ -183,6 +187,12 @@ public: return ++ticks; } + bool ConsumeReconfigurationFlag() { + const bool result = force_reconfiguration; + force_reconfiguration = false; + return result; + } + protected: TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) : system{system}, rasterizer{rasterizer} { @@ -219,9 +229,10 @@ protected: rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); } - void Unregister(TSurface surface) { - if (surface->IsProtected()) + void Unregister(TSurface surface, const bool force_unregister = false) { + if (surface->IsProtected() && !force_unregister) { return; + } const GPUVAddr gpu_addr = surface->GetGpuAddr(); const CacheAddr cache_ptr = surface->GetCacheAddr(); const std::size_t size = surface->GetSizeInBytes(); @@ -365,8 +376,10 @@ private: std::min(src_params.height, dst_height), 1); ImageCopy(surface, new_surface, copy_params); } + force_reconfiguration = false; for (auto surface : overlaps) { - Unregister(surface); + force_reconfiguration |= surface->IsProtected(); + Unregister(surface, true); } Register(new_surface); return {{new_surface, new_surface->GetMainView()}}; @@ -379,6 +392,7 @@ private: const auto cache_addr{ToCacheAddr(host_ptr)}; const std::size_t candidate_size = params.GetGuestSizeInBytes(); auto overlaps{GetSurfacesInRegion(cache_addr, candidate_size)}; + if (overlaps.empty()) { return InitializeSurface(gpu_addr, params, preserve_contents); } @@ -403,7 +417,7 @@ private: return RebuildSurface(current_surface, params); } } - if (current_surface->GetSizeInBytes() <= candidate_size) { + if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false); } @@ -530,6 +544,10 @@ private: u64 ticks{}; + // Sometimes Setup Textures can hit a surface that's on the render target, when this happens + // we force a reconfiguration of the frame buffer after setup. + bool force_reconfiguration; + // The internal Cache is different for the Texture Cache. It's based on buckets // of 1MB. This fits better for the purpose of this cache as textures are normaly // large in size. -- cgit v1.2.3