2025-07-19 15:57:09 +03:00
# include "DrawingProgramCache.hpp"
2025-07-20 15:24:44 +03:00
# include "DrawingProgram.hpp"
# include "../World.hpp"
# include "../MainProgram.hpp"
2025-07-27 11:56:34 +03:00
# include "Helpers/Parallel.hpp"
2025-07-20 15:24:44 +03:00
# include <chrono>
# ifdef USE_SKIA_BACKEND_GRAPHITE
# include <include/gpu/graphite/Surface.h>
# elif USE_SKIA_BACKEND_GANESH
# include <include/gpu/ganesh/GrDirectContext.h>
# include <include/gpu/ganesh/SkSurfaceGanesh.h>
# endif
2025-07-23 16:04:16 +03:00
# define MAXIMUM_DRAW_CACHE_SURFACES 40
2025-07-22 12:22:08 +03:00
2025-07-24 16:35:48 +03:00
std : : unordered_set < std : : shared_ptr < DrawingProgramCacheBVHNode > > DrawingProgramCache : : nodesWithCachedSurfaces ;
2025-07-20 15:24:44 +03:00
DrawingProgramCache : : DrawingProgramCache ( DrawingProgram & initDrawP ) :
drawP ( initDrawP )
2025-07-21 11:59:19 +03:00
{
lastBvhBuildTime = std : : chrono : : steady_clock : : now ( ) ;
}
2025-07-19 15:57:09 +03:00
void DrawingProgramCache : : build ( std : : vector < CollabListType : : ObjectInfoPtr > components ) {
2025-07-24 16:35:48 +03:00
bvhRoot = std : : make_shared < DrawingProgramCacheBVHNode > ( ) ;
2025-07-19 15:57:09 +03:00
unsortedComponents . clear ( ) ;
2025-07-22 12:22:08 +03:00
clear_own_cached_surfaces ( ) ;
2025-07-19 15:57:09 +03:00
std : : erase_if ( components , [ & ] ( auto & c ) {
2025-07-21 17:48:46 +03:00
if ( ! c - > obj - > worldAABB ) {
2025-07-19 15:57:09 +03:00
unsortedComponents . emplace_back ( c ) ;
2025-07-21 11:59:19 +03:00
c - > obj - > parentBvhNode . reset ( ) ;
2025-07-19 15:57:09 +03:00
return true ;
}
return false ;
} ) ;
build_bvh_node ( bvhRoot , components ) ;
2025-07-21 11:59:19 +03:00
lastBvhBuildTime = std : : chrono : : steady_clock : : now ( ) ;
2025-07-19 15:57:09 +03:00
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : clear ( ) {
bvhRoot = nullptr ;
unsortedComponents . clear ( ) ;
clear_own_cached_surfaces ( ) ;
}
2025-07-22 12:22:08 +03:00
void DrawingProgramCache : : clear_own_cached_surfaces ( ) {
std : : erase_if ( nodesWithCachedSurfaces , [ & ] ( auto & s ) {
2025-07-24 16:35:48 +03:00
return s - > drawCache . value ( ) . attachedCache = = this ;
2025-07-22 12:22:08 +03:00
} ) ;
}
2025-07-26 21:20:14 +03:00
bool DrawingProgramCache : : check_if_rebuild_should_occur ( ) {
2025-07-27 20:04:26 +03:00
return ( unsortedComponents . size ( ) > = MINIMUM_COMPONENTS_TO_START_REBUILD ) ;
2025-07-26 21:20:14 +03:00
}
void DrawingProgramCache : : test_rebuild ( const std : : vector < CollabListType : : ObjectInfoPtr > & comps , bool force ) {
if ( force | | check_if_rebuild_should_occur ( ) )
force_rebuild ( comps ) ;
}
void DrawingProgramCache : : test_rebuild_dont_include_set ( const std : : vector < CollabListType : : ObjectInfoPtr > & comps , const std : : unordered_set < CollabListType : : ObjectInfoPtr > & objsToNotInclude , bool force ) {
if ( force | | check_if_rebuild_should_occur ( ) )
force_rebuild_dont_include_objs ( comps , objsToNotInclude ) ;
}
void DrawingProgramCache : : test_rebuild_dont_include_set_dont_include_nodes ( const std : : vector < CollabListType : : ObjectInfoPtr > & comps , const std : : unordered_set < CollabListType : : ObjectInfoPtr > & objsToNotInclude , const std : : unordered_set < std : : shared_ptr < DrawingProgramCacheBVHNode > > & nodesToNotInclude , bool force ) {
if ( force | | check_if_rebuild_should_occur ( ) ) {
auto objsToNotIncludeNew = objsToNotInclude ;
move_components_from_bvh_nodes_to_set ( objsToNotIncludeNew , nodesToNotInclude ) ;
force_rebuild_dont_include_objs ( comps , objsToNotIncludeNew ) ;
}
}
void DrawingProgramCache : : move_components_from_bvh_nodes_to_set ( std : : unordered_set < CollabListType : : ObjectInfoPtr > & s , const std : : unordered_set < std : : shared_ptr < DrawingProgramCacheBVHNode > > & bvhNodes ) {
for ( auto & b : bvhNodes )
move_components_from_bvh_node_to_set ( s , b ) ;
}
void DrawingProgramCache : : move_components_from_bvh_node_to_set ( std : : unordered_set < CollabListType : : ObjectInfoPtr > & s , const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode ) {
for ( auto & c : bvhNode - > components )
s . emplace ( c ) ;
for ( auto & p : bvhNode - > children )
move_components_from_bvh_node_to_set ( s , p ) ;
}
void DrawingProgramCache : : force_rebuild_dont_include_objs ( std : : vector < CollabListType : : ObjectInfoPtr > componentsToBuild , const std : : unordered_set < CollabListType : : ObjectInfoPtr > & objsToNotInclude ) {
std : : erase_if ( componentsToBuild , [ & objsToNotInclude ] ( auto & c ) {
return objsToNotInclude . contains ( c ) ;
} ) ;
build ( componentsToBuild ) ;
2025-07-24 16:35:48 +03:00
}
void DrawingProgramCache : : force_rebuild ( const std : : vector < CollabListType : : ObjectInfoPtr > & componentsToBuild ) {
build ( componentsToBuild ) ;
2025-07-21 11:59:19 +03:00
}
2025-07-24 16:35:48 +03:00
const std : : vector < CollabListType : : ObjectInfoPtr > & DrawingProgramCache : : get_unsorted_component_list ( ) const {
return unsortedComponents ;
}
const std : : chrono : : steady_clock : : time_point & DrawingProgramCache : : get_last_bvh_build_time ( ) const {
return lastBvhBuildTime ;
2025-07-19 15:57:09 +03:00
}
void DrawingProgramCache : : add_component ( const CollabListType : : ObjectInfoPtr & c ) {
unsortedComponents . emplace_back ( c ) ;
2025-07-27 20:04:26 +03:00
invalidate_cache_at_optional_aabb_before_pos ( c - > obj - > worldAABB , c - > pos ) ;
2025-07-19 15:57:09 +03:00
}
void DrawingProgramCache : : erase_component ( const CollabListType : : ObjectInfoPtr & c ) {
2025-07-21 11:59:19 +03:00
auto parentBvhNode = c - > obj - > parentBvhNode . lock ( ) ;
if ( parentBvhNode ) {
std : : erase ( parentBvhNode - > components , c ) ;
c - > obj - > parentBvhNode . reset ( ) ;
2025-07-19 15:57:09 +03:00
}
2025-07-21 11:59:19 +03:00
else
std : : erase ( unsortedComponents , c ) ;
2025-07-27 20:04:26 +03:00
invalidate_cache_at_optional_aabb_before_pos ( c - > obj - > worldAABB , c - > pos ) ;
2025-07-19 15:57:09 +03:00
}
2025-07-24 16:35:48 +03:00
std : : pair < std : : shared_ptr < DrawingProgramCacheBVHNode > , std : : vector < CollabListType : : ObjectInfoPtr > : : iterator > DrawingProgramCache : : get_bvh_node_fully_containing_recursive ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode , DrawComponent * c ) {
2025-07-19 15:57:09 +03:00
SCollision : : AABB < WorldScalar > & cAABB = c - > worldAABB . value ( ) ;
2025-07-21 11:59:19 +03:00
if ( ! bvhNode - > bounds . fully_contains_aabb ( cAABB ) )
return { nullptr , bvhNode - > components . end ( ) } ;
auto it = std : : find_if ( bvhNode - > components . begin ( ) , bvhNode - > components . end ( ) , [ & ] ( const auto & comp ) {
2025-07-19 15:57:09 +03:00
return comp - > obj . get ( ) = = c ;
} ) ;
2025-07-21 11:59:19 +03:00
if ( it ! = bvhNode - > components . end ( ) )
return { bvhNode , it } ;
for ( auto & p : bvhNode - > children ) {
2025-07-19 15:57:09 +03:00
auto toRet = get_bvh_node_fully_containing_recursive ( p , c ) ;
if ( toRet . first )
return toRet ;
}
2025-07-21 11:59:19 +03:00
return { nullptr , bvhNode - > components . end ( ) } ;
2025-07-19 15:57:09 +03:00
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : traverse_bvh_erase_function ( const SCollision : : AABB < WorldScalar > & aabb , std : : function < bool ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & node , std : : vector < CollabListType : : ObjectInfoPtr > & components ) > f ) {
2025-07-23 16:04:16 +03:00
f ( nullptr , unsortedComponents ) ;
if ( traverse_bvh_erase_function_recursive ( bvhRoot , aabb , f ) )
bvhRoot = nullptr ;
}
2025-07-24 16:35:48 +03:00
bool DrawingProgramCache : : traverse_bvh_erase_function_recursive ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode , const SCollision : : AABB < WorldScalar > & aabb , std : : function < bool ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & node , std : : vector < CollabListType : : ObjectInfoPtr > & components ) > f ) {
2025-07-23 16:04:16 +03:00
if ( bvhNode & & SCollision : : collide ( aabb , bvhNode - > bounds ) ) {
if ( f ( bvhNode , bvhNode - > components ) )
return true ;
std : : erase_if ( bvhNode - > children , [ & ] ( auto & p ) {
return traverse_bvh_erase_function_recursive ( p , aabb , f ) ;
} ) ;
}
return false ;
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : traverse_bvh_run_function ( const SCollision : : AABB < WorldScalar > & aabb , std : : function < bool ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & node , const std : : vector < CollabListType : : ObjectInfoPtr > & components ) > f ) {
2025-07-19 15:57:09 +03:00
f ( nullptr , unsortedComponents ) ;
traverse_bvh_run_function_recursive ( bvhRoot , aabb , f ) ;
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : traverse_bvh_run_function_recursive ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode , const SCollision : : AABB < WorldScalar > & aabb , std : : function < bool ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & node , const std : : vector < CollabListType : : ObjectInfoPtr > & components ) > f ) {
2025-07-21 11:59:19 +03:00
if ( bvhNode & & SCollision : : collide ( aabb , bvhNode - > bounds ) & & f ( bvhNode , bvhNode - > components ) ) {
for ( auto & p : bvhNode - > children )
2025-07-19 15:57:09 +03:00
traverse_bvh_run_function_recursive ( p , aabb , f ) ;
}
}
2025-07-31 09:34:17 +03:00
void DrawingProgramCache : : preupdate_component ( const CollabListType : : ObjectInfoPtr & c , const std : : optional < SCollision : : AABB < WorldScalar > > & aabb ) {
2025-07-21 11:59:19 +03:00
auto parentBvhNode = c - > obj - > parentBvhNode . lock ( ) ;
if ( parentBvhNode ) {
unsortedComponents . emplace_back ( c ) ;
std : : erase ( parentBvhNode - > components , c ) ;
c - > obj - > parentBvhNode . reset ( ) ;
2025-07-19 15:57:09 +03:00
}
2025-07-31 09:34:17 +03:00
invalidate_cache_at_optional_aabb_before_pos ( aabb , c - > pos ) ;
2025-07-19 15:57:09 +03:00
}
2025-07-27 11:56:34 +03:00
void DrawingProgramCache : : build_bvh_node ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode , const std : : vector < CollabListType : : ObjectInfoPtr > & components ) {
2025-07-19 15:57:09 +03:00
if ( components . empty ( ) )
return ;
2025-07-21 11:59:19 +03:00
bvhNode - > bounds = components . front ( ) - > obj - > worldAABB . value ( ) ;
2025-07-19 15:57:09 +03:00
for ( auto & c : components )
2025-07-21 11:59:19 +03:00
bvhNode - > bounds . include_aabb_in_bounds ( c - > obj - > worldAABB . value ( ) ) ;
2025-07-19 15:57:09 +03:00
2025-07-21 11:59:19 +03:00
build_bvh_node_coords_and_resolution ( * bvhNode ) ;
2025-07-20 15:24:44 +03:00
2025-07-26 21:20:14 +03:00
if ( components . size ( ) < MAXIMUM_COMPONENTS_IN_SINGLE_NODE ) {
2025-07-21 11:59:19 +03:00
bvhNode - > components = components ;
for ( auto & c : bvhNode - > components )
c - > obj - > parentBvhNode = bvhNode ;
2025-07-19 15:57:09 +03:00
return ;
}
2025-07-21 11:59:19 +03:00
WorldVec boundsCenter = bvhNode - > bounds . center ( ) ;
2025-07-19 15:57:09 +03:00
std : : array < std : : vector < CollabListType : : ObjectInfoPtr > , 4 > parts ;
for ( auto & c : components ) {
const auto & cAABB = c - > obj - > worldAABB . value ( ) ;
if ( cAABB . min . x ( ) < boundsCenter . x ( ) & & cAABB . max . x ( ) < boundsCenter . x ( ) & & cAABB . min . y ( ) < boundsCenter . y ( ) & & cAABB . max . y ( ) < boundsCenter . y ( ) )
parts [ 0 ] . emplace_back ( c ) ;
else if ( cAABB . min . x ( ) > boundsCenter . x ( ) & & cAABB . max . x ( ) > boundsCenter . x ( ) & & cAABB . min . y ( ) < boundsCenter . y ( ) & & cAABB . max . y ( ) < boundsCenter . y ( ) )
parts [ 1 ] . emplace_back ( c ) ;
else if ( cAABB . min . x ( ) < boundsCenter . x ( ) & & cAABB . max . x ( ) < boundsCenter . x ( ) & & cAABB . min . y ( ) > boundsCenter . y ( ) & & cAABB . max . y ( ) > boundsCenter . y ( ) )
parts [ 2 ] . emplace_back ( c ) ;
else if ( cAABB . min . x ( ) > boundsCenter . x ( ) & & cAABB . max . x ( ) > boundsCenter . x ( ) & & cAABB . min . y ( ) > boundsCenter . y ( ) & & cAABB . max . y ( ) > boundsCenter . y ( ) )
parts [ 3 ] . emplace_back ( c ) ;
2025-07-21 11:59:19 +03:00
else {
bvhNode - > components . emplace_back ( c ) ;
c - > obj - > parentBvhNode = bvhNode ;
}
2025-07-19 15:57:09 +03:00
}
for ( auto & p : parts ) {
if ( ! p . empty ( ) )
2025-07-24 16:35:48 +03:00
build_bvh_node ( bvhNode - > children . emplace_back ( std : : make_shared < DrawingProgramCacheBVHNode > ( ) ) , p ) ;
2025-07-19 15:57:09 +03:00
}
}
2025-07-19 19:41:25 +03:00
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : build_bvh_node_coords_and_resolution ( DrawingProgramCacheBVHNode & node ) {
2025-07-20 15:24:44 +03:00
// These are part of the draw cache data, but we're putting it out here, because:
// - We dont have to recalculate it every time we refresh the cache
// - Some of the data here is needed to determine whether to generate the cache in the first place
const int MAX_DIMENSION_RESOLUTION = 2000 ;
WorldVec cacheBoundDim = node . bounds . dim ( ) ;
if ( cacheBoundDim . x ( ) > cacheBoundDim . y ( ) ) {
node . resolution . x ( ) = MAX_DIMENSION_RESOLUTION ;
node . resolution . y ( ) = MAX_DIMENSION_RESOLUTION * static_cast < double > ( cacheBoundDim . y ( ) / cacheBoundDim . x ( ) ) ;
}
else {
node . resolution . y ( ) = MAX_DIMENSION_RESOLUTION ;
node . resolution . x ( ) = MAX_DIMENSION_RESOLUTION * static_cast < double > ( cacheBoundDim . x ( ) / cacheBoundDim . y ( ) ) ;
}
node . coords . rotation = 0.0 ;
node . coords . pos = node . bounds . min ;
// Not necessary, but we choose the number that had less operations done on it for more accuracy
if ( node . resolution . x ( ) > node . resolution . y ( ) )
node . coords . inverseScale = cacheBoundDim . x ( ) . divide_double ( node . resolution . x ( ) ) ;
else
node . coords . inverseScale = cacheBoundDim . y ( ) . divide_double ( node . resolution . y ( ) ) ;
}
2025-07-19 19:41:25 +03:00
void DrawingProgramCache : : invalidate_cache_before_pos ( uint64_t placementToInvalidateAt ) {
// We could use worldAABB of component to invalidate specific areas. However, that comes with some issues:
// - The AABB couldve been changed from the last frame, so the current worldAABB doesnt actually represent what we should update
// - The worldAABB might not be calculated yet, or mightve been invalidated (worldAABB = nullopt)
// For now, we will ignore worldAABB and just clear cache by placement in list
std : : erase_if ( nodesWithCachedSurfaces , [ & ] ( auto & n ) {
if ( placementToInvalidateAt < = n - > drawCache . value ( ) . lastDrawnComponentPlacement ) {
n - > drawCache = std : : nullopt ;
return true ;
}
return false ;
} ) ;
}
2025-07-20 15:24:44 +03:00
2025-07-27 20:04:26 +03:00
void DrawingProgramCache : : invalidate_cache_at_optional_aabb_before_pos ( const std : : optional < SCollision : : AABB < WorldScalar > > & aabb , uint64_t placementToInvalidateAt ) {
if ( aabb )
invalidate_cache_at_aabb_before_pos ( aabb . value ( ) , placementToInvalidateAt ) ;
else
invalidate_cache_before_pos ( placementToInvalidateAt ) ;
}
2025-07-23 16:04:16 +03:00
void DrawingProgramCache : : invalidate_cache_at_aabb_before_pos ( const SCollision : : AABB < WorldScalar > & aabb , uint64_t placementToInvalidateAt ) {
std : : erase_if ( nodesWithCachedSurfaces , [ & ] ( auto & n ) {
if ( placementToInvalidateAt < = n - > drawCache . value ( ) . lastDrawnComponentPlacement & & SCollision : : collide ( aabb , n - > bounds ) ) {
n - > drawCache = std : : nullopt ;
return true ;
}
return false ;
} ) ;
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : refresh_all_draw_cache ( const DrawData & drawData ) {
std : : deque < std : : shared_ptr < DrawingProgramCacheBVHNode > > nodeFlatList ; // We want to render children before parents, so that parents can make use of the cached children
traverse_bvh_run_function ( drawData . cam . viewingAreaGenerousCollider , [ & ] ( std : : shared_ptr < DrawingProgramCacheBVHNode > node , const std : : vector < CollabListType : : ObjectInfoPtr > & comps ) {
2025-07-20 15:24:44 +03:00
if ( node & & node - > coords . inverseScale < = drawData . cam . c . inverseScale ) {
if ( ! node - > drawCache )
nodeFlatList . emplace_front ( node ) ;
return false ;
}
return true ;
} ) ;
if ( ! nodeFlatList . empty ( ) )
2025-07-21 11:59:19 +03:00
refresh_draw_cache ( nodeFlatList . front ( ) , drawData ) ;
2025-07-20 15:24:44 +03:00
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : refresh_draw_cache ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & bvhNode , const DrawData & drawData ) {
2025-07-21 11:59:19 +03:00
if ( bvhNode - > children . empty ( ) & & bvhNode - > components . empty ( ) )
2025-07-20 15:24:44 +03:00
return ;
2025-07-21 11:59:19 +03:00
bvhNode - > drawCache = std : : nullopt ;
2025-07-24 16:35:48 +03:00
DrawingProgramCacheBVHNode : : DrawCacheData drawCache ;
2025-07-20 15:24:44 +03:00
2025-07-21 11:59:19 +03:00
SkImageInfo imgInfo = SkImageInfo : : MakeN32Premul ( bvhNode - > resolution . x ( ) , bvhNode - > resolution . y ( ) ) ;
2025-07-20 15:24:44 +03:00
# ifdef USE_SKIA_BACKEND_GRAPHITE
drawCache . surface = SkSurfaces : : RenderTarget ( drawP . world . main . window . recorder ( ) , imgInfo , skgpu : : Mipmapped : : kNo , drawP . world . main . window . defaultMSAASurfaceProps ) ;
# elif USE_SKIA_BACKEND_GANESH
drawCache . surface = SkSurfaces : : RenderTarget ( drawP . world . main . window . ctx . get ( ) , skgpu : : Budgeted : : kNo , imgInfo , drawP . world . main . window . defaultMSAASampleCount , & drawP . world . main . window . defaultMSAASurfaceProps ) ;
# endif
if ( ! drawCache . surface )
throw std : : runtime_error ( " [DrawingProgramCache::refresh_draw_cache] Could not make cache surface " ) ;
SkCanvas * cacheCanvas = drawCache . surface - > getCanvas ( ) ;
cacheCanvas - > clear ( SkColor4f { 0 , 0 , 0 , 0 } ) ;
DrawData cacheDrawData = drawData ;
2025-07-21 11:59:19 +03:00
cacheDrawData . cam . c = bvhNode - > coords ;
2025-07-20 15:24:44 +03:00
cacheDrawData . cam . changed = nullptr ;
2025-07-21 11:59:19 +03:00
cacheDrawData . cam . set_viewing_area ( bvhNode - > resolution . cast < float > ( ) ) ;
2025-07-20 15:24:44 +03:00
cacheDrawData . refresh_draw_optimizing_values ( ) ;
2025-07-24 16:35:48 +03:00
draw_components_to_canvas ( cacheCanvas , cacheDrawData , & drawCache . lastDrawnComponentPlacement ) ;
2025-07-20 15:24:44 +03:00
drawCache . lastRenderTime = std : : chrono : : steady_clock : : now ( ) ;
2025-07-24 16:35:48 +03:00
drawCache . attachedCache = this ;
2025-07-20 15:24:44 +03:00
2025-07-21 11:59:19 +03:00
bvhNode - > drawCache = drawCache ; // Set the drawCache after rendering is done, so that the draw function doesnt assume we have this node cached
2025-07-20 15:24:44 +03:00
while ( nodesWithCachedSurfaces . size ( ) > = MAXIMUM_DRAW_CACHE_SURFACES ) {
2025-07-24 16:35:48 +03:00
std : : shared_ptr < DrawingProgramCacheBVHNode > leastUsedNode = * nodesWithCachedSurfaces . begin ( ) ;
for ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & n : nodesWithCachedSurfaces ) {
2025-07-20 15:24:44 +03:00
if ( n - > drawCache . value ( ) . lastRenderTime < leastUsedNode - > drawCache . value ( ) . lastRenderTime )
leastUsedNode = n ;
}
2025-07-21 11:59:19 +03:00
leastUsedNode - > drawCache = std : : nullopt ;
2025-07-20 15:24:44 +03:00
nodesWithCachedSurfaces . erase ( leastUsedNode ) ;
}
2025-07-21 11:59:19 +03:00
nodesWithCachedSurfaces . emplace ( bvhNode ) ;
2025-07-20 15:24:44 +03:00
}
2025-07-24 16:35:48 +03:00
void DrawingProgramCache : : draw_components_to_canvas ( SkCanvas * canvas , const DrawData & drawData , uint64_t * lastDrawnComponentPlacement ) {
uint64_t lastComponentDrawn = 0 ;
std : : vector < std : : shared_ptr < DrawingProgramCacheBVHNode > > cachedNodesToDraw ;
std : : vector < CollabListType : : ObjectInfoPtr > uncachedCompsToDraw ;
traverse_bvh_run_function ( drawData . cam . viewingAreaGenerousCollider , [ & ] ( const std : : shared_ptr < DrawingProgramCacheBVHNode > & node , const std : : vector < CollabListType : : ObjectInfoPtr > & comps ) {
if ( node & & node - > drawCache & & node - > coords . inverseScale < = drawData . cam . c . inverseScale ) {
cachedNodesToDraw . emplace_back ( node ) ;
return false ;
}
for ( auto & c : comps )
c - > obj - > calculate_draw_transform ( drawData ) ;
uncachedCompsToDraw . insert ( uncachedCompsToDraw . end ( ) , comps . begin ( ) , comps . end ( ) ) ;
return true ;
} ) ;
std : : sort ( uncachedCompsToDraw . begin ( ) , uncachedCompsToDraw . end ( ) , [ ] ( auto & a , auto & b ) {
return a - > pos < b - > pos ;
} ) ;
std : : sort ( cachedNodesToDraw . begin ( ) , cachedNodesToDraw . end ( ) , [ ] ( auto & a , auto & b ) {
return a - > drawCache . value ( ) . lastDrawnComponentPlacement < b - > drawCache . value ( ) . lastDrawnComponentPlacement ;
} ) ;
size_t nextCacheToRender = 0 ;
for ( auto & c : uncachedCompsToDraw ) {
for ( ; ; ) {
if ( nextCacheToRender > = cachedNodesToDraw . size ( ) | | c - > pos < cachedNodesToDraw [ nextCacheToRender ] - > drawCache . value ( ) . lastDrawnComponentPlacement )
break ;
auto & bvhNode = cachedNodesToDraw [ nextCacheToRender ] ;
auto & drawCache = bvhNode - > drawCache . value ( ) ;
canvas - > save ( ) ;
bvhNode - > coords . transform_sk_canvas ( canvas , drawData ) ;
drawCache . lastRenderTime = std : : chrono : : steady_clock : : now ( ) ;
lastComponentDrawn = std : : max ( lastComponentDrawn , drawCache . lastDrawnComponentPlacement ) ;
SkPaint p ;
p . setBlendMode ( SkBlendMode : : kSrc ) ;
// Note, no mipmaps here. You might need to generate mipmaps in the future (withDefaultMipmaps)
canvas - > drawImage ( drawCache . surface - > makeTemporaryImage ( ) , 0 , 0 , { SkFilterMode : : kLinear , SkMipmapMode : : kLinear } , & p ) ;
canvas - > restore ( ) ;
nextCacheToRender + + ;
}
c - > obj - > draw ( canvas , drawData ) ;
c - > obj - > drawSetupData . shouldDraw = false ;
lastComponentDrawn = std : : max ( lastComponentDrawn , c - > pos ) ;
}
for ( ; nextCacheToRender < cachedNodesToDraw . size ( ) ; nextCacheToRender + + ) {
auto & bvhNode = cachedNodesToDraw [ nextCacheToRender ] ;
auto & drawCache = bvhNode - > drawCache . value ( ) ;
canvas - > save ( ) ;
bvhNode - > coords . transform_sk_canvas ( canvas , drawData ) ;
drawCache . lastRenderTime = std : : chrono : : steady_clock : : now ( ) ;
lastComponentDrawn = std : : max ( lastComponentDrawn , drawCache . lastDrawnComponentPlacement ) ;
SkPaint p ;
p . setBlendMode ( SkBlendMode : : kSrc ) ;
// Note, no mipmaps here. You might need to generate mipmaps in the future (withDefaultMipmaps)
canvas - > drawImage ( drawCache . surface - > makeTemporaryImage ( ) , 0 , 0 , { SkFilterMode : : kLinear , SkMipmapMode : : kLinear } , & p ) ;
canvas - > restore ( ) ;
}
if ( lastDrawnComponentPlacement )
* lastDrawnComponentPlacement = lastComponentDrawn ;
}
DrawingProgramCache : : ~ DrawingProgramCache ( ) {
clear_own_cached_surfaces ( ) ;
}