Fixed ordering issue with cache draw, also sharing draw cache space with all open tabs

This commit is contained in:
Yousef Khadadeh 2025-07-22 12:22:08 +03:00
parent 415921d881
commit 7fa82d3fa4
5 changed files with 59 additions and 69 deletions

View file

@ -564,8 +564,10 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
parallel_loop_all_components([&](auto& c) {
c->obj->calculate_draw_transform(drawData);
});
for(auto& c : components.client_list())
for(auto& c : components.client_list()) {
c->obj->draw(canvas, drawData);
c->obj->drawSetupData.shouldDraw = false;
}
}
else {
SkCanvas* drawProgCacheCanvas = world.main.drawProgCache.surface->getCanvas();
@ -609,13 +611,11 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
}
}
void DrawingProgram::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, bool dontUseCache) {
uint64_t DrawingProgram::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, bool dontUseCache) {
uint64_t lastComponentDrawn = 0;
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) {
@ -626,51 +626,30 @@ void DrawingProgram::draw_components_to_canvas(SkCanvas* canvas, const DrawData&
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();
}
uncachedCompsToDraw.insert(uncachedCompsToDraw.end(), comps.begin(), comps.end());
return true;
});
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);
// 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;
}
for(;nextCacheToRender < cachedNodesToDraw.size(); nextCacheToRender++) {
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);
@ -678,31 +657,31 @@ 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;
lastComponentDrawn = std::max(lastComponentDrawn, c->pos);
}
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);
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();
// 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);
lastComponentDrawn = std::max(lastComponentDrawn, drawCache.lastDrawnComponentPlacement);
canvas->restore();
}
}
c->obj->drawSetupData.shouldDraw = false;
}
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();
}
return lastComponentDrawn;
}
Vector4f* DrawingProgram::get_foreground_color_ptr() {

View file

@ -86,7 +86,7 @@ class DrawingProgram {
void add_undo_place_component(uint64_t placement, const std::shared_ptr<DrawComponent>& comp);
void add_undo_place_components(uint64_t placement, const std::vector<std::shared_ptr<DrawComponent>>& comps);
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, bool dontUseCache);
uint64_t draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, bool dontUseCache);
BrushTool brushTool;
EraserTool eraserTool;

View file

@ -11,7 +11,9 @@
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#endif
#define MAXIMUM_DRAW_CACHE_SURFACES 32
#define MAXIMUM_DRAW_CACHE_SURFACES 64
std::unordered_set<std::shared_ptr<DrawingProgramCache::BVHNode>> DrawingProgramCache::nodesWithCachedSurfaces;
DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP):
drawP(initDrawP)
@ -22,7 +24,7 @@ DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP):
void DrawingProgramCache::build(std::vector<CollabListType::ObjectInfoPtr> components) {
bvhRoot = std::make_shared<BVHNode>();
unsortedComponents.clear();
nodesWithCachedSurfaces.clear();
clear_own_cached_surfaces();
std::erase_if(components, [&](auto& c) {
if(!c->obj->worldAABB) {
unsortedComponents.emplace_back(c);
@ -35,6 +37,12 @@ void DrawingProgramCache::build(std::vector<CollabListType::ObjectInfoPtr> compo
lastBvhBuildTime = std::chrono::steady_clock::now();
}
void DrawingProgramCache::clear_own_cached_surfaces() {
std::erase_if(nodesWithCachedSurfaces, [&](auto& s) {
return s->drawCache.value().attachedDrawP == &drawP;
});
}
void DrawingProgramCache::update() {
if(unsortedComponents.size() >= 1000 && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(5))
force_rebuild();
@ -257,10 +265,10 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<BVHNode>& bvh
cacheDrawData.cam.changed = nullptr;
cacheDrawData.cam.set_viewing_area(bvhNode->resolution.cast<float>());
cacheDrawData.refresh_draw_optimizing_values();
drawP.draw_components_to_canvas(cacheCanvas, cacheDrawData, false);
drawCache.lastDrawnComponentPlacement = drawP.components.client_list().size() - 1;
drawCache.lastDrawnComponentPlacement = drawP.draw_components_to_canvas(cacheCanvas, cacheDrawData, false);
drawCache.lastRenderTime = std::chrono::steady_clock::now();
drawCache.attachedDrawP = &drawP;
bvhNode->drawCache = drawCache; // Set the drawCache after rendering is done, so that the draw function doesnt assume we have this node cached

View file

@ -30,12 +30,13 @@ class DrawingProgramCache {
uint64_t lastDrawnComponentPlacement;
sk_sp<SkSurface> surface;
std::chrono::steady_clock::time_point lastRenderTime;
DrawingProgram* attachedDrawP;
};
std::optional<DrawCacheData> drawCache;
};
std::unordered_set<std::shared_ptr<BVHNode>> nodesWithCachedSurfaces;
static std::unordered_set<std::shared_ptr<BVHNode>> nodesWithCachedSurfaces;
void traverse_bvh_collision_check(const SCollision::ColliderCollection<WorldScalar>& checkAgainstWorld, const SCollision::ColliderCollection<float>& checkAgainstCam);
void traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode> node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f);
@ -46,6 +47,7 @@ class DrawingProgramCache {
void invalidate_cache_before_pos(uint64_t placementToInvalidateAt);
private:
void clear_own_cached_surfaces();
void traverse_bvh_collision_check_recursive(const std::shared_ptr<BVHNode>& bvhNode, const SCollision::ColliderCollection<WorldScalar>& checkAgainstWorld, const SCollision::ColliderCollection<float>& checkAgainstCam);
void traverse_bvh_collision_check_recursive_tiny(const std::shared_ptr<BVHNode>& bvhNode);