Add fix to partial cache refresh

This commit is contained in:
Yousef Khadadeh 2025-08-08 09:56:50 +03:00
parent e9bcedb7ba
commit c8b6ed58e7
2 changed files with 57 additions and 65 deletions

View file

@ -267,27 +267,19 @@ void DrawingProgramCache::invalidate_cache_at_optional_aabb_before_pos(const std
}
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)) {
//if(aabb.fully_contains_aabb(n->bounds)) {
// NOTE: For now, we will invalidate the entire cache when something needs updating
// Invalidating parts of the cache can lead to massive speed ups with eraser and GIFs, but it currently has accuracy issues
// related to determining what's been drawn last
n->drawCache = std::nullopt;
return true;
//}
//else {
// auto& dCache = n->drawCache.value();
// if(dCache.invalidBounds.has_value()) {
// auto& iBounds = dCache.invalidBounds.value();
// iBounds.include_aabb_in_bounds(aabb);
// iBounds = n->bounds.get_intersection_between_aabbs(iBounds);
// }
// else
// dCache.invalidBounds = n->bounds.get_intersection_between_aabbs(aabb);
//}
std::for_each(nodesWithCachedSurfaces.begin(), nodesWithCachedSurfaces.end(), [&](auto& n) {
if(SCollision::collide(aabb, n->bounds)) {
auto& dCache = n->drawCache.value();
if(dCache.invalidBounds.has_value()) {
auto& iBounds = dCache.invalidBounds.value();
iBounds.include_aabb_in_bounds(aabb);
}
else
dCache.invalidBounds = aabb;
if(placementToInvalidateAt <= n->drawCache.value().lastDrawnComponentPlacement)
dCache.isInvalid = true;
}
return false;
});
}
@ -295,7 +287,7 @@ 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) {
if(node && node->coords.inverseScale <= drawData.cam.c.inverseScale) {
if(!node->drawCache /*|| node->drawCache.value().invalidBounds*/)
if(!node->drawCache || node->drawCache.value().isInvalid)
nodeFlatList.emplace_front(node);
return false;
}
@ -333,46 +325,45 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<DrawingProgra
cacheDrawData.cam.set_viewing_area(bvhNode->resolution.cast<float>());
cacheDrawData.refresh_draw_optimizing_values();
//if(drawCache.invalidBounds) {
// auto& iBounds = drawCache.invalidBounds.value();
// WorldVec bDim = bvhNode->bounds.dim();
if(drawCache.isInvalid) {
auto iBounds = drawCache.invalidBounds.value();
iBounds = bvhNode->bounds.get_intersection_between_aabbs(iBounds);
// Vector2f clipBoundMin{static_cast<float>((iBounds.min.x() - bvhNode->bounds.min.x()) / bDim.x()) * bvhNode->resolution.x(),
// static_cast<float>((iBounds.min.y() - bvhNode->bounds.min.y()) / bDim.y()) * bvhNode->resolution.y()};
// Vector2f clipBoundMax{static_cast<float>((iBounds.max.x() - bvhNode->bounds.min.x()) / bDim.x()) * bvhNode->resolution.x(),
// static_cast<float>((iBounds.max.y() - bvhNode->bounds.min.y()) / bDim.y()) * bvhNode->resolution.y()};
WorldVec bDim = bvhNode->bounds.dim();
// SkIRect clipRect = SkIRect::MakeLTRB(clipBoundMin.x() - 2,
// clipBoundMin.y() - 2,
// clipBoundMax.x() + 2,
// clipBoundMax.y() + 2);
Vector2f clipBoundMin{static_cast<float>((iBounds.min.x() - bvhNode->bounds.min.x()) / bDim.x()) * bvhNode->resolution.x(),
static_cast<float>((iBounds.min.y() - bvhNode->bounds.min.y()) / bDim.y()) * bvhNode->resolution.y()};
Vector2f clipBoundMax{static_cast<float>((iBounds.max.x() - bvhNode->bounds.min.x()) / bDim.x()) * bvhNode->resolution.x(),
static_cast<float>((iBounds.max.y() - bvhNode->bounds.min.y()) / bDim.y()) * bvhNode->resolution.y()};
// SCollision::AABB<float> clipRectBoundAABB{clipBoundMin - Vector2f{4, 4}, clipBoundMax + Vector2f{4, 4}};
// SCollision::AABB<WorldScalar> clipRectBoundAABBWorld{
// bvhNode->coords.from_space(clipRectBoundAABB.min),
// bvhNode->coords.from_space(clipRectBoundAABB.max)
// };
SkIRect clipRect = SkIRect::MakeLTRB(clipBoundMin.x() - 2,
clipBoundMin.y() - 2,
clipBoundMax.x() + 2,
clipBoundMax.y() + 2);
// cacheCanvas->save();
// cacheCanvas->clipIRect(clipRect);
// cacheCanvas->clear(SkColor4f{0, 0, 0, 0});
// uint64_t lastDrawnComponentPlacementNew = 0;
// draw_components_to_canvas(cacheCanvas, cacheDrawData, {
// .lastDrawnComponentPlacement = &lastDrawnComponentPlacementNew,
// .drawBounds = clipRectBoundAABBWorld,
// .lastObjectPositionToDraw = drawCache.lastDrawnComponentPlacement
// });
// // drawCache.lastDrawnComponentPlacement = std::max(lastDrawnComponentPlacementNew, drawCache.lastDrawnComponentPlacement);
// cacheCanvas->restore();
// drawCache.invalidBounds = std::nullopt;
//}
//else {
SCollision::AABB<float> clipRectBoundAABB{clipBoundMin - Vector2f{4, 4}, clipBoundMax + Vector2f{4, 4}};
SCollision::AABB<WorldScalar> clipRectBoundAABBWorld{
bvhNode->coords.from_space(clipRectBoundAABB.min),
bvhNode->coords.from_space(clipRectBoundAABB.max)
};
cacheCanvas->save();
cacheCanvas->clipIRect(clipRect);
cacheCanvas->clear(SkColor4f{0, 0, 0, 0});
draw_components_to_canvas(cacheCanvas, cacheDrawData, {
.lastDrawnComponentPlacement = &drawCache.lastDrawnComponentPlacement,
//.drawBounds = drawCache.invalidBounds
.drawBounds = clipRectBoundAABBWorld,
});
//}
cacheCanvas->restore();
drawCache.invalidBounds = std::nullopt;
drawCache.isInvalid = false;
}
else {
cacheCanvas->clear(SkColor4f{0, 0, 0, 0});
draw_components_to_canvas(cacheCanvas, cacheDrawData, {
.lastDrawnComponentPlacement = &drawCache.lastDrawnComponentPlacement,
});
}
drawCache.lastRenderTime = std::chrono::steady_clock::now();
drawCache.attachedCache = this;
@ -402,16 +393,19 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw
};
std::vector<UncachedObjectToDraw> uncachedCompsToDraw;
traverse_bvh_run_function(optData.drawBounds.has_value() ? optData.drawBounds.value() : drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
if(node && node->drawCache /*&& !node->drawCache.value().invalidBounds*/ && node->coords.inverseScale <= drawData.cam.c.inverseScale) {
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
if(node && node->drawCache && !node->drawCache.value().isInvalid && node->coords.inverseScale <= drawData.cam.c.inverseScale) {
cachedNodesToDraw.emplace_back(node);
lastComponentDrawn = std::max(lastComponentDrawn, node->drawCache->lastDrawnComponentPlacement);
return false;
}
for(auto& c : comps) {
c->obj->calculate_draw_transform(drawData);
if(c->obj->drawSetupData.shouldDraw)
if(!optData.drawBounds.has_value() || !c->obj->worldAABB.has_value() || SCollision::collide(optData.drawBounds.value(), c->obj->worldAABB.value())) {
c->obj->calculate_draw_transform(drawData);
uncachedCompsToDraw.emplace_back(c, !node);
}
lastComponentDrawn = std::max(lastComponentDrawn, c->pos);
}
return true;
@ -431,7 +425,7 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw
for(;;) {
if(nextCacheToRender >= cachedNodesToDraw.size() || uncachedComp.comp->pos <= cachedNodesToDraw[nextCacheToRender]->drawCache.value().lastDrawnComponentPlacement)
break;
lastComponentDrawn = std::max(lastComponentDrawn, draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]));
draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]);
nextCacheToRender++;
}
std::chrono::time_point drawStartTime = std::chrono::steady_clock::now();
@ -440,10 +434,9 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw
unsortedCompDrawTime += std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - drawStartTime);
uncachedComp.comp->obj->drawSetupData.shouldDraw = false;
lastComponentDrawn = std::max(lastComponentDrawn, uncachedComp.comp->pos);
}
for(;nextCacheToRender < cachedNodesToDraw.size(); nextCacheToRender++)
lastComponentDrawn = std::max(lastComponentDrawn, draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]));
draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]);
if(optData.lastDrawnComponentPlacement)
*optData.lastDrawnComponentPlacement = lastComponentDrawn;
@ -452,7 +445,7 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw
*optData.timeToDrawUnsortedComponents = unsortedCompDrawTime;
}
uint64_t DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
auto& drawCache = bvhNode->drawCache.value();
canvas->save();
bvhNode->coords.transform_sk_canvas(canvas, drawData);
@ -464,8 +457,6 @@ uint64_t DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const
canvas->drawImage(drawCache.surface->makeTemporaryImage(), 0, 0, {SkFilterMode::kLinear, SkMipmapMode::kLinear}, &srcPaint);
canvas->restore();
return drawCache.lastDrawnComponentPlacement;
}
DrawingProgramCache::~DrawingProgramCache() {

View file

@ -22,7 +22,8 @@ class DrawingProgramCacheBVHNode {
sk_sp<SkSurface> surface;
std::chrono::steady_clock::time_point lastRenderTime;
DrawingProgramCache* attachedCache;
//std::optional<SCollision::AABB<WorldScalar>> invalidBounds;
std::optional<SCollision::AABB<WorldScalar>> invalidBounds;
bool isInvalid = false;
};
std::optional<DrawCacheData> drawCache;
@ -69,7 +70,7 @@ class DrawingProgramCache {
const std::chrono::steady_clock::time_point& get_last_bvh_build_time() const;
void clear_own_cached_surfaces();
private:
uint64_t draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
void force_rebuild_dont_include_objs(std::vector<CollabListType::ObjectInfoPtr> componentsToBuild, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude);
void force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild);