From 45b6d2d349b35bd056dcb95a252da27a57c04c5f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:24:04 -0400 Subject: [PATCH 01/11] rasterizer_cache: Expose FlushObject to Child classes and allow redefining of Register and Unregister --- src/video_core/rasterizer_cache.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index bcf0c15a44..b239dff842 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -104,7 +104,7 @@ protected: } /// Register an object into the cache - void Register(const T& object) { + virtual void Register(const T& object) { object->SetIsRegistered(true); interval_cache.add({GetInterval(object), ObjectSet{object}}); map_cache.insert({object->GetAddr(), object}); @@ -112,7 +112,7 @@ protected: } /// Unregisters an object from the cache - void Unregister(const T& object) { + virtual void Unregister(const T& object) { object->SetIsRegistered(false); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit @@ -129,6 +129,15 @@ protected: return ++modified_ticks; } + /// Flushes the specified object, updating appropriate cache state as needed + void FlushObject(const T& object) { + if (!object->IsDirty()) { + return; + } + object->Flush(); + object->MarkAsModified(false, *this); + } + private: /// Returns a list of cached objects from the specified memory region, ordered by access time std::vector GetSortedObjectsFromRegion(VAddr addr, u64 size) { @@ -154,15 +163,6 @@ private: return objects; } - /// Flushes the specified object, updating appropriate cache state as needed - void FlushObject(const T& object) { - if (!object->IsDirty()) { - return; - } - object->Flush(); - object->MarkAsModified(false, *this); - } - using ObjectSet = std::set; using ObjectCache = std::unordered_map; using IntervalCache = boost::icl::interval_map; From d583fc1e97a78dc6a893c332b3537218ddae194a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:31:35 -0400 Subject: [PATCH 02/11] rasterizer_cache_gl: Notify on framebuffer change --- .../renderer_opengl/gl_rasterizer_cache.cpp | 20 ++++++++++++++++--- .../renderer_opengl/gl_rasterizer_cache.h | 7 ++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 81b6099f9a..2d2bbd6acb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -968,18 +968,27 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre gpu.dirty_flags.color_buffer.reset(index); ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); + auto Notify = [&]() { + if (last_color_buffers[index] != current_color_buffers[index]) { + NotifyFrameBufferChange(current_color_buffers[index]); + } + last_color_buffers[index] = current_color_buffers[index]; + }; if (index >= regs.rt_control.count) { - return last_color_buffers[index] = {}; + Notify(); + return current_color_buffers[index] = {}; } if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { - return last_color_buffers[index] = {}; + Notify(); + return current_color_buffers[index] = {}; } const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)}; - return last_color_buffers[index] = GetSurface(color_params, preserve_contents); + Notify(); + return current_color_buffers[index] = GetSurface(color_params, preserve_contents); } void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { @@ -1290,4 +1299,9 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params return {}; } +void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { + if (triggering_surface == nullptr) + return; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 838554c357..cc27fefb53 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -34,6 +34,7 @@ using SurfaceTarget = VideoCore::Surface::SurfaceTarget; using SurfaceType = VideoCore::Surface::SurfaceType; using PixelFormat = VideoCore::Surface::PixelFormat; using ComponentType = VideoCore::Surface::ComponentType; +using Maxwell = Tegra::Engines::Maxwell3D::Regs; struct SurfaceParams { enum class SurfaceClass { @@ -449,6 +450,9 @@ private: /// Tries to get a reserved surface for the specified parameters Surface TryGetReservedSurface(const SurfaceParams& params); + /// When a render target is changed, this method is called with the previous render target + void NotifyFrameBufferChange(Surface triggering_surface); + /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); @@ -469,7 +473,8 @@ private: /// using the new format. OGLBuffer copy_pbo; - std::array last_color_buffers; + std::array last_color_buffers; + std::array current_color_buffers; Surface last_depth_buffer; }; From 44ea2810e422c6b53e56b26fc8aa918c48b80c8b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:40:32 -0400 Subject: [PATCH 03/11] rasterizer_cache: mark reinterpreted surfaces and add ability to reload marked surfaces on next use. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 5 ++ .../renderer_opengl/gl_rasterizer_cache.h | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 2d2bbd6acb..fe81ff2279 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1007,6 +1007,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres if (surface) { if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { // Use the cached surface as-is + if (surface->MustReload()) + LoadSurface(surface); return surface; } else if (preserve_contents) { // If surface parameters changed and we care about keeping the previous data, recreate @@ -1014,6 +1016,9 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres Surface new_surface{RecreateSurface(surface, params)}; Unregister(surface); Register(new_surface); + if (new_surface->IsUploaded()) { + RegisterReinterpretSurface(new_surface); + } return new_surface; } else { // Delete the old surface before creating a new one to prevent collisions. diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index cc27fefb53..0b4d720e28 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -347,6 +347,10 @@ public: return cached_size_in_bytes; } + std::size_t GetMemorySize() const { + return memory_size; + } + void Flush() override { FlushGLBuffer(); } @@ -396,6 +400,26 @@ public: Tegra::Texture::SwizzleSource swizzle_z, Tegra::Texture::SwizzleSource swizzle_w); + void MarkReinterpreted() { + reinterpreted = true; + } + + bool IsReinterpreted() { + return reinterpreted; + } + + void MarkForReload(bool reload) { + must_reload = reload; + } + + bool MustReload() { + return must_reload; + } + + bool IsUploaded() { + return params.identity == SurfaceParams::SurfaceClass::Uploaded; + } + private: void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); @@ -409,6 +433,9 @@ private: GLenum gl_internal_format{}; std::size_t cached_size_in_bytes{}; std::array swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + std::size_t memory_size; + bool reinterpreted = false; + bool must_reload = false; }; class RasterizerCacheOpenGL final : public RasterizerCache { @@ -469,6 +496,9 @@ private: OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; + bool run_texception_pass = false; + bool texception = false; + /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one /// using the new format. OGLBuffer copy_pbo; @@ -476,6 +506,49 @@ private: std::array last_color_buffers; std::array current_color_buffers; Surface last_depth_buffer; + + using SurfaceIntervalCache = boost::icl::interval_map; + using SurfaceInterval = typename IntervalCache::interval_type; + + static auto GetReinterpretInterval(const Surface& object) { + return SurfaceInterval::right_open(object->GetAddr() + 1, + object->GetAddr() + object->GetMemorySize() - 1); + } + + // Reinterpreted surfaces are very fragil as the game may keep rendering into them. + SurfaceIntervalCache reinterpreted_surfaces; + + void RegisterReinterpretSurface(Surface r_surface) { + auto interval = GetReinterpretInterval(r_surface); + reinterpreted_surfaces.insert({interval, r_surface}); + r_surface->MarkReinterpreted(); + run_texception_pass = true; + } + + Surface CollideOnReinterpretedSurface(VAddr addr) const { + const SurfaceInterval interval{addr}; + for (auto& pair : + boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) { + return pair.second; + } + return nullptr; + } + +protected: + void Register(const Surface& object) { + RasterizerCache::Register(object); + } + + /// Unregisters an object from the cache + void Unregister(const Surface& object) { + const auto& params = object->GetSurfaceParams(); + if (object->IsReinterpreted()) { + auto interval = GetReinterpretInterval(object); + reinterpreted_surfaces.erase(interval); + } + RasterizerCache::Unregister(object); + } + }; } // namespace OpenGL From 893200161020f251dd327a5ac42c55509414dc3b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:51:31 -0400 Subject: [PATCH 04/11] rasterizer_cache_gl: Implement Partial Reinterpretation of Surfaces. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 89 +++++++++++++++++++ .../renderer_opengl/gl_rasterizer_cache.h | 11 +++ 2 files changed, 100 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index fe81ff2279..367dbd0413 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1304,9 +1304,98 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params return {}; } +bool FindBestMipMap(std::size_t memory, const SurfaceParams params, u32 height, u32& mipmap) { + for (u32 i = 0; i < params.max_mip_level; i++) + if (memory == params.GetMipmapSingleSize(i) && params.MipHeight(i) == height) { + mipmap = i; + return true; + } + return false; +} + +bool FindBestLayer(VAddr addr, const SurfaceParams params, u32 mipmap, u32& layer) { + std::size_t size = params.LayerMemorySize(); + VAddr start = params.addr + params.GetMipmapLevelOffset(mipmap); + for (u32 i = 0; i < params.depth; i++) { + if (start == addr) { + layer = i; + return true; + } + start += size; + } + return false; +} + +bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface render_surface, + const Surface blitted_surface) { + const auto dst_params = blitted_surface->GetSurfaceParams(); + const auto src_params = render_surface->GetSurfaceParams(); + u32 level = 0; + std::size_t src_memory_size = src_params.size_in_bytes; + if (FindBestMipMap(src_memory_size, dst_params, src_params.height, level)) { + if (src_params.width == dst_params.MipWidthGobAligned(level) && + src_params.height == dst_params.MipHeight(level) && + src_params.block_height >= dst_params.MipBlockHeight(level)) { + u32 slot = 0; + if (FindBestLayer(render_surface->GetAddr(), dst_params, level, slot)) { + glCopyImageSubData( + render_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0, + 0, blitted_surface->Texture().handle, SurfaceTargetToGL(dst_params.target), + level, 0, 0, slot, dst_params.MipWidth(level), dst_params.MipHeight(level), 1); + blitted_surface->MarkAsModified(true, cache); + return true; + } + } + } + return false; +} + +bool IsReinterpretInvalid(const Surface render_surface, const Surface blitted_surface) { + VAddr bound1 = blitted_surface->GetAddr() + blitted_surface->GetMemorySize(); + VAddr bound2 = render_surface->GetAddr() + render_surface->GetMemorySize(); + if (bound2 > bound1) + return true; + const auto dst_params = blitted_surface->GetSurfaceParams(); + const auto src_params = render_surface->GetSurfaceParams(); + if (dst_params.component_type != src_params.component_type) + return true; + return false; +} + +bool IsReinterpretInvalidSecond(const Surface render_surface, const Surface blitted_surface) { + const auto dst_params = blitted_surface->GetSurfaceParams(); + const auto src_params = render_surface->GetSurfaceParams(); + if (dst_params.height > src_params.height && dst_params.width > src_params.width) + return false; + return true; +} + +bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface, + Surface intersect) { + if (IsReinterpretInvalid(triggering_surface, intersect)) { + Unregister(intersect); + return false; + } + if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) { + if (IsReinterpretInvalidSecond(triggering_surface, intersect)) { + Unregister(intersect); + return false; + } + FlushObject(intersect); + FlushObject(triggering_surface); + intersect->MarkForReload(true); + } + return true; +} + + void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { if (triggering_surface == nullptr) return; + Surface intersect = CollideOnReinterpretedSurface(triggering_surface->GetAddr()); + if (intersect != nullptr) { + PartialReinterpretSurface(triggering_surface, intersect); + } } } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 0b4d720e28..2be056f0a9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -141,10 +141,18 @@ struct SurfaceParams { return offset; } + std::size_t GetMipmapSingleSize(u32 mip_level) const { + return InnerMipmapMemorySize(mip_level, false, is_layered); + } + u32 MipWidth(u32 mip_level) const { return std::max(1U, width >> mip_level); } + u32 MipWidthGobAligned(u32 mip_level) const { + return std::max(64U*8U / GetFormatBpp(), width >> mip_level); + } + u32 MipHeight(u32 mip_level) const { return std::max(1U, height >> mip_level); } @@ -480,6 +488,9 @@ private: /// When a render target is changed, this method is called with the previous render target void NotifyFrameBufferChange(Surface triggering_surface); + // Partialy reinterpret a surface based on a triggering_surface that collides with it. + bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect); + /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); From 5bc82d124cbf26f62cf62c26dc212f556e603547 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 20:06:49 -0400 Subject: [PATCH 05/11] rasterizer_cache_gl: Implement Texception Pass --- .../renderer_opengl/gl_rasterizer.cpp | 7 ++++ .../renderer_opengl/gl_rasterizer_cache.cpp | 39 +++++++++++++++++++ .../renderer_opengl/gl_rasterizer_cache.h | 5 +++ 3 files changed, 51 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index ee04569fa0..1a0a18c3ee 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -575,6 +575,8 @@ std::pair RasterizerOpenGL::ConfigureFramebuffers( SetupCachedFramebuffer(fbkey, current_state); SyncViewport(current_state); + res_cache.SignalPostFramebufferSetup(); + return current_depth_stencil_usage = {static_cast(depth_surface), fbkey.stencil_enable}; } @@ -738,9 +740,13 @@ void RasterizerOpenGL::DrawArrays() { shader_program_manager->ApplyTo(state); state.Apply(); + res_cache.SignalPreDrawCall(); + // Execute draw call params.DispatchDraw(); + res_cache.SignalPostDrawCall(); + // Disable scissor test state.viewports[0].scissor.enabled = false; @@ -1013,6 +1019,7 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture, entry); + res_cache.SignalSurfaceParameter(surface); if (surface != nullptr) { state.texture_units[current_bindpoint].texture = entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 367dbd0413..5e97e2f7af 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1392,10 +1392,49 @@ bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { if (triggering_surface == nullptr) return; + run_texception_pass = false; + if (texception) { + return; + } Surface intersect = CollideOnReinterpretedSurface(triggering_surface->GetAddr()); if (intersect != nullptr) { PartialReinterpretSurface(triggering_surface, intersect); } } +void RasterizerCacheOpenGL::SignalPreDrawCall() { + if (texception) { + glTextureBarrier(); + } +} + +void RasterizerCacheOpenGL::SignalPostDrawCall() { + if (!run_texception_pass) + return; + for (u32 i = 0; i < Maxwell::NumRenderTargets; i++) { + if (current_color_buffers[i] != nullptr) { + Surface intersect = CollideOnReinterpretedSurface(current_color_buffers[i]->GetAddr()); + if (intersect != nullptr) { + PartialReinterpretSurface(current_color_buffers[i], intersect); + texception = true; + } + } + } + if (!texception) + run_texception_pass = false; +} + +void RasterizerCacheOpenGL::SignalPostFramebufferSetup() { + if (!run_texception_pass) + texception = false; +} + +void RasterizerCacheOpenGL::SignalSurfaceParameter(Surface& surface) { + if (surface == nullptr) + return; + if (surface->IsReinterpreted()) { + run_texception_pass = true; + } +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 2be056f0a9..8c3cddf6ac 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -469,6 +469,11 @@ public: const Common::Rectangle& src_rect, const Common::Rectangle& dst_rect); + void SignalPreDrawCall(); + void SignalPostDrawCall(); + void SignalSurfaceParameter(Surface& surface); + void SignalPostFramebufferSetup(); + private: void LoadSurface(const Surface& surface); Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); From e9d84ef22cfea4e5ce72116f03d1b8d357582c58 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 20:33:11 -0400 Subject: [PATCH 06/11] Bug fixes and formatting --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 4 +++- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 5e97e2f7af..66a80730cb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -549,6 +549,8 @@ CachedSurface::CachedSurface(const SurfaceParams& params) // alternatives. This signals a bug on those functions. const auto width = static_cast(params.MipWidth(0)); const auto height = static_cast(params.MipHeight(0)); + memory_size = params.MemorySize(); + reinterpreted = false; const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); gl_internal_format = format_tuple.internal_format; @@ -995,6 +997,7 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { surface->LoadGLBuffer(); surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); surface->MarkAsModified(false, *this); + surface->MarkForReload(false); } Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) { @@ -1388,7 +1391,6 @@ bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface return true; } - void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { if (triggering_surface == nullptr) return; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 8c3cddf6ac..67841d554a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -150,7 +150,7 @@ struct SurfaceParams { } u32 MipWidthGobAligned(u32 mip_level) const { - return std::max(64U*8U / GetFormatBpp(), width >> mip_level); + return Common::AlignUp(std::max(1U, width >> mip_level), 64U * 8U / GetFormatBpp()); } u32 MipHeight(u32 mip_level) const { @@ -564,7 +564,6 @@ protected: } RasterizerCache::Unregister(object); } - }; } // namespace OpenGL From 3558c88442b532642ce077d32bf1ddfdd36bd0c3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 9 Feb 2019 18:42:52 -0400 Subject: [PATCH 07/11] Remove certain optimizations that caused texception to fail in certain scenarios. --- .../renderer_opengl/gl_rasterizer.cpp | 3 --- .../renderer_opengl/gl_rasterizer_cache.cpp | 19 +------------------ .../renderer_opengl/gl_rasterizer_cache.h | 3 --- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1a0a18c3ee..99c3cd67d8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -575,8 +575,6 @@ std::pair RasterizerOpenGL::ConfigureFramebuffers( SetupCachedFramebuffer(fbkey, current_state); SyncViewport(current_state); - res_cache.SignalPostFramebufferSetup(); - return current_depth_stencil_usage = {static_cast(depth_surface), fbkey.stencil_enable}; } @@ -1019,7 +1017,6 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture, entry); - res_cache.SignalSurfaceParameter(surface); if (surface != nullptr) { state.texture_units[current_bindpoint].texture = entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 66a80730cb..09013d6dae 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1394,7 +1394,6 @@ bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { if (triggering_surface == nullptr) return; - run_texception_pass = false; if (texception) { return; } @@ -1408,11 +1407,10 @@ void RasterizerCacheOpenGL::SignalPreDrawCall() { if (texception) { glTextureBarrier(); } + texception = false; } void RasterizerCacheOpenGL::SignalPostDrawCall() { - if (!run_texception_pass) - return; for (u32 i = 0; i < Maxwell::NumRenderTargets; i++) { if (current_color_buffers[i] != nullptr) { Surface intersect = CollideOnReinterpretedSurface(current_color_buffers[i]->GetAddr()); @@ -1422,21 +1420,6 @@ void RasterizerCacheOpenGL::SignalPostDrawCall() { } } } - if (!texception) - run_texception_pass = false; -} - -void RasterizerCacheOpenGL::SignalPostFramebufferSetup() { - if (!run_texception_pass) - texception = false; -} - -void RasterizerCacheOpenGL::SignalSurfaceParameter(Surface& surface) { - if (surface == nullptr) - return; - if (surface->IsReinterpreted()) { - run_texception_pass = true; - } } } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 67841d554a..fd3f9cc72e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -471,8 +471,6 @@ public: void SignalPreDrawCall(); void SignalPostDrawCall(); - void SignalSurfaceParameter(Surface& surface); - void SignalPostFramebufferSetup(); private: void LoadSurface(const Surface& surface); @@ -512,7 +510,6 @@ private: OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; - bool run_texception_pass = false; bool texception = false; /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one From e64fa4d2ea1519d325355711b5247cec6afd7d56 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 9 Feb 2019 19:19:16 -0400 Subject: [PATCH 08/11] Remove NotifyFrameBuffer as we are doing a texception pass every drawcall. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 21 ------------------- .../renderer_opengl/gl_rasterizer_cache.h | 4 ---- 2 files changed, 25 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 09013d6dae..58e6dc8249 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -970,26 +970,17 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre gpu.dirty_flags.color_buffer.reset(index); ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); - auto Notify = [&]() { - if (last_color_buffers[index] != current_color_buffers[index]) { - NotifyFrameBufferChange(current_color_buffers[index]); - } - last_color_buffers[index] = current_color_buffers[index]; - }; if (index >= regs.rt_control.count) { - Notify(); return current_color_buffers[index] = {}; } if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { - Notify(); return current_color_buffers[index] = {}; } const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)}; - Notify(); return current_color_buffers[index] = GetSurface(color_params, preserve_contents); } @@ -1391,18 +1382,6 @@ bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface return true; } -void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) { - if (triggering_surface == nullptr) - return; - if (texception) { - return; - } - Surface intersect = CollideOnReinterpretedSurface(triggering_surface->GetAddr()); - if (intersect != nullptr) { - PartialReinterpretSurface(triggering_surface, intersect); - } -} - void RasterizerCacheOpenGL::SignalPreDrawCall() { if (texception) { glTextureBarrier(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index fd3f9cc72e..bbad719b2d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -488,9 +488,6 @@ private: /// Tries to get a reserved surface for the specified parameters Surface TryGetReservedSurface(const SurfaceParams& params); - /// When a render target is changed, this method is called with the previous render target - void NotifyFrameBufferChange(Surface triggering_surface); - // Partialy reinterpret a surface based on a triggering_surface that collides with it. bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect); @@ -535,7 +532,6 @@ private: auto interval = GetReinterpretInterval(r_surface); reinterpreted_surfaces.insert({interval, r_surface}); r_surface->MarkReinterpreted(); - run_texception_pass = true; } Surface CollideOnReinterpretedSurface(VAddr addr) const { From d6b9b516061b460ea422469557a931932c565ac8 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 13 Feb 2019 15:57:27 -0400 Subject: [PATCH 09/11] Fix linux compile error. --- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index bbad719b2d..ed180a6831 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -518,7 +518,7 @@ private: Surface last_depth_buffer; using SurfaceIntervalCache = boost::icl::interval_map; - using SurfaceInterval = typename IntervalCache::interval_type; + using SurfaceInterval = typename SurfaceIntervalCache::interval_type; static auto GetReinterpretInterval(const Surface& object) { return SurfaceInterval::right_open(object->GetAddr() + 1, From 5a9204dbd7ec302eddb8abed76bda487dbc852a3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 16 Feb 2019 18:32:26 -0400 Subject: [PATCH 10/11] Corrections and redesign. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 85 ++++++++++--------- .../renderer_opengl/gl_rasterizer_cache.h | 17 ++-- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 58e6dc8249..1f84026cd8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include "common/alignment.h" @@ -1000,7 +1001,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres Surface surface{TryGet(params.addr)}; if (surface) { if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { - // Use the cached surface as-is + // Use the cached surface as-is unless it's not synced with memory if (surface->MustReload()) LoadSurface(surface); return surface; @@ -1298,44 +1299,47 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params return {}; } -bool FindBestMipMap(std::size_t memory, const SurfaceParams params, u32 height, u32& mipmap) { - for (u32 i = 0; i < params.max_mip_level; i++) +static std::optional TryFindBestMipMap(std::size_t memory, const SurfaceParams params, + u32 height) { + for (u32 i = 0; i < params.max_mip_level; i++) { if (memory == params.GetMipmapSingleSize(i) && params.MipHeight(i) == height) { - mipmap = i; - return true; + return {i}; } - return false; + } + return {}; } -bool FindBestLayer(VAddr addr, const SurfaceParams params, u32 mipmap, u32& layer) { - std::size_t size = params.LayerMemorySize(); +static std::optional TryFindBestLayer(VAddr addr, const SurfaceParams params, u32 mipmap) { + const std::size_t size = params.LayerMemorySize(); VAddr start = params.addr + params.GetMipmapLevelOffset(mipmap); for (u32 i = 0; i < params.depth; i++) { if (start == addr) { - layer = i; - return true; + return {i}; } start += size; } - return false; + return {}; } -bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface render_surface, - const Surface blitted_surface) { - const auto dst_params = blitted_surface->GetSurfaceParams(); - const auto src_params = render_surface->GetSurfaceParams(); - u32 level = 0; - std::size_t src_memory_size = src_params.size_in_bytes; - if (FindBestMipMap(src_memory_size, dst_params, src_params.height, level)) { - if (src_params.width == dst_params.MipWidthGobAligned(level) && - src_params.height == dst_params.MipHeight(level) && - src_params.block_height >= dst_params.MipBlockHeight(level)) { - u32 slot = 0; - if (FindBestLayer(render_surface->GetAddr(), dst_params, level, slot)) { - glCopyImageSubData( - render_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0, - 0, blitted_surface->Texture().handle, SurfaceTargetToGL(dst_params.target), - level, 0, 0, slot, dst_params.MipWidth(level), dst_params.MipHeight(level), 1); +static bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface render_surface, + const Surface blitted_surface) { + const auto& dst_params = blitted_surface->GetSurfaceParams(); + const auto& src_params = render_surface->GetSurfaceParams(); + const std::size_t src_memory_size = src_params.size_in_bytes; + const std::optional level = + TryFindBestMipMap(src_memory_size, dst_params, src_params.height); + if (level.has_value()) { + if (src_params.width == dst_params.MipWidthGobAligned(*level) && + src_params.height == dst_params.MipHeight(*level) && + src_params.block_height >= dst_params.MipBlockHeight(*level)) { + const std::optional slot = + TryFindBestLayer(render_surface->GetAddr(), dst_params, *level); + if (slot.has_value()) { + glCopyImageSubData(render_surface->Texture().handle, + SurfaceTargetToGL(src_params.target), 0, 0, 0, 0, + blitted_surface->Texture().handle, + SurfaceTargetToGL(dst_params.target), *level, 0, 0, *slot, + dst_params.MipWidth(*level), dst_params.MipHeight(*level), 1); blitted_surface->MarkAsModified(true, cache); return true; } @@ -1344,24 +1348,21 @@ bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface rend return false; } -bool IsReinterpretInvalid(const Surface render_surface, const Surface blitted_surface) { - VAddr bound1 = blitted_surface->GetAddr() + blitted_surface->GetMemorySize(); - VAddr bound2 = render_surface->GetAddr() + render_surface->GetMemorySize(); +static bool IsReinterpretInvalid(const Surface render_surface, const Surface blitted_surface) { + const VAddr bound1 = blitted_surface->GetAddr() + blitted_surface->GetMemorySize(); + const VAddr bound2 = render_surface->GetAddr() + render_surface->GetMemorySize(); if (bound2 > bound1) return true; - const auto dst_params = blitted_surface->GetSurfaceParams(); - const auto src_params = render_surface->GetSurfaceParams(); - if (dst_params.component_type != src_params.component_type) - return true; - return false; + const auto& dst_params = blitted_surface->GetSurfaceParams(); + const auto& src_params = render_surface->GetSurfaceParams(); + return (dst_params.component_type != src_params.component_type); } -bool IsReinterpretInvalidSecond(const Surface render_surface, const Surface blitted_surface) { - const auto dst_params = blitted_surface->GetSurfaceParams(); - const auto src_params = render_surface->GetSurfaceParams(); - if (dst_params.height > src_params.height && dst_params.width > src_params.width) - return false; - return true; +static bool IsReinterpretInvalidSecond(const Surface render_surface, + const Surface blitted_surface) { + const auto& dst_params = blitted_surface->GetSurfaceParams(); + const auto& src_params = render_surface->GetSurfaceParams(); + return (dst_params.height > src_params.height && dst_params.width > src_params.width); } bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface, @@ -1383,7 +1384,7 @@ bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface } void RasterizerCacheOpenGL::SignalPreDrawCall() { - if (texception) { + if (texception && GLAD_GL_ARB_texture_barrier) { glTextureBarrier(); } texception = false; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index ed180a6831..d530d64d47 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -412,7 +412,7 @@ public: reinterpreted = true; } - bool IsReinterpreted() { + bool IsReinterpreted() const { return reinterpreted; } @@ -420,11 +420,11 @@ public: must_reload = reload; } - bool MustReload() { + bool MustReload() const { return must_reload; } - bool IsUploaded() { + bool IsUploaded() const { return params.identity == SurfaceParams::SurfaceClass::Uploaded; } @@ -489,6 +489,7 @@ private: Surface TryGetReservedSurface(const SurfaceParams& params); // Partialy reinterpret a surface based on a triggering_surface that collides with it. + // returns true if the reinterpret was successful, false in case it was not. bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect); /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data @@ -528,10 +529,10 @@ private: // Reinterpreted surfaces are very fragil as the game may keep rendering into them. SurfaceIntervalCache reinterpreted_surfaces; - void RegisterReinterpretSurface(Surface r_surface) { - auto interval = GetReinterpretInterval(r_surface); - reinterpreted_surfaces.insert({interval, r_surface}); - r_surface->MarkReinterpreted(); + void RegisterReinterpretSurface(Surface reinterpret_surface) { + auto interval = GetReinterpretInterval(reinterpret_surface); + reinterpreted_surfaces.insert({interval, reinterpret_surface}); + reinterpret_surface->MarkReinterpreted(); } Surface CollideOnReinterpretedSurface(VAddr addr) const { @@ -543,14 +544,12 @@ private: return nullptr; } -protected: void Register(const Surface& object) { RasterizerCache::Register(object); } /// Unregisters an object from the cache void Unregister(const Surface& object) { - const auto& params = object->GetSurfaceParams(); if (object->IsReinterpreted()) { auto interval = GetReinterpretInterval(object); reinterpreted_surfaces.erase(interval); From 7ea097e5c25737e681ad8ba007e655a7c6bfba31 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 27 Feb 2019 20:36:06 -0400 Subject: [PATCH 11/11] Devirtualize Register/Unregister and use a wrapper instead. --- src/video_core/rasterizer_cache.h | 4 ++-- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 8 ++++---- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 8 ++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index b239dff842..a7bcf26fbc 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -104,7 +104,7 @@ protected: } /// Register an object into the cache - virtual void Register(const T& object) { + void Register(const T& object) { object->SetIsRegistered(true); interval_cache.add({GetInterval(object), ObjectSet{object}}); map_cache.insert({object->GetAddr(), object}); @@ -112,7 +112,7 @@ protected: } /// Unregisters an object from the cache - virtual void Unregister(const T& object) { + void Unregister(const T& object) { object->SetIsRegistered(false); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 1f84026cd8..5fdf1164d2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1009,7 +1009,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres // If surface parameters changed and we care about keeping the previous data, recreate // the surface from the old one Surface new_surface{RecreateSurface(surface, params)}; - Unregister(surface); + UnregisterSurface(surface); Register(new_surface); if (new_surface->IsUploaded()) { RegisterReinterpretSurface(new_surface); @@ -1017,7 +1017,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres return new_surface; } else { // Delete the old surface before creating a new one to prevent collisions. - Unregister(surface); + UnregisterSurface(surface); } } @@ -1368,12 +1368,12 @@ static bool IsReinterpretInvalidSecond(const Surface render_surface, bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface, Surface intersect) { if (IsReinterpretInvalid(triggering_surface, intersect)) { - Unregister(intersect); + UnregisterSurface(intersect); return false; } if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) { if (IsReinterpretInvalidSecond(triggering_surface, intersect)) { - Unregister(intersect); + UnregisterSurface(intersect); return false; } FlushObject(intersect); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index d530d64d47..797bbdc9c2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -544,17 +544,13 @@ private: return nullptr; } - void Register(const Surface& object) { - RasterizerCache::Register(object); - } - /// Unregisters an object from the cache - void Unregister(const Surface& object) { + void UnregisterSurface(const Surface& object) { if (object->IsReinterpreted()) { auto interval = GetReinterpretInterval(object); reinterpreted_surfaces.erase(interval); } - RasterizerCache::Unregister(object); + Unregister(object); } };