Draw speedup when there are >100000 objects in the canvas

This commit is contained in:
Yousef Khadadeh 2025-07-21 15:46:42 +03:00
parent 1c1f23d68d
commit f74298d21d
3 changed files with 70 additions and 12 deletions

View file

@ -617,31 +617,48 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
}
void DrawingProgram::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, bool dontUseCache) {
for(auto& c : components.client_list())
c->obj->drawSetupData.shouldDraw = false;
std::vector<std::shared_ptr<DrawingProgramCache::BVHNode>> cachedNodesToDraw;
std::vector<CollabListType::ObjectInfoPtr> uncachedCompsToDraw;
size_t numOfUncachedComponentsToDraw = 0;
const size_t maxUncachedCompsToUseAltStrategy = 1000;
const size_t minCompsToUseAltStrategy = 100000;
compCache.traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCache::BVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
if(!dontUseCache && 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);
if(numOfUncachedComponentsToDraw < minCompsToUseAltStrategy && components.client_list().size() > maxUncachedCompsToUseAltStrategy) {
uncachedCompsToDraw.insert(uncachedCompsToDraw.end(), comps.begin(), comps.end());
numOfUncachedComponentsToDraw += comps.size();
}
return true;
});
for(uint64_t i = 0; i < components.client_list().size(); i++) {
auto& c = components.client_list()[i];
c->obj->draw(canvas, drawData);
for(const std::shared_ptr<DrawingProgramCache::BVHNode>& bvhNode : cachedNodesToDraw) {
auto& drawCache = bvhNode->drawCache.value();
if(drawCache.lastDrawnComponentPlacement == i) {
if(numOfUncachedComponentsToDraw < minCompsToUseAltStrategy && components.client_list().size() > maxUncachedCompsToUseAltStrategy) {
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();
SkPaint p;
p.setBlendMode(SkBlendMode::kSrc);
@ -649,7 +666,48 @@ void DrawingProgram::draw_components_to_canvas(SkCanvas* canvas, const DrawData&
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;
}
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();
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();
}
}
else {
for(uint64_t i = 0; i < components.client_list().size(); i++) {
auto& c = components.client_list()[i];
c->obj->draw(canvas, drawData);
for(const std::shared_ptr<DrawingProgramCache::BVHNode>& bvhNode : cachedNodesToDraw) {
auto& drawCache = bvhNode->drawCache.value();
if(drawCache.lastDrawnComponentPlacement == i) {
canvas->save();
bvhNode->coords.transform_sk_canvas(canvas, drawData);
drawCache.lastRenderTime = std::chrono::steady_clock::now();
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();
}
}
c->obj->drawSetupData.shouldDraw = false;
}
}
}

View file

@ -36,7 +36,7 @@ void DrawingProgramCache::build(std::vector<CollabListType::ObjectInfoPtr> compo
}
void DrawingProgramCache::update() {
if(unsortedComponents.size() >= 750 && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(7))
if(unsortedComponents.size() >= 1000 && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(7))
force_rebuild();
}