rasterizer_cache_gl: Implement Partial Reinterpretation of Surfaces.
This commit is contained in:
		
				
					committed by
					
						
						FernandoS27
					
				
			
			
				
	
			
			
			
						parent
						
							44ea2810e4
						
					
				
				
					commit
					8932001610
				
			@@ -1304,9 +1304,98 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params
 | 
				
			|||||||
    return {};
 | 
					    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) {
 | 
					void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) {
 | 
				
			||||||
    if (triggering_surface == nullptr)
 | 
					    if (triggering_surface == nullptr)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					    Surface intersect = CollideOnReinterpretedSurface(triggering_surface->GetAddr());
 | 
				
			||||||
 | 
					    if (intersect != nullptr) {
 | 
				
			||||||
 | 
					        PartialReinterpretSurface(triggering_surface, intersect);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace OpenGL
 | 
					} // namespace OpenGL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,10 +141,18 @@ struct SurfaceParams {
 | 
				
			|||||||
        return offset;
 | 
					        return offset;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t GetMipmapSingleSize(u32 mip_level) const {
 | 
				
			||||||
 | 
					        return InnerMipmapMemorySize(mip_level, false, is_layered);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u32 MipWidth(u32 mip_level) const {
 | 
					    u32 MipWidth(u32 mip_level) const {
 | 
				
			||||||
        return std::max(1U, width >> mip_level);
 | 
					        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 {
 | 
					    u32 MipHeight(u32 mip_level) const {
 | 
				
			||||||
        return std::max(1U, height >> mip_level);
 | 
					        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
 | 
					    /// When a render target is changed, this method is called with the previous render target
 | 
				
			||||||
    void NotifyFrameBufferChange(Surface triggering_surface);
 | 
					    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
 | 
					    /// 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 AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
 | 
				
			||||||
    void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
 | 
					    void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user