From e750d857da001c8719087e9a29d175ca8cf8fd46 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Sat, 31 Jan 2026 14:03:00 +0300 Subject: [PATCH] Add parallelization to transform calculation --- .../CanvasComponentContainer.cpp | 17 +++++----- .../CanvasComponentContainer.hpp | 16 +++++----- src/DrawingProgram/DrawingProgramCache.cpp | 31 ++++++++++++++----- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp index 7f43015..f138a3c 100644 --- a/src/CanvasComponents/CanvasComponentContainer.cpp +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -88,12 +88,15 @@ void CanvasComponentContainer::load_file(cereal::PortableBinaryInputArchive& a, } void CanvasComponentContainer::draw(SkCanvas* canvas, const DrawData& drawData) const { - if(should_draw(drawData)) { - canvas->save(); - canvas_do_transform(canvas, calculate_draw_transform(drawData)); - get_comp().draw(canvas, drawData); - canvas->restore(); - } + if(should_draw(drawData)) + draw_with_transform(canvas, drawData, calculate_draw_transform(drawData)); +} + +void CanvasComponentContainer::draw_with_transform(SkCanvas* canvas, const DrawData& drawData, const TransformDrawData& transformDrawData) const { + canvas->save(); + canvas_do_transform(canvas, transformDrawData); + get_comp().draw(canvas, drawData); + canvas->restore(); } void CanvasComponentContainer::commit_update(DrawingProgram& drawP) { @@ -132,7 +135,7 @@ bool CanvasComponentContainer::collides_with_cam_coords(const CoordSpaceHelper& bool CanvasComponentContainer::collides_with(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) const { if((camCoords.inverseScale << COMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS) < coords.inverseScale) // Object is too large, just dismiss the collision return false; - else if((camCoords.inverseScale >> COMP_COLLIDE_MIN_SHIFT_TINY) >= coords.inverseScale) + else if(coords.inverseScale < (camCoords.inverseScale >> COMP_COLLIDE_MIN_SHIFT_TINY)) return SCollision::collide(checkAgainstCam, camCoords.to_space(worldAABB.value().min)); else { auto c = checkAgainstWorld.transform( diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp index f71e43c..7f19e81 100644 --- a/src/CanvasComponents/CanvasComponentContainer.hpp +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -32,6 +32,13 @@ class CanvasComponentContainer { std::unique_ptr obj; void scale_up(const WorldScalar& scaleUpAmount); }; + + struct TransformDrawData { + Vector2f translation; + float rotation; + float scale; + }; + std::optional transformHolder; // Can be used to store transforms when calculating transforms in parallel CanvasComponentContainer(); CanvasComponentContainer(NetworkingObjects::NetObjManager& objMan, CanvasComponentType type); @@ -45,6 +52,8 @@ class CanvasComponentContainer { CanvasComponent& get_comp() const; SCollision::AABB get_world_bounds() const; void draw(SkCanvas* canvas, const DrawData& drawData) const; + void draw_with_transform(SkCanvas* canvas, const DrawData& drawData, const TransformDrawData& transformDrawData) const; + TransformDrawData calculate_draw_transform(const DrawData& drawData) const; void commit_update(DrawingProgram& drawP); void commit_transform_dont_invalidate_cache(); // Must be thread safe void commit_transform(DrawingProgram& drawP); @@ -66,16 +75,9 @@ class CanvasComponentContainer { static void write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); - struct TransformDrawData { - Vector2f translation; - float rotation; - float scale; - }; - unsigned get_mipmap_level(const DrawData& drawData) const; CanvasComponent* allocate_comp(CanvasComponentType type); void canvas_do_transform(SkCanvas* canvas, const TransformDrawData& transformData) const; - TransformDrawData calculate_draw_transform(const DrawData& drawData) const; void calculate_world_bounds(); std::optional> worldAABB; diff --git a/src/DrawingProgram/DrawingProgramCache.cpp b/src/DrawingProgram/DrawingProgramCache.cpp index 3bec0dc..d81375a 100644 --- a/src/DrawingProgram/DrawingProgramCache.cpp +++ b/src/DrawingProgram/DrawingProgramCache.cpp @@ -2,6 +2,7 @@ #include "DrawingProgram.hpp" #include "../World.hpp" #include "../MainProgram.hpp" +#include "Helpers/Parallel.hpp" #include "Layers/DrawingProgramLayerManager.hpp" #ifdef USE_SKIA_BACKEND_GRAPHITE @@ -424,8 +425,10 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw } } } - if(node) // Not the "unsorted components" node (which is nullptr) + if(node && node->coords.inverseScale > (drawData.cam.c.inverseScale >> CanvasComponentContainer::COMP_MIN_SHIFT_BEFORE_DISAPPEAR)) // Not the "unsorted components" node (which is nullptr) uncachedNodes.emplace_back(node); + else + return false; return true; }); @@ -448,21 +451,35 @@ void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgr } else { std::vector compsToDraw; - for(auto& c : unsortedComponents) { - if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds()))) - compsToDraw.emplace_back(c); - } + parallel_loop_container(nodesToDraw, [&](auto& node) { + std::for_each(node->components.begin(), node->components.end(), [&](auto& c) { + if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData)) + c->obj->transformHolder = c->obj->calculate_draw_transform(drawData); + else + c->obj->transformHolder = std::nullopt; + }); + }); + parallel_loop_container(unsortedComponents, [&](auto& c) { + if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData)) + c->obj->transformHolder = c->obj->calculate_draw_transform(drawData); + else + c->obj->transformHolder = std::nullopt; + }); for(auto& node : nodesToDraw) { for(auto& c : node->components) { - if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds()))) + if(c->obj->transformHolder.has_value()) compsToDraw.emplace_back(c); } } + for(auto& c : unsortedComponents) { + if(c->obj->transformHolder.has_value()) + compsToDraw.emplace_back(c); + } std::sort(compsToDraw.begin(), compsToDraw.end(), [](auto& a, auto& b) { return a->pos < b->pos; }); for(auto& c : compsToDraw) - c->obj->draw(canvas, drawData); + c->obj->draw_with_transform(canvas, drawData, c->obj->transformHolder.value()); } canvas->restore(); }