diff options
| author | 2020-06-09 21:52:15 -0400 | |
|---|---|---|
| committer | 2020-06-09 21:52:15 -0400 | |
| commit | 83e3b77ed7eaa12ec497fd7d978c2e889c5d14db (patch) | |
| tree | 2940fc6a036c7b1f5ecc13aca6248ba657ed48f4 /src/video_core/texture_cache | |
| parent | Merge pull request #4040 from ReinUsesLisp/nv-transform-feedback (diff) | |
| parent | texture_cache: Port original code management for 2D vs 3D textures (diff) | |
| download | yuzu-83e3b77ed7eaa12ec497fd7d978c2e889c5d14db.tar.gz yuzu-83e3b77ed7eaa12ec497fd7d978c2e889c5d14db.tar.xz yuzu-83e3b77ed7eaa12ec497fd7d978c2e889c5d14db.zip | |
Merge pull request #4027 from ReinUsesLisp/3d-slices
texture_cache: Implement rendering to 3D textures
Diffstat (limited to 'src/video_core/texture_cache')
| -rw-r--r-- | src/video_core/texture_cache/surface_base.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/texture_cache/surface_base.h | 13 | ||||
| -rw-r--r-- | src/video_core/texture_cache/surface_params.cpp | 19 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 119 |
4 files changed, 88 insertions, 70 deletions
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 715f39d0d..94d3a6ae5 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp | |||
| @@ -248,12 +248,11 @@ void SurfaceBaseImpl::FlushBuffer(Tegra::MemoryManager& memory_manager, | |||
| 248 | 248 | ||
| 249 | // Use an extra temporal buffer | 249 | // Use an extra temporal buffer |
| 250 | auto& tmp_buffer = staging_cache.GetBuffer(1); | 250 | auto& tmp_buffer = staging_cache.GetBuffer(1); |
| 251 | // Special case for 3D Texture Segments | ||
| 252 | const bool must_read_current_data = | ||
| 253 | params.block_depth > 0 && params.target == VideoCore::Surface::SurfaceTarget::Texture2D; | ||
| 254 | tmp_buffer.resize(guest_memory_size); | 251 | tmp_buffer.resize(guest_memory_size); |
| 255 | host_ptr = tmp_buffer.data(); | 252 | host_ptr = tmp_buffer.data(); |
| 256 | if (must_read_current_data) { | 253 | |
| 254 | if (params.target == SurfaceTarget::Texture3D) { | ||
| 255 | // Special case for 3D texture segments | ||
| 257 | memory_manager.ReadBlockUnsafe(gpu_addr, host_ptr, guest_memory_size); | 256 | memory_manager.ReadBlockUnsafe(gpu_addr, host_ptr, guest_memory_size); |
| 258 | } | 257 | } |
| 259 | 258 | ||
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 79e10ffbb..173f2edba 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h | |||
| @@ -217,8 +217,8 @@ public: | |||
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | bool IsProtected() const { | 219 | bool IsProtected() const { |
| 220 | // Only 3D Slices are to be protected | 220 | // Only 3D slices are to be protected |
| 221 | return is_target && params.block_depth > 0; | 221 | return is_target && params.target == SurfaceTarget::Texture3D; |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | bool IsRenderTarget() const { | 224 | bool IsRenderTarget() const { |
| @@ -250,6 +250,11 @@ public: | |||
| 250 | return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels)); | 250 | return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels)); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | TView Emplace3DView(u32 slice, u32 depth, u32 base_level, u32 num_levels) { | ||
| 254 | return GetView(ViewParams(VideoCore::Surface::SurfaceTarget::Texture3D, slice, depth, | ||
| 255 | base_level, num_levels)); | ||
| 256 | } | ||
| 257 | |||
| 253 | std::optional<TView> EmplaceIrregularView(const SurfaceParams& view_params, | 258 | std::optional<TView> EmplaceIrregularView(const SurfaceParams& view_params, |
| 254 | const GPUVAddr view_addr, | 259 | const GPUVAddr view_addr, |
| 255 | const std::size_t candidate_size, const u32 mipmap, | 260 | const std::size_t candidate_size, const u32 mipmap, |
| @@ -272,8 +277,8 @@ public: | |||
| 272 | std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr, | 277 | std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr, |
| 273 | const std::size_t candidate_size) { | 278 | const std::size_t candidate_size) { |
| 274 | if (params.target == SurfaceTarget::Texture3D || | 279 | if (params.target == SurfaceTarget::Texture3D || |
| 275 | (params.num_levels == 1 && !params.is_layered) || | 280 | view_params.target == SurfaceTarget::Texture3D || |
| 276 | view_params.target == SurfaceTarget::Texture3D) { | 281 | (params.num_levels == 1 && !params.is_layered)) { |
| 277 | return {}; | 282 | return {}; |
| 278 | } | 283 | } |
| 279 | const auto layer_mipmap{GetLayerMipmap(view_addr)}; | 284 | const auto layer_mipmap{GetLayerMipmap(view_addr)}; |
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 884fabffe..0b2b2b8c4 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp | |||
| @@ -215,10 +215,19 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz | |||
| 215 | params.num_levels = 1; | 215 | params.num_levels = 1; |
| 216 | params.emulated_levels = 1; | 216 | params.emulated_levels = 1; |
| 217 | 217 | ||
| 218 | const bool is_layered = config.layers > 1 && params.block_depth == 0; | 218 | if (config.memory_layout.is_3d != 0) { |
| 219 | params.is_layered = is_layered; | 219 | params.depth = config.layers.Value(); |
| 220 | params.depth = is_layered ? config.layers.Value() : 1; | 220 | params.is_layered = false; |
| 221 | params.target = is_layered ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D; | 221 | params.target = SurfaceTarget::Texture3D; |
| 222 | } else if (config.layers > 1) { | ||
| 223 | params.depth = config.layers.Value(); | ||
| 224 | params.is_layered = true; | ||
| 225 | params.target = SurfaceTarget::Texture2DArray; | ||
| 226 | } else { | ||
| 227 | params.depth = 1; | ||
| 228 | params.is_layered = false; | ||
| 229 | params.target = SurfaceTarget::Texture2D; | ||
| 230 | } | ||
| 222 | return params; | 231 | return params; |
| 223 | } | 232 | } |
| 224 | 233 | ||
| @@ -237,7 +246,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( | |||
| 237 | params.width = config.width; | 246 | params.width = config.width; |
| 238 | params.height = config.height; | 247 | params.height = config.height; |
| 239 | params.pitch = config.pitch; | 248 | params.pitch = config.pitch; |
| 240 | // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters | 249 | // TODO(Rodrigo): Try to guess texture arrays from parameters |
| 241 | params.target = SurfaceTarget::Texture2D; | 250 | params.target = SurfaceTarget::Texture2D; |
| 242 | params.depth = 1; | 251 | params.depth = 1; |
| 243 | params.num_levels = 1; | 252 | params.num_levels = 1; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 6f63217a2..b543fc8c0 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -298,15 +298,13 @@ public: | |||
| 298 | const GPUVAddr src_gpu_addr = src_config.Address(); | 298 | const GPUVAddr src_gpu_addr = src_config.Address(); |
| 299 | const GPUVAddr dst_gpu_addr = dst_config.Address(); | 299 | const GPUVAddr dst_gpu_addr = dst_config.Address(); |
| 300 | DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); | 300 | DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); |
| 301 | const std::optional<VAddr> dst_cpu_addr = | 301 | |
| 302 | system.GPU().MemoryManager().GpuToCpuAddress(dst_gpu_addr); | 302 | const auto& memory_manager = system.GPU().MemoryManager(); |
| 303 | const std::optional<VAddr> src_cpu_addr = | 303 | const std::optional<VAddr> dst_cpu_addr = memory_manager.GpuToCpuAddress(dst_gpu_addr); |
| 304 | system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr); | 304 | const std::optional<VAddr> src_cpu_addr = memory_manager.GpuToCpuAddress(src_gpu_addr); |
| 305 | std::pair<TSurface, TView> dst_surface = | 305 | std::pair dst_surface = GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false); |
| 306 | GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false); | 306 | TView src_surface = GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false).second; |
| 307 | std::pair<TSurface, TView> src_surface = | 307 | ImageBlit(src_surface, dst_surface.second, copy_config); |
| 308 | GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false); | ||
| 309 | ImageBlit(src_surface.second, dst_surface.second, copy_config); | ||
| 310 | dst_surface.first->MarkAsModified(true, Tick()); | 308 | dst_surface.first->MarkAsModified(true, Tick()); |
| 311 | } | 309 | } |
| 312 | 310 | ||
| @@ -508,12 +506,12 @@ private: | |||
| 508 | return RecycleStrategy::Flush; | 506 | return RecycleStrategy::Flush; |
| 509 | } | 507 | } |
| 510 | // 3D Textures decision | 508 | // 3D Textures decision |
| 511 | if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) { | 509 | if (params.target == SurfaceTarget::Texture3D) { |
| 512 | return RecycleStrategy::Flush; | 510 | return RecycleStrategy::Flush; |
| 513 | } | 511 | } |
| 514 | for (const auto& s : overlaps) { | 512 | for (const auto& s : overlaps) { |
| 515 | const auto& s_params = s->GetSurfaceParams(); | 513 | const auto& s_params = s->GetSurfaceParams(); |
| 516 | if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) { | 514 | if (s_params.target == SurfaceTarget::Texture3D) { |
| 517 | return RecycleStrategy::Flush; | 515 | return RecycleStrategy::Flush; |
| 518 | } | 516 | } |
| 519 | } | 517 | } |
| @@ -731,51 +729,9 @@ private: | |||
| 731 | */ | 729 | */ |
| 732 | std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(VectorSurface& overlaps, | 730 | std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(VectorSurface& overlaps, |
| 733 | const SurfaceParams& params, | 731 | const SurfaceParams& params, |
| 734 | const GPUVAddr gpu_addr, | 732 | GPUVAddr gpu_addr, VAddr cpu_addr, |
| 735 | const VAddr cpu_addr, | ||
| 736 | bool preserve_contents) { | 733 | bool preserve_contents) { |
| 737 | if (params.target == SurfaceTarget::Texture3D) { | 734 | if (params.target != SurfaceTarget::Texture3D) { |
| 738 | bool failed = false; | ||
| 739 | if (params.num_levels > 1) { | ||
| 740 | // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach | ||
| 741 | return std::nullopt; | ||
| 742 | } | ||
| 743 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); | ||
| 744 | bool modified = false; | ||
| 745 | for (auto& surface : overlaps) { | ||
| 746 | const SurfaceParams& src_params = surface->GetSurfaceParams(); | ||
| 747 | if (src_params.target != SurfaceTarget::Texture2D) { | ||
| 748 | failed = true; | ||
| 749 | break; | ||
| 750 | } | ||
| 751 | if (src_params.height != params.height) { | ||
| 752 | failed = true; | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | if (src_params.block_depth != params.block_depth || | ||
| 756 | src_params.block_height != params.block_height) { | ||
| 757 | failed = true; | ||
| 758 | break; | ||
| 759 | } | ||
| 760 | const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr); | ||
| 761 | const auto offsets = params.GetBlockOffsetXYZ(offset); | ||
| 762 | const auto z = std::get<2>(offsets); | ||
| 763 | modified |= surface->IsModified(); | ||
| 764 | const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height, | ||
| 765 | 1); | ||
| 766 | ImageCopy(surface, new_surface, copy_params); | ||
| 767 | } | ||
| 768 | if (failed) { | ||
| 769 | return std::nullopt; | ||
| 770 | } | ||
| 771 | for (const auto& surface : overlaps) { | ||
| 772 | Unregister(surface); | ||
| 773 | } | ||
| 774 | new_surface->MarkAsModified(modified, Tick()); | ||
| 775 | Register(new_surface); | ||
| 776 | auto view = new_surface->GetMainView(); | ||
| 777 | return {{std::move(new_surface), view}}; | ||
| 778 | } else { | ||
| 779 | for (const auto& surface : overlaps) { | 735 | for (const auto& surface : overlaps) { |
| 780 | if (!surface->MatchTarget(params.target)) { | 736 | if (!surface->MatchTarget(params.target)) { |
| 781 | if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) { | 737 | if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) { |
| @@ -791,11 +747,60 @@ private: | |||
| 791 | continue; | 747 | continue; |
| 792 | } | 748 | } |
| 793 | if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) { | 749 | if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) { |
| 794 | return {{surface, surface->GetMainView()}}; | 750 | return std::make_pair(surface, surface->GetMainView()); |
| 795 | } | 751 | } |
| 796 | } | 752 | } |
| 797 | return InitializeSurface(gpu_addr, params, preserve_contents); | 753 | return InitializeSurface(gpu_addr, params, preserve_contents); |
| 798 | } | 754 | } |
| 755 | |||
| 756 | if (params.num_levels > 1) { | ||
| 757 | // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach | ||
| 758 | return std::nullopt; | ||
| 759 | } | ||
| 760 | |||
| 761 | if (overlaps.size() == 1) { | ||
| 762 | const auto& surface = overlaps[0]; | ||
| 763 | const SurfaceParams& overlap_params = surface->GetSurfaceParams(); | ||
| 764 | // Don't attempt to render to textures with more than one level for now | ||
| 765 | // The texture has to be to the right or the sample address if we want to render to it | ||
| 766 | if (overlap_params.num_levels == 1 && cpu_addr >= surface->GetCpuAddr()) { | ||
| 767 | const u32 offset = static_cast<u32>(cpu_addr - surface->GetCpuAddr()); | ||
| 768 | const u32 slice = std::get<2>(params.GetBlockOffsetXYZ(offset)); | ||
| 769 | if (slice < overlap_params.depth) { | ||
| 770 | auto view = surface->Emplace3DView(slice, params.depth, 0, 1); | ||
| 771 | return std::make_pair(std::move(surface), std::move(view)); | ||
| 772 | } | ||
| 773 | } | ||
| 774 | } | ||
| 775 | |||
| 776 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); | ||
| 777 | bool modified = false; | ||
| 778 | |||
| 779 | for (auto& surface : overlaps) { | ||
| 780 | const SurfaceParams& src_params = surface->GetSurfaceParams(); | ||
| 781 | if (src_params.target != SurfaceTarget::Texture2D || | ||
| 782 | src_params.height != params.height || | ||
| 783 | src_params.block_depth != params.block_depth || | ||
| 784 | src_params.block_height != params.block_height) { | ||
| 785 | return std::nullopt; | ||
| 786 | } | ||
| 787 | modified |= surface->IsModified(); | ||
| 788 | |||
| 789 | const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr); | ||
| 790 | const u32 slice = std::get<2>(params.GetBlockOffsetXYZ(offset)); | ||
| 791 | const u32 width = params.width; | ||
| 792 | const u32 height = params.height; | ||
| 793 | const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1); | ||
| 794 | ImageCopy(surface, new_surface, copy_params); | ||
| 795 | } | ||
| 796 | for (const auto& surface : overlaps) { | ||
| 797 | Unregister(surface); | ||
| 798 | } | ||
| 799 | new_surface->MarkAsModified(modified, Tick()); | ||
| 800 | Register(new_surface); | ||
| 801 | |||
| 802 | TView view = new_surface->GetMainView(); | ||
| 803 | return std::make_pair(std::move(new_surface), std::move(view)); | ||
| 799 | } | 804 | } |
| 800 | 805 | ||
| 801 | /** | 806 | /** |
| @@ -873,7 +878,7 @@ private: | |||
| 873 | } | 878 | } |
| 874 | } | 879 | } |
| 875 | 880 | ||
| 876 | // Check if it's a 3D texture | 881 | // Manage 3D textures |
| 877 | if (params.block_depth > 0) { | 882 | if (params.block_depth > 0) { |
| 878 | auto surface = | 883 | auto surface = |
| 879 | Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents); | 884 | Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents); |