@ -615,6 +615,85 @@ private:
return { { new_surface , new_surface - > GetMainView ( ) } } ;
return { { new_surface , new_surface - > GetMainView ( ) } } ;
}
}
/**
* Takes care of managing 3 D textures and its slices . Does some HLE methods when possible .
* Fallsback to LLE when it isn ' t possible .
*
* @ param overlaps The overlapping surfaces registered in the cache .
* @ param params The parameters on the new surface .
* @ param gpu_addr The starting address of the new surface .
* @ param cache_addr The starting address of the new surface on physical memory .
* @ param preserve_contents Indicates that the new surface should be loaded from memory or
* left blank .
*/
std : : optional < std : : pair < TSurface , TView > > Manage3DSurfaces ( std : : vector < TSurface > & overlaps ,
const SurfaceParams & params ,
const GPUVAddr gpu_addr ,
const CacheAddr cache_addr ,
bool preserve_contents ) {
if ( params . target = = SurfaceTarget : : Texture3D ) {
bool failed = false ;
if ( params . num_levels > 1 ) {
// We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
return std : : nullopt ;
}
TSurface new_surface = GetUncachedSurface ( gpu_addr , params ) ;
bool modified = false ;
for ( auto & surface : overlaps ) {
const SurfaceParams & src_params = surface - > GetSurfaceParams ( ) ;
if ( src_params . target ! = SurfaceTarget : : Texture2D ) {
failed = true ;
break ;
}
if ( src_params . height ! = params . height ) {
failed = true ;
break ;
}
if ( src_params . block_depth ! = params . block_depth | |
src_params . block_height ! = params . block_height ) {
failed = true ;
break ;
}
const u32 offset = static_cast < u32 > ( surface - > GetCacheAddr ( ) - cache_addr ) ;
const auto [ x , y , z ] = params . GetBlockOffsetXYZ ( offset ) ;
modified | = surface - > IsModified ( ) ;
const CopyParams copy_params ( 0 , 0 , 0 , 0 , 0 , z , 0 , 0 , params . width , params . height ,
1 ) ;
ImageCopy ( surface , new_surface , copy_params ) ;
}
if ( failed ) {
return std : : nullopt ;
}
for ( const auto & surface : overlaps ) {
Unregister ( surface ) ;
}
new_surface - > MarkAsModified ( modified , Tick ( ) ) ;
Register ( new_surface ) ;
return { { new_surface , new_surface - > GetMainView ( ) } } ;
} else {
for ( const auto & surface : overlaps ) {
if ( ! surface - > MatchTarget ( params . target ) ) {
if ( overlaps . size ( ) = = 1 & & surface - > GetCacheAddr ( ) = = cache_addr ) {
if ( Settings : : values . use_accurate_gpu_emulation ) {
return std : : nullopt ;
}
Unregister ( surface ) ;
return InitializeSurface ( gpu_addr , params , preserve_contents ) ;
}
return std : : nullopt ;
}
if ( surface - > GetCacheAddr ( ) ! = cache_addr ) {
continue ;
}
const auto struct_result = surface - > MatchesStructure ( params ) ;
if ( struct_result = = MatchStructureResult : : FullMatch ) {
return { { surface , surface - > GetMainView ( ) } } ;
}
}
return InitializeSurface ( gpu_addr , params , preserve_contents ) ;
}
}
/**
/**
* Gets the starting address and parameters of a candidate surface and tries
* Gets the starting address and parameters of a candidate surface and tries
* to find a matching surface within the cache . This is done in 3 big steps :
* to find a matching surface within the cache . This is done in 3 big steps :
@ -687,6 +766,15 @@ private:
}
}
}
}
// Look if it's a 3D texture
if ( params . block_depth > 0 ) {
std : : optional < std : : pair < TSurface , TView > > surface =
Manage3DSurfaces ( overlaps , params , gpu_addr , cache_addr , preserve_contents ) ;
if ( surface ) {
return * surface ;
}
}
// Split cases between 1 overlap or many.
// Split cases between 1 overlap or many.
if ( overlaps . size ( ) = = 1 ) {
if ( overlaps . size ( ) = = 1 ) {
TSurface current_surface = overlaps [ 0 ] ;
TSurface current_surface = overlaps [ 0 ] ;