Rebuild cache when framerate drops significantly from uncached objects

This commit is contained in:
Yousef Khadadeh 2025-08-07 21:30:40 +03:00
parent d91c7e987f
commit 0b72dd4ea9
4 changed files with 54 additions and 19 deletions

View file

@ -564,6 +564,8 @@ void DrawingProgram::write_to_file(cereal::PortableBinaryOutputArchive& a) {
}
void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
std::chrono::microseconds timeToDrawUnsortedComponents(0);
if(drawData.dontUseDrawProgCache) {
parallel_loop_all_components([&](auto& c) {
c->obj->calculate_draw_transform(drawData);
@ -577,7 +579,9 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
canvas->saveLayer(nullptr, nullptr);
canvas->clear(SkColor4f{0.0f, 0.0f, 0.0f, 0.0f});
compCache.refresh_all_draw_cache(drawData);
compCache.draw_components_to_canvas(canvas, drawData);
compCache.draw_components_to_canvas(canvas, drawData, {
.timeToDrawUnsortedComponents = &timeToDrawUnsortedComponents
});
canvas->saveLayer(nullptr, nullptr);
selection.draw_components(canvas, drawData);
canvas->restore();
@ -586,6 +590,9 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
}
drawTool->draw(canvas, drawData);
if(timeToDrawUnsortedComponents >= std::chrono::microseconds(16000))
force_rebuild_cache();
}
Vector4f* DrawingProgram::get_foreground_color_ptr() {

View file

@ -354,14 +354,20 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<DrawingProgra
cacheCanvas->clipIRect(clipRect);
cacheCanvas->clear(SkColor4f{0, 0, 0, 0});
uint64_t lastDrawnComponentPlacementNew = 0;
draw_components_to_canvas(cacheCanvas, cacheDrawData, &lastDrawnComponentPlacementNew, clipRectBoundAABBWorld);
draw_components_to_canvas(cacheCanvas, cacheDrawData, {
.lastDrawnComponentPlacement = &lastDrawnComponentPlacementNew,
.drawBounds = clipRectBoundAABBWorld
});
drawCache.lastDrawnComponentPlacement = std::max(lastDrawnComponentPlacementNew, drawCache.lastDrawnComponentPlacement);
cacheCanvas->restore();
drawCache.invalidBounds = std::nullopt;
}
else {
cacheCanvas->clear(SkColor4f{0, 0, 0, 0});
draw_components_to_canvas(cacheCanvas, cacheDrawData, &drawCache.lastDrawnComponentPlacement, drawCache.invalidBounds);
draw_components_to_canvas(cacheCanvas, cacheDrawData, {
.lastDrawnComponentPlacement = &drawCache.lastDrawnComponentPlacement,
.drawBounds = drawCache.invalidBounds
});
}
drawCache.lastRenderTime = std::chrono::steady_clock::now();
@ -382,49 +388,64 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<DrawingProgra
nodesWithCachedSurfaces.emplace(bvhNode);
}
void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, uint64_t* lastDrawnComponentPlacement, std::optional<SCollision::AABB<WorldScalar>> drawBounds) {
void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData) {
uint64_t lastComponentDrawn = 0;
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> cachedNodesToDraw;
std::vector<CollabListType::ObjectInfoPtr> uncachedCompsToDraw;
struct UncachedObjectToDraw {
CollabListType::ObjectInfoPtr comp;
bool isAnUnsortedObject;
};
std::vector<UncachedObjectToDraw> uncachedCompsToDraw;
traverse_bvh_run_function(drawBounds.has_value() ? drawBounds.value() : drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
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) {
cachedNodesToDraw.emplace_back(node);
return false;
}
for(auto& c : comps)
for(auto& c : comps) {
c->obj->calculate_draw_transform(drawData);
uncachedCompsToDraw.insert(uncachedCompsToDraw.end(), comps.begin(), comps.end());
if(c->obj->drawSetupData.shouldDraw)
uncachedCompsToDraw.emplace_back(c, !node);
}
return true;
});
std::sort(uncachedCompsToDraw.begin(), uncachedCompsToDraw.end(), [](auto& a, auto& b) {
return a->pos < b->pos;
return a.comp->pos < b.comp->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) {
std::chrono::microseconds unsortedCompDrawTime(0);
for(auto& uncachedComp : uncachedCompsToDraw) {
for(;;) {
if(nextCacheToRender >= cachedNodesToDraw.size() || c->pos <= cachedNodesToDraw[nextCacheToRender]->drawCache.value().lastDrawnComponentPlacement)
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]));
nextCacheToRender++;
}
c->obj->draw(canvas, drawData);
c->obj->drawSetupData.shouldDraw = false;
lastComponentDrawn = std::max(lastComponentDrawn, c->pos);
std::chrono::time_point drawStartTime = std::chrono::steady_clock::now();
uncachedComp.comp->obj->draw(canvas, drawData);
if(uncachedComp.isAnUnsortedObject)
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]));
if(lastDrawnComponentPlacement)
*lastDrawnComponentPlacement = lastComponentDrawn;
if(optData.lastDrawnComponentPlacement)
*optData.lastDrawnComponentPlacement = lastComponentDrawn;
if(optData.timeToDrawUnsortedComponents)
*optData.timeToDrawUnsortedComponents = unsortedCompDrawTime;
}
uint64_t DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {

View file

@ -57,7 +57,14 @@ class DrawingProgramCache {
void invalidate_cache_at_aabb_before_pos(const SCollision::AABB<WorldScalar>& aabb, uint64_t placementToInvalidateAt);
void invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& aabb, uint64_t placementToInvalidateAt);
void clear();
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, uint64_t* lastDrawnComponentPlacement = nullptr, std::optional<SCollision::AABB<WorldScalar>> drawBounds = std::nullopt);
struct DrawComponentsToCanvasOptionalData {
uint64_t* lastDrawnComponentPlacement = nullptr;
std::optional<SCollision::AABB<WorldScalar>> drawBounds;
std::chrono::microseconds* timeToDrawUnsortedComponents = nullptr;
};
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData);
const std::vector<CollabListType::ObjectInfoPtr>& get_unsorted_component_list() const;
const std::chrono::steady_clock::time_point& get_last_bvh_build_time() const;
void clear_own_cached_surfaces();

View file

@ -453,7 +453,7 @@ void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData&
if(!surface)
throw std::runtime_error("[DrawingProgramSelection::draw_components] Could not make temporary surface");
cache.draw_components_to_canvas(surface->getCanvas(), selectionDrawData);
cache.draw_components_to_canvas(surface->getCanvas(), selectionDrawData, {});
SkPaint glowBlurP;
glowBlurP.setImageFilter(SkImageFilters::Blur(5, 5, nullptr));