summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-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,
}
std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
- OpenGLState& current_state, bool using_color_fb, bool using_depth_fb, bool preserve_contents,
- std::optional<std::size_t> single_color_target) {
+ OpenGLState& current_state, bool must_reconfigure, bool using_color_fb, bool using_depth_fb,
+ bool preserve_contents, std::optional<std::size_t> single_color_target) {
MICROPROFILE_SCOPE(OpenGL_Framebuffer);
auto& gpu = system.GPU().Maxwell3D();
const auto& regs = gpu.regs;
const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents,
single_color_target};
- if (fb_config_state == current_framebuffer_config_state &&
+ if (!must_reconfigure && fb_config_state == current_framebuffer_config_state &&
gpu.dirty_flags.color_buffer.none() && !gpu.dirty_flags.zeta_buffer) {
// Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or
// single color targets). This is done because the guest registers may not change but the
@@ -622,8 +622,9 @@ void RasterizerOpenGL::Clear() {
return;
}
- const auto [clear_depth, clear_stencil] = ConfigureFramebuffers(
- clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value());
+ const auto [clear_depth, clear_stencil] =
+ ConfigureFramebuffers(clear_state, false, use_color, use_depth || use_stencil, false,
+ regs.clear_buffers.RT.Value());
if (regs.clear_flags.scissor) {
SyncScissorTest(clear_state);
}
@@ -705,6 +706,10 @@ void RasterizerOpenGL::DrawArrays() {
DrawParameters params = SetupDraw();
SetupShaders(params.primitive_mode);
+ if (texture_cache.ConsumeReconfigurationFlag()) {
+ ConfigureFramebuffers(state, true);
+ }
+
buffer_cache.Unmap();
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:
/**
* Configures the color and depth framebuffer states.
+ * @param must_reconfigure If true, tells the framebuffer to skip the cache and reconfigure
+ * again. Used by the texture cache to solve texception conflicts
* @param use_color_fb If true, configure color framebuffers.
* @param using_depth_fb If true, configure the depth/stencil framebuffer.
* @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
@@ -109,8 +111,9 @@ private:
* (requires using_depth_fb to be true)
*/
std::pair<bool, bool> ConfigureFramebuffers(
- OpenGLState& current_state, bool use_color_fb = true, bool using_depth_fb = true,
- bool preserve_contents = true, std::optional<std::size_t> single_color_target = {});
+ OpenGLState& current_state, bool must_reconfigure = false, bool use_color_fb = true,
+ bool using_depth_fb = true, bool preserve_contents = true,
+ std::optional<std::size_t> single_color_target = {});
/// Configures the current constbuffers to use for the draw command.
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:
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<TView> 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.