@ -652,45 +652,54 @@ private:
* */
std : : optional < std : : pair < TSurface , TView > > TryReconstructSurface ( std : : vector < TSurface > & overlaps ,
const SurfaceParams & params ,
const GPUVAddr gpu_addr ) {
GPUVAddr gpu_addr ) {
if ( params . target = = SurfaceTarget : : Texture3D ) {
return { } ;
return std : : nullopt ;
}
bool modified = false ;
TSurface new_surface = GetUncachedSurface ( gpu_addr , params ) ;
u32 passed_tests = 0 ;
std : : size_t passed_tests = 0 ;
bool modified = false ;
for ( auto & surface : overlaps ) {
const SurfaceParams & src_params = surface - > GetSurfaceParams ( ) ;
if ( src_params . is_layered | | src_params . num_levels > 1 ) {
// We send this cases to recycle as they are more complex to handle
return { } ;
}
const std : : size_t candidate_size = surface - > GetSizeInBytes ( ) ;
auto mipmap_layer { new_surface - > GetLayerMipmap ( surface - > GetGpuAddr ( ) ) } ;
const auto mipmap_layer { new_surface - > GetLayerMipmap ( surface - > GetGpuAddr ( ) ) } ;
if ( ! mipmap_layer ) {
continue ;
}
const auto [ layer, mipmap] = * mipmap_layer ;
if ( new_surface - > GetMipmapSize ( mipmap) ! = candidate_size ) {
const auto [ base_layer , base_mipmap ] = * mipmap_layer ;
if ( new_surface - > GetMipmapSize ( base_mipmap ) ! = surface - > GetMipmapSize ( 0 ) ) {
continue ;
}
// Copy all mipmaps and layers
const u32 block_width = params . GetDefaultBlockWidth ( ) ;
const u32 block_height = params . GetDefaultBlockHeight ( ) ;
for ( u32 mipmap = base_mipmap ; mipmap < base_mipmap + src_params . num_levels ; + + mipmap ) {
const u32 width = SurfaceParams : : IntersectWidth ( src_params , params , 0 , mipmap ) ;
const u32 height = SurfaceParams : : IntersectHeight ( src_params , params , 0 , mipmap ) ;
if ( width < block_width | | height < block_height ) {
// Current APIs forbid copying small compressed textures, avoid errors
break ;
}
const CopyParams copy_params ( 0 , 0 , 0 , 0 , 0 , base_layer , 0 , mipmap , width , height ,
src_params . depth ) ;
ImageCopy ( surface , new_surface , copy_params ) ;
}
+ + passed_tests ;
modified | = surface - > IsModified ( ) ;
// Now we got all the data set up
const u32 width = SurfaceParams : : IntersectWidth ( src_params , params , 0 , mipmap ) ;
const u32 height = SurfaceParams : : IntersectHeight ( src_params , params , 0 , mipmap ) ;
const CopyParams copy_params ( 0 , 0 , 0 , 0 , 0 , layer , 0 , mipmap , width , height , 1 ) ;
passed_tests + + ;
ImageCopy ( surface , new_surface , copy_params ) ;
}
if ( passed_tests = = 0 ) {
return { } ;
return std : : nullopt ;
}
if ( Settings : : IsGPULevelExtreme ( ) & & passed_tests ! = overlaps . size ( ) ) {
// In Accurate GPU all tests should pass, else we recycle
} else if ( Settings : : IsGPULevelExtreme ( ) & & passed_tests ! = overlaps . size ( ) ) {
return { } ;
return std : : nullopt ;
}
for ( const auto & surface : overlaps ) {
Unregister ( surface ) ;
}
new_surface - > MarkAsModified ( modified , Tick ( ) ) ;
Register ( new_surface ) ;
return { { new_surface , new_surface - > GetMainView ( ) } } ;
@ -868,12 +877,9 @@ private:
// two things either the candidate surface is a supertexture of the overlap
// or they don't match in any known way.
if ( ! current_surface - > IsInside ( gpu_addr , gpu_addr + candidate_size ) ) {
if ( current_surface - > GetGpuAddr ( ) = = gpu_addr ) {
std : : optional < std : : pair < TSurface , TView > > view =
TryReconstructSurface ( overlaps , params , gpu_addr ) ;
if ( view ) {
return * view ;
}
const std : : optional view = TryReconstructSurface ( overlaps , params , gpu_addr ) ;
if ( view ) {
return * view ;
}
return RecycleSurface ( overlaps , params , gpu_addr , preserve_contents ,
MatchTopologyResult : : FullMatch ) ;