summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-05-08 17:45:59 -0400
committerGravatar ReinUsesLisp2019-06-20 21:36:12 -0300
commit4e2071b6d9b414fa0152deb5e9d55674d636afe4 (patch)
treede07e334d6d345852d289903be961f494b70b2a1 /src
parenttexture_cache: Implement guest flushing (diff)
downloadyuzu-4e2071b6d9b414fa0152deb5e9d55674d636afe4.tar.gz
yuzu-4e2071b6d9b414fa0152deb5e9d55674d636afe4.tar.xz
yuzu-4e2071b6d9b414fa0152deb5e9d55674d636afe4.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h7
-rw-r--r--src/video_core/texture_cache/surface_base.h17
-rw-r--r--src/video_core/texture_cache/texture_cache.h26
4 files changed, 51 insertions, 14 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 63ee83391..3baf1522d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -461,15 +461,15 @@ void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading,
461} 461}
462 462
463std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( 463std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
464 OpenGLState& current_state, bool using_color_fb, bool using_depth_fb, bool preserve_contents, 464 OpenGLState& current_state, bool must_reconfigure, bool using_color_fb, bool using_depth_fb,
465 std::optional<std::size_t> single_color_target) { 465 bool preserve_contents, std::optional<std::size_t> single_color_target) {
466 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 466 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
467 auto& gpu = system.GPU().Maxwell3D(); 467 auto& gpu = system.GPU().Maxwell3D();
468 const auto& regs = gpu.regs; 468 const auto& regs = gpu.regs;
469 469
470 const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents, 470 const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents,
471 single_color_target}; 471 single_color_target};
472 if (fb_config_state == current_framebuffer_config_state && 472 if (!must_reconfigure && fb_config_state == current_framebuffer_config_state &&
473 gpu.dirty_flags.color_buffer.none() && !gpu.dirty_flags.zeta_buffer) { 473 gpu.dirty_flags.color_buffer.none() && !gpu.dirty_flags.zeta_buffer) {
474 // Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or 474 // Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or
475 // single color targets). This is done because the guest registers may not change but the 475 // single color targets). This is done because the guest registers may not change but the
@@ -622,8 +622,9 @@ void RasterizerOpenGL::Clear() {
622 return; 622 return;
623 } 623 }
624 624
625 const auto [clear_depth, clear_stencil] = ConfigureFramebuffers( 625 const auto [clear_depth, clear_stencil] =
626 clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value()); 626 ConfigureFramebuffers(clear_state, false, use_color, use_depth || use_stencil, false,
627 regs.clear_buffers.RT.Value());
627 if (regs.clear_flags.scissor) { 628 if (regs.clear_flags.scissor) {
628 SyncScissorTest(clear_state); 629 SyncScissorTest(clear_state);
629 } 630 }
@@ -705,6 +706,10 @@ void RasterizerOpenGL::DrawArrays() {
705 DrawParameters params = SetupDraw(); 706 DrawParameters params = SetupDraw();
706 SetupShaders(params.primitive_mode); 707 SetupShaders(params.primitive_mode);
707 708
709 if (texture_cache.ConsumeReconfigurationFlag()) {
710 ConfigureFramebuffers(state, true);
711 }
712
708 buffer_cache.Unmap(); 713 buffer_cache.Unmap();
709 714
710 shader_program_manager->ApplyTo(state); 715 shader_program_manager->ApplyTo(state);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index d872e5110..970637efa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -101,6 +101,8 @@ private:
101 101
102 /** 102 /**
103 * Configures the color and depth framebuffer states. 103 * Configures the color and depth framebuffer states.
104 * @param must_reconfigure If true, tells the framebuffer to skip the cache and reconfigure
105 * again. Used by the texture cache to solve texception conflicts
104 * @param use_color_fb If true, configure color framebuffers. 106 * @param use_color_fb If true, configure color framebuffers.
105 * @param using_depth_fb If true, configure the depth/stencil framebuffer. 107 * @param using_depth_fb If true, configure the depth/stencil framebuffer.
106 * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. 108 * @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
@@ -109,8 +111,9 @@ private:
109 * (requires using_depth_fb to be true) 111 * (requires using_depth_fb to be true)
110 */ 112 */
111 std::pair<bool, bool> ConfigureFramebuffers( 113 std::pair<bool, bool> ConfigureFramebuffers(
112 OpenGLState& current_state, bool use_color_fb = true, bool using_depth_fb = true, 114 OpenGLState& current_state, bool must_reconfigure = false, bool use_color_fb = true,
113 bool preserve_contents = true, std::optional<std::size_t> single_color_target = {}); 115 bool using_depth_fb = true, bool preserve_contents = true,
116 std::optional<std::size_t> single_color_target = {});
114 117
115 /// Configures the current constbuffers to use for the draw command. 118 /// Configures the current constbuffers to use for the draw command.
116 void SetupDrawConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, 119 void SetupDrawConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
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:
55 return (cache_addr < end) && (cache_addr_end > start); 55 return (cache_addr < end) && (cache_addr_end > start);
56 } 56 }
57 57
58 bool IsInside(const GPUVAddr other_start, const GPUVAddr other_end) {
59 const GPUVAddr gpu_addr_end = gpu_addr + guest_memory_size;
60 return (gpu_addr <= other_start && other_end <= gpu_addr_end);
61 }
62
58 // Use only when recycling a surface 63 // Use only when recycling a surface
59 void SetGpuAddr(const GPUVAddr new_addr) { 64 void SetGpuAddr(const GPUVAddr new_addr) {
60 gpu_addr = new_addr; 65 gpu_addr = new_addr;
@@ -105,6 +110,12 @@ public:
105 return params.target == target; 110 return params.target == target;
106 } 111 }
107 112
113 bool MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const {
114 return std::tie(gpu_addr, params.target, params.num_levels) ==
115 std::tie(other_gpu_addr, rhs.target, rhs.num_levels) &&
116 params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
117 }
118
108 bool MatchesTopology(const SurfaceParams& rhs) const { 119 bool MatchesTopology(const SurfaceParams& rhs) const {
109 const u32 src_bpp{params.GetBytesPerPixel()}; 120 const u32 src_bpp{params.GetBytesPerPixel()};
110 const u32 dst_bpp{rhs.GetBytesPerPixel()}; 121 const u32 dst_bpp{rhs.GetBytesPerPixel()};
@@ -121,9 +132,9 @@ public:
121 } 132 }
122 // Tiled surface 133 // Tiled surface
123 if (std::tie(params.height, params.depth, params.block_width, params.block_height, 134 if (std::tie(params.height, params.depth, params.block_width, params.block_height,
124 params.block_depth, params.tile_width_spacing) == 135 params.block_depth, params.tile_width_spacing, params.num_levels) ==
125 std::tie(rhs.height, rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth, 136 std::tie(rhs.height, rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth,
126 rhs.tile_width_spacing)) { 137 rhs.tile_width_spacing, rhs.num_levels)) {
127 if (params.width == rhs.width) { 138 if (params.width == rhs.width) {
128 return MatchStructureResult::FullMatch; 139 return MatchStructureResult::FullMatch;
129 } 140 }
@@ -259,7 +270,7 @@ public:
259 270
260 std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) { 271 std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) {
261 if (view_addr < gpu_addr || params.target == SurfaceTarget::Texture3D || 272 if (view_addr < gpu_addr || params.target == SurfaceTarget::Texture3D ||
262 view_params.target == SurfaceTarget::Texture3D) { 273 params.num_levels == 1 || view_params.target == SurfaceTarget::Texture3D) {
263 return {}; 274 return {};
264 } 275 }
265 const auto layer_mipmap{GetLayerMipmap(view_addr)}; 276 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:
120 return {}; 120 return {};
121 } 121 }
122 122
123 if (regs.color_mask[index].raw == 0) {
124 return {};
125 }
126
123 auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), 127 auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
124 preserve_contents); 128 preserve_contents);
125 if (render_targets[index].target) 129 if (render_targets[index].target)
@@ -183,6 +187,12 @@ public:
183 return ++ticks; 187 return ++ticks;
184 } 188 }
185 189
190 bool ConsumeReconfigurationFlag() {
191 const bool result = force_reconfiguration;
192 force_reconfiguration = false;
193 return result;
194 }
195
186protected: 196protected:
187 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 197 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
188 : system{system}, rasterizer{rasterizer} { 198 : system{system}, rasterizer{rasterizer} {
@@ -219,9 +229,10 @@ protected:
219 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); 229 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
220 } 230 }
221 231
222 void Unregister(TSurface surface) { 232 void Unregister(TSurface surface, const bool force_unregister = false) {
223 if (surface->IsProtected()) 233 if (surface->IsProtected() && !force_unregister) {
224 return; 234 return;
235 }
225 const GPUVAddr gpu_addr = surface->GetGpuAddr(); 236 const GPUVAddr gpu_addr = surface->GetGpuAddr();
226 const CacheAddr cache_ptr = surface->GetCacheAddr(); 237 const CacheAddr cache_ptr = surface->GetCacheAddr();
227 const std::size_t size = surface->GetSizeInBytes(); 238 const std::size_t size = surface->GetSizeInBytes();
@@ -365,8 +376,10 @@ private:
365 std::min(src_params.height, dst_height), 1); 376 std::min(src_params.height, dst_height), 1);
366 ImageCopy(surface, new_surface, copy_params); 377 ImageCopy(surface, new_surface, copy_params);
367 } 378 }
379 force_reconfiguration = false;
368 for (auto surface : overlaps) { 380 for (auto surface : overlaps) {
369 Unregister(surface); 381 force_reconfiguration |= surface->IsProtected();
382 Unregister(surface, true);
370 } 383 }
371 Register(new_surface); 384 Register(new_surface);
372 return {{new_surface, new_surface->GetMainView()}}; 385 return {{new_surface, new_surface->GetMainView()}};
@@ -379,6 +392,7 @@ private:
379 const auto cache_addr{ToCacheAddr(host_ptr)}; 392 const auto cache_addr{ToCacheAddr(host_ptr)};
380 const std::size_t candidate_size = params.GetGuestSizeInBytes(); 393 const std::size_t candidate_size = params.GetGuestSizeInBytes();
381 auto overlaps{GetSurfacesInRegion(cache_addr, candidate_size)}; 394 auto overlaps{GetSurfacesInRegion(cache_addr, candidate_size)};
395
382 if (overlaps.empty()) { 396 if (overlaps.empty()) {
383 return InitializeSurface(gpu_addr, params, preserve_contents); 397 return InitializeSurface(gpu_addr, params, preserve_contents);
384 } 398 }
@@ -403,7 +417,7 @@ private:
403 return RebuildSurface(current_surface, params); 417 return RebuildSurface(current_surface, params);
404 } 418 }
405 } 419 }
406 if (current_surface->GetSizeInBytes() <= candidate_size) { 420 if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) {
407 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, 421 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
408 false); 422 false);
409 } 423 }
@@ -530,6 +544,10 @@ private:
530 544
531 u64 ticks{}; 545 u64 ticks{};
532 546
547 // Sometimes Setup Textures can hit a surface that's on the render target, when this happens
548 // we force a reconfiguration of the frame buffer after setup.
549 bool force_reconfiguration;
550
533 // The internal Cache is different for the Texture Cache. It's based on buckets 551 // The internal Cache is different for the Texture Cache. It's based on buckets
534 // of 1MB. This fits better for the purpose of this cache as textures are normaly 552 // of 1MB. This fits better for the purpose of this cache as textures are normaly
535 // large in size. 553 // large in size.