From 51c9e98677395564a4fafeaba718cbd2263541bb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Dec 2019 13:13:18 -0400 Subject: Texture Cache: Add HLE methods for building 3D textures within the GPU in certain scenarios. This commit adds a series of HLE methods for handling 3D textures in general. This helps games that generate 3D textures on every frame and may reduce loading times for certain games. --- src/video_core/texture_cache/texture_cache.h | 88 ++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 02d2e9136..5416eee3b 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -615,6 +615,85 @@ private: return {{new_surface, new_surface->GetMainView()}}; } + /** + * Takes care of managing 3D textures and its slices. Does some HLE methods when possible. + * Fallsback to LLE when it isn't possible. + * + * @param overlaps The overlapping surfaces registered in the cache. + * @param params The parameters on the new surface. + * @param gpu_addr The starting address of the new surface. + * @param cache_addr The starting address of the new surface on physical memory. + * @param preserve_contents Indicates that the new surface should be loaded from memory or + * left blank. + */ + std::optional> Manage3DSurfaces(std::vector& overlaps, + const SurfaceParams& params, + const GPUVAddr gpu_addr, + const CacheAddr cache_addr, + bool preserve_contents) { + if (params.target == SurfaceTarget::Texture3D) { + bool failed = false; + if (params.num_levels > 1) { + // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach + return std::nullopt; + } + TSurface new_surface = GetUncachedSurface(gpu_addr, params); + bool modified = false; + for (auto& surface : overlaps) { + const SurfaceParams& src_params = surface->GetSurfaceParams(); + if (src_params.target != SurfaceTarget::Texture2D) { + failed = true; + break; + } + if (src_params.height != params.height) { + failed = true; + break; + } + if (src_params.block_depth != params.block_depth || + src_params.block_height != params.block_height) { + failed = true; + break; + } + const u32 offset = static_cast(surface->GetCacheAddr() - cache_addr); + const auto [x, y, z] = params.GetBlockOffsetXYZ(offset); + modified |= surface->IsModified(); + const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height, + 1); + ImageCopy(surface, new_surface, copy_params); + } + if (failed) { + return std::nullopt; + } + for (const auto& surface : overlaps) { + Unregister(surface); + } + new_surface->MarkAsModified(modified, Tick()); + Register(new_surface); + return {{new_surface, new_surface->GetMainView()}}; + } else { + for (const auto& surface : overlaps) { + if (!surface->MatchTarget(params.target)) { + if (overlaps.size() == 1 && surface->GetCacheAddr() == cache_addr) { + if (Settings::values.use_accurate_gpu_emulation) { + return std::nullopt; + } + Unregister(surface); + return InitializeSurface(gpu_addr, params, preserve_contents); + } + return std::nullopt; + } + if (surface->GetCacheAddr() != cache_addr) { + continue; + } + const auto struct_result = surface->MatchesStructure(params); + if (struct_result == MatchStructureResult::FullMatch) { + return {{surface, surface->GetMainView()}}; + } + } + return InitializeSurface(gpu_addr, params, preserve_contents); + } + } + /** * Gets the starting address and parameters of a candidate surface and tries * to find a matching surface within the cache. This is done in 3 big steps: @@ -687,6 +766,15 @@ private: } } + // Look if it's a 3D texture + if (params.block_depth > 0) { + std::optional> surface = + Manage3DSurfaces(overlaps, params, gpu_addr, cache_addr, preserve_contents); + if (surface) { + return *surface; + } + } + // Split cases between 1 overlap or many. if (overlaps.size() == 1) { TSurface current_surface = overlaps[0]; -- cgit v1.2.3 From a3916588b6964c6764a4f601c86b09a7d5eb2d4f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Dec 2019 09:34:37 -0400 Subject: Texture Cache: Address Feedback --- src/video_core/texture_cache/texture_cache.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 5416eee3b..9c2d108d3 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -619,10 +619,10 @@ private: * Takes care of managing 3D textures and its slices. Does some HLE methods when possible. * Fallsback to LLE when it isn't possible. * - * @param overlaps The overlapping surfaces registered in the cache. - * @param params The parameters on the new surface. - * @param gpu_addr The starting address of the new surface. - * @param cache_addr The starting address of the new surface on physical memory. + * @param overlaps The overlapping surfaces registered in the cache. + * @param params The parameters on the new surface. + * @param gpu_addr The starting address of the new surface. + * @param cache_addr The starting address of the new surface on physical memory. * @param preserve_contents Indicates that the new surface should be loaded from memory or * left blank. */ @@ -669,7 +669,8 @@ private: } new_surface->MarkAsModified(modified, Tick()); Register(new_surface); - return {{new_surface, new_surface->GetMainView()}}; + auto view = new_surface->GetMainView(); + return {{std::move(new_surface), view}}; } else { for (const auto& surface : overlaps) { if (!surface->MatchTarget(params.target)) { @@ -685,8 +686,7 @@ private: if (surface->GetCacheAddr() != cache_addr) { continue; } - const auto struct_result = surface->MatchesStructure(params); - if (struct_result == MatchStructureResult::FullMatch) { + if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) { return {{surface, surface->GetMainView()}}; } } @@ -768,7 +768,7 @@ private: // Look if it's a 3D texture if (params.block_depth > 0) { - std::optional> surface = + auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cache_addr, preserve_contents); if (surface) { return *surface; -- cgit v1.2.3 From 218ee1841772e1d74370d464078c43112ed3505a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 22 Dec 2019 12:29:23 -0400 Subject: Texture Cache: Improve documentation --- src/video_core/texture_cache/texture_cache.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 9c2d108d3..f4c015635 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -616,8 +616,9 @@ private: } /** - * Takes care of managing 3D textures and its slices. Does some HLE methods when possible. - * Fallsback to LLE when it isn't possible. + * Takes care of managing 3D textures and its slices. Does HLE methods for reconstructing the 3D + * textures within the GPU if possible. Falls back to LLE when it isn't possible to use any of + * the HLE methods. * * @param overlaps The overlapping surfaces registered in the cache. * @param params The parameters on the new surface. @@ -766,7 +767,7 @@ private: } } - // Look if it's a 3D texture + // Check if it's a 3D texture if (params.block_depth > 0) { auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cache_addr, preserve_contents); -- cgit v1.2.3