rasterizer_cache_gl: Implement Partial Reinterpretation of Surfaces.
This commit is contained in:
		
							parent
							
								
									44ea2810e4
								
							
						
					
					
						commit
						8932001610
					
				| @ -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
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Fernando Sahmkow
						Fernando Sahmkow