From 893200161020f251dd327a5ac42c55509414dc3b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:51:31 -0400 Subject: rasterizer_cache_gl: Implement Partial Reinterpretation of Surfaces. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'src/video_core/renderer_opengl/gl_rasterizer_cache.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index fe81ff227..367dbd041 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 -- cgit v1.2.3