diff options
| -rw-r--r-- | src/video_core/texture_cache/surface_params.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/texture_cache/surface_params.h | 8 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 115 |
3 files changed, 101 insertions, 32 deletions
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 858e17e08..a4f1edd9a 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp | |||
| @@ -246,6 +246,16 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( | |||
| 246 | return params; | 246 | return params; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | VideoCore::Surface::SurfaceTarget SurfaceParams::ExpectedTarget( | ||
| 250 | const VideoCommon::Shader::Sampler& entry) { | ||
| 251 | return TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray()); | ||
| 252 | } | ||
| 253 | |||
| 254 | VideoCore::Surface::SurfaceTarget SurfaceParams::ExpectedTarget( | ||
| 255 | const VideoCommon::Shader::Image& entry) { | ||
| 256 | return ImageTypeToSurfaceTarget(entry.GetType()); | ||
| 257 | } | ||
| 258 | |||
| 249 | bool SurfaceParams::IsLayered() const { | 259 | bool SurfaceParams::IsLayered() const { |
| 250 | switch (target) { | 260 | switch (target) { |
| 251 | case SurfaceTarget::Texture1DArray: | 261 | case SurfaceTarget::Texture1DArray: |
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 709aa0dc2..129817ad3 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h | |||
| @@ -45,6 +45,14 @@ public: | |||
| 45 | static SurfaceParams CreateForFermiCopySurface( | 45 | static SurfaceParams CreateForFermiCopySurface( |
| 46 | const Tegra::Engines::Fermi2D::Regs::Surface& config); | 46 | const Tegra::Engines::Fermi2D::Regs::Surface& config); |
| 47 | 47 | ||
| 48 | /// Obtains the texture target from a shader's sampler entry. | ||
| 49 | static VideoCore::Surface::SurfaceTarget ExpectedTarget( | ||
| 50 | const VideoCommon::Shader::Sampler& entry); | ||
| 51 | |||
| 52 | /// Obtains the texture target from a shader's sampler entry. | ||
| 53 | static VideoCore::Surface::SurfaceTarget ExpectedTarget( | ||
| 54 | const VideoCommon::Shader::Image& entry); | ||
| 55 | |||
| 48 | std::size_t Hash() const { | 56 | std::size_t Hash() const { |
| 49 | return static_cast<std::size_t>( | 57 | return static_cast<std::size_t>( |
| 50 | Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); | 58 | Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 41309ebea..02d2e9136 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -95,10 +95,16 @@ public: | |||
| 95 | std::lock_guard lock{mutex}; | 95 | std::lock_guard lock{mutex}; |
| 96 | const auto gpu_addr{tic.Address()}; | 96 | const auto gpu_addr{tic.Address()}; |
| 97 | if (!gpu_addr) { | 97 | if (!gpu_addr) { |
| 98 | return {}; | 98 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); |
| 99 | } | ||
| 100 | |||
| 101 | const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; | ||
| 102 | const auto cache_addr{ToCacheAddr(host_ptr)}; | ||
| 103 | if (!cache_addr) { | ||
| 104 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); | ||
| 99 | } | 105 | } |
| 100 | const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)}; | 106 | const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)}; |
| 101 | const auto [surface, view] = GetSurface(gpu_addr, params, true, false); | 107 | const auto [surface, view] = GetSurface(gpu_addr, cache_addr, params, true, false); |
| 102 | if (guard_samplers) { | 108 | if (guard_samplers) { |
| 103 | sampled_textures.push_back(surface); | 109 | sampled_textures.push_back(surface); |
| 104 | } | 110 | } |
| @@ -110,10 +116,15 @@ public: | |||
| 110 | std::lock_guard lock{mutex}; | 116 | std::lock_guard lock{mutex}; |
| 111 | const auto gpu_addr{tic.Address()}; | 117 | const auto gpu_addr{tic.Address()}; |
| 112 | if (!gpu_addr) { | 118 | if (!gpu_addr) { |
| 113 | return {}; | 119 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); |
| 120 | } | ||
| 121 | const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; | ||
| 122 | const auto cache_addr{ToCacheAddr(host_ptr)}; | ||
| 123 | if (!cache_addr) { | ||
| 124 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); | ||
| 114 | } | 125 | } |
| 115 | const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)}; | 126 | const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)}; |
| 116 | const auto [surface, view] = GetSurface(gpu_addr, params, true, false); | 127 | const auto [surface, view] = GetSurface(gpu_addr, cache_addr, params, true, false); |
| 117 | if (guard_samplers) { | 128 | if (guard_samplers) { |
| 118 | sampled_textures.push_back(surface); | 129 | sampled_textures.push_back(surface); |
| 119 | } | 130 | } |
| @@ -143,11 +154,17 @@ public: | |||
| 143 | SetEmptyDepthBuffer(); | 154 | SetEmptyDepthBuffer(); |
| 144 | return {}; | 155 | return {}; |
| 145 | } | 156 | } |
| 157 | const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; | ||
| 158 | const auto cache_addr{ToCacheAddr(host_ptr)}; | ||
| 159 | if (!cache_addr) { | ||
| 160 | SetEmptyDepthBuffer(); | ||
| 161 | return {}; | ||
| 162 | } | ||
| 146 | const auto depth_params{SurfaceParams::CreateForDepthBuffer( | 163 | const auto depth_params{SurfaceParams::CreateForDepthBuffer( |
| 147 | system, regs.zeta_width, regs.zeta_height, regs.zeta.format, | 164 | system, regs.zeta_width, regs.zeta_height, regs.zeta.format, |
| 148 | regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, | 165 | regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, |
| 149 | regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; | 166 | regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; |
| 150 | auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents, true); | 167 | auto surface_view = GetSurface(gpu_addr, cache_addr, depth_params, preserve_contents, true); |
| 151 | if (depth_buffer.target) | 168 | if (depth_buffer.target) |
| 152 | depth_buffer.target->MarkAsRenderTarget(false, NO_RT); | 169 | depth_buffer.target->MarkAsRenderTarget(false, NO_RT); |
| 153 | depth_buffer.target = surface_view.first; | 170 | depth_buffer.target = surface_view.first; |
| @@ -180,8 +197,16 @@ public: | |||
| 180 | return {}; | 197 | return {}; |
| 181 | } | 198 | } |
| 182 | 199 | ||
| 183 | auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), | 200 | const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; |
| 184 | preserve_contents, true); | 201 | const auto cache_addr{ToCacheAddr(host_ptr)}; |
| 202 | if (!cache_addr) { | ||
| 203 | SetEmptyColorBuffer(index); | ||
| 204 | return {}; | ||
| 205 | } | ||
| 206 | |||
| 207 | auto surface_view = | ||
| 208 | GetSurface(gpu_addr, cache_addr, SurfaceParams::CreateForFramebuffer(system, index), | ||
| 209 | preserve_contents, true); | ||
| 185 | if (render_targets[index].target) | 210 | if (render_targets[index].target) |
| 186 | render_targets[index].target->MarkAsRenderTarget(false, NO_RT); | 211 | render_targets[index].target->MarkAsRenderTarget(false, NO_RT); |
| 187 | render_targets[index].target = surface_view.first; | 212 | render_targets[index].target = surface_view.first; |
| @@ -230,8 +255,14 @@ public: | |||
| 230 | const GPUVAddr src_gpu_addr = src_config.Address(); | 255 | const GPUVAddr src_gpu_addr = src_config.Address(); |
| 231 | const GPUVAddr dst_gpu_addr = dst_config.Address(); | 256 | const GPUVAddr dst_gpu_addr = dst_config.Address(); |
| 232 | DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); | 257 | DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); |
| 233 | std::pair<TSurface, TView> dst_surface = GetSurface(dst_gpu_addr, dst_params, true, false); | 258 | const auto dst_host_ptr{system.GPU().MemoryManager().GetPointer(dst_gpu_addr)}; |
| 234 | std::pair<TSurface, TView> src_surface = GetSurface(src_gpu_addr, src_params, true, false); | 259 | const auto dst_cache_addr{ToCacheAddr(dst_host_ptr)}; |
| 260 | const auto src_host_ptr{system.GPU().MemoryManager().GetPointer(src_gpu_addr)}; | ||
| 261 | const auto src_cache_addr{ToCacheAddr(src_host_ptr)}; | ||
| 262 | std::pair<TSurface, TView> dst_surface = | ||
| 263 | GetSurface(dst_gpu_addr, dst_cache_addr, dst_params, true, false); | ||
| 264 | std::pair<TSurface, TView> src_surface = | ||
| 265 | GetSurface(src_gpu_addr, src_cache_addr, src_params, true, false); | ||
| 235 | ImageBlit(src_surface.second, dst_surface.second, copy_config); | 266 | ImageBlit(src_surface.second, dst_surface.second, copy_config); |
| 236 | dst_surface.first->MarkAsModified(true, Tick()); | 267 | dst_surface.first->MarkAsModified(true, Tick()); |
| 237 | } | 268 | } |
| @@ -347,13 +378,6 @@ protected: | |||
| 347 | return new_surface; | 378 | return new_surface; |
| 348 | } | 379 | } |
| 349 | 380 | ||
| 350 | std::pair<TSurface, TView> GetFermiSurface( | ||
| 351 | const Tegra::Engines::Fermi2D::Regs::Surface& config) { | ||
| 352 | SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config); | ||
| 353 | const GPUVAddr gpu_addr = config.Address(); | ||
| 354 | return GetSurface(gpu_addr, params, true, false); | ||
| 355 | } | ||
| 356 | |||
| 357 | Core::System& system; | 381 | Core::System& system; |
| 358 | 382 | ||
| 359 | private: | 383 | private: |
| @@ -614,22 +638,9 @@ private: | |||
| 614 | * left blank. | 638 | * left blank. |
| 615 | * @param is_render Whether or not the surface is a render target. | 639 | * @param is_render Whether or not the surface is a render target. |
| 616 | **/ | 640 | **/ |
| 617 | std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, | 641 | std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const CacheAddr cache_addr, |
| 618 | bool preserve_contents, bool is_render) { | 642 | const SurfaceParams& params, bool preserve_contents, |
| 619 | const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; | 643 | bool is_render) { |
| 620 | const auto cache_addr{ToCacheAddr(host_ptr)}; | ||
| 621 | |||
| 622 | // Step 0: guarantee a valid surface | ||
| 623 | if (!cache_addr) { | ||
| 624 | // Return a null surface if it's invalid | ||
| 625 | SurfaceParams new_params = params; | ||
| 626 | new_params.width = 1; | ||
| 627 | new_params.height = 1; | ||
| 628 | new_params.depth = 1; | ||
| 629 | new_params.block_height = 0; | ||
| 630 | new_params.block_depth = 0; | ||
| 631 | return InitializeSurface(gpu_addr, new_params, false); | ||
| 632 | } | ||
| 633 | 644 | ||
| 634 | // Step 1 | 645 | // Step 1 |
| 635 | // Check Level 1 Cache for a fast structural match. If candidate surface | 646 | // Check Level 1 Cache for a fast structural match. If candidate surface |
| @@ -794,6 +805,41 @@ private: | |||
| 794 | } | 805 | } |
| 795 | 806 | ||
| 796 | /** | 807 | /** |
| 808 | * Gets a null surface based on a target texture. | ||
| 809 | * @param target The target of the null surface. | ||
| 810 | */ | ||
| 811 | TView GetNullSurface(SurfaceTarget target) { | ||
| 812 | const u32 i_target = static_cast<u32>(target); | ||
| 813 | if (const auto it = invalid_cache.find(i_target); it != invalid_cache.end()) { | ||
| 814 | return it->second->GetMainView(); | ||
| 815 | } | ||
| 816 | SurfaceParams params{}; | ||
| 817 | params.target = target; | ||
| 818 | params.is_tiled = false; | ||
| 819 | params.srgb_conversion = false; | ||
| 820 | params.is_layered = false; | ||
| 821 | params.block_width = 0; | ||
| 822 | params.block_height = 0; | ||
| 823 | params.block_depth = 0; | ||
| 824 | params.tile_width_spacing = 1; | ||
| 825 | params.width = 1; | ||
| 826 | params.height = 1; | ||
| 827 | params.depth = 1; | ||
| 828 | params.pitch = 4; | ||
| 829 | params.num_levels = 1; | ||
| 830 | params.emulated_levels = 1; | ||
| 831 | params.pixel_format = VideoCore::Surface::PixelFormat::RGBA16F; | ||
| 832 | params.type = VideoCore::Surface::SurfaceType::ColorTexture; | ||
| 833 | auto surface = CreateSurface(0ULL, params); | ||
| 834 | invalid_memory.clear(); | ||
| 835 | invalid_memory.resize(surface->GetHostSizeInBytes(), 0U); | ||
| 836 | surface->UploadTexture(invalid_memory); | ||
| 837 | surface->MarkAsModified(false, Tick()); | ||
| 838 | invalid_cache.emplace(i_target, surface); | ||
| 839 | return surface->GetMainView(); | ||
| 840 | } | ||
| 841 | |||
| 842 | /** | ||
| 797 | * Gets the a source and destination starting address and parameters, | 843 | * Gets the a source and destination starting address and parameters, |
| 798 | * and tries to deduce if they are supposed to be depth textures. If so, their | 844 | * and tries to deduce if they are supposed to be depth textures. If so, their |
| 799 | * parameters are modified and fixed into so. | 845 | * parameters are modified and fixed into so. |
| @@ -991,6 +1037,11 @@ private: | |||
| 991 | 1037 | ||
| 992 | std::vector<TSurface> sampled_textures; | 1038 | std::vector<TSurface> sampled_textures; |
| 993 | 1039 | ||
| 1040 | /// This cache stores null surfaces in order to be used as a placeholder | ||
| 1041 | /// for invalid texture calls. | ||
| 1042 | std::unordered_map<u32, TSurface> invalid_cache; | ||
| 1043 | std::vector<u8> invalid_memory; | ||
| 1044 | |||
| 994 | StagingCache staging_cache; | 1045 | StagingCache staging_cache; |
| 995 | std::recursive_mutex mutex; | 1046 | std::recursive_mutex mutex; |
| 996 | }; | 1047 | }; |