Skip to content

Commit a078895

Browse files
committed
Merge pull request #109243 from precup/tile-map-optimizations
Avoid unnecessary updates in `TileMapLayer`
2 parents c32c260 + adfb0d8 commit a078895

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

scene/2d/tile_map_layer.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ void TileMapLayer::_debug_update(bool p_force_cleanup) {
6464

6565
// Check if we should cleanup everything.
6666
bool forced_cleanup = p_force_cleanup || !enabled || tile_set.is_null() || !is_visible_in_tree();
67+
if (forced_cleanup && _debug_was_cleaned_up) {
68+
return;
69+
}
6770

6871
if (forced_cleanup) {
6972
for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) {
@@ -206,6 +209,9 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
206209

207210
// Check if we should cleanup everything.
208211
bool forced_cleanup = p_force_cleanup || !enabled || tile_set.is_null() || !is_visible_in_tree();
212+
if (forced_cleanup && _rendering_was_cleaned_up) {
213+
return;
214+
}
209215

210216
// ----------- Layer level processing -----------
211217
if (!forced_cleanup) {
@@ -234,7 +240,7 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
234240
(!is_y_sort_enabled() && dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE]);
235241

236242
// Free all quadrants.
237-
if (forced_cleanup || quadrant_shape_changed) {
243+
if (!_rendering_was_cleaned_up && (forced_cleanup || quadrant_shape_changed)) {
238244
for (const KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
239245
for (const RID &ci : kv.value->canvas_items) {
240246
if (ci.is_valid()) {
@@ -398,15 +404,23 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
398404
int index = -(int64_t)0x80000000; // Always must be drawn below children.
399405

400406
// Sort the quadrants coords per local coordinates.
401-
RBMap<Vector2, Ref<RenderingQuadrant>, RenderingQuadrant::CoordsWorldComparator> local_to_map;
407+
LocalVector<Pair<Vector2, Ref<RenderingQuadrant>>> sortable_quadrant_keys;
408+
sortable_quadrant_keys.reserve(rendering_quadrant_map.size());
402409
for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
403-
Ref<RenderingQuadrant> &rendering_quadrant = kv.value;
404-
local_to_map[tile_set->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant;
410+
Vector2 local_coords = tile_set->map_to_local(kv.value->quadrant_coords);
411+
sortable_quadrant_keys.push_back(Pair<Vector2, Ref<RenderingQuadrant>>(local_coords, kv.value));
405412
}
413+
struct PairedQuadrantSorter {
414+
RenderingQuadrant::CoordsWorldComparator comparator;
415+
_ALWAYS_INLINE_ bool operator()(const Pair<Vector2, Ref<RenderingQuadrant>> &p_a, const Pair<Vector2, Ref<RenderingQuadrant>> &p_b) const {
416+
return comparator(p_a.first, p_b.first);
417+
}
418+
};
419+
sortable_quadrant_keys.sort_custom<PairedQuadrantSorter>();
406420

407-
// Sort the quadrants.
408-
for (const KeyValue<Vector2, Ref<RenderingQuadrant>> &E : local_to_map) {
409-
for (const RID &ci : E.value->canvas_items) {
421+
// Set the draw indices.
422+
for (const Pair<Vector2, Ref<RenderingQuadrant>> &E : sortable_quadrant_keys) {
423+
for (const RID &ci : E.second->canvas_items) {
410424
RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
411425
}
412426
}
@@ -429,14 +443,23 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
429443
}
430444
}
431445

446+
// -----------
447+
// Mark the rendering state as up to date.
448+
_rendering_was_cleaned_up = forced_cleanup;
449+
432450
// ----------- Occluders processing -----------
433-
if (forced_cleanup || !occlusion_enabled) {
451+
bool cleanup_occlusion = forced_cleanup || !occlusion_enabled;
452+
if (cleanup_occlusion && _occlusion_was_cleaned_up) {
453+
return;
454+
}
455+
456+
if (cleanup_occlusion) {
434457
// Clean everything.
435458
for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) {
436459
_rendering_occluders_clear_cell(kv.value);
437460
}
438461
} else {
439-
if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET]) {
462+
if (_occlusion_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET]) {
440463
// Update all cells.
441464
for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) {
442465
_rendering_occluders_update_cell(kv.value);
@@ -451,8 +474,8 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
451474
}
452475

453476
// -----------
454-
// Mark the rendering state as up to date.
455-
_rendering_was_cleaned_up = forced_cleanup || !occlusion_enabled;
477+
// Mark the occlusion state as up to date.
478+
_occlusion_was_cleaned_up = cleanup_occlusion;
456479
}
457480

458481
void TileMapLayer::_rendering_notification(int p_what) {
@@ -721,6 +744,9 @@ void TileMapLayer::_physics_update(bool p_force_cleanup) {
721744

722745
// Check if we should cleanup everything.
723746
bool forced_cleanup = p_force_cleanup || !enabled || !collision_enabled || !is_inside_tree() || tile_set.is_null();
747+
if (forced_cleanup && _physics_was_cleaned_up) {
748+
return;
749+
}
724750

725751
// ----------- Quadrants processing -----------
726752

@@ -732,7 +758,7 @@ void TileMapLayer::_physics_update(bool p_force_cleanup) {
732758
bool quadrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_PHYSICS_QUADRANT_SIZE];
733759

734760
// Free all quadrants.
735-
if (forced_cleanup || quadrant_shape_changed) {
761+
if (!_physics_was_cleaned_up && (forced_cleanup || quadrant_shape_changed)) {
736762
for (const KeyValue<Vector2i, Ref<PhysicsQuadrant>> &kv : physics_quadrant_map) {
737763
// Clear bodies.
738764
for (KeyValue<PhysicsQuadrant::PhysicsBodyKey, PhysicsQuadrant::PhysicsBodyValue> &kvbody : kv.value->bodies) {
@@ -940,7 +966,7 @@ void TileMapLayer::_physics_update(bool p_force_cleanup) {
940966

941967
// -----------
942968
// Mark the physics state as up to date.
943-
_physics_was_cleaned_up = forced_cleanup || !occlusion_enabled;
969+
_physics_was_cleaned_up = forced_cleanup;
944970
}
945971

946972
void TileMapLayer::_physics_quadrants_update_cell(CellData &r_cell_data, SelfList<PhysicsQuadrant>::List &r_dirty_physics_quadrant_list) {
@@ -1260,6 +1286,9 @@ void TileMapLayer::_navigation_update(bool p_force_cleanup) {
12601286

12611287
// Check if we should cleanup everything.
12621288
bool forced_cleanup = p_force_cleanup || !enabled || !navigation_enabled || !is_inside_tree() || tile_set.is_null();
1289+
if (forced_cleanup && _navigation_was_cleaned_up) {
1290+
return;
1291+
}
12631292

12641293
// ----------- Layer level processing -----------
12651294
// All this processing is kept for compatibility with the TileMap node.
@@ -1531,6 +1560,9 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V
15311560
void TileMapLayer::_scenes_update(bool p_force_cleanup) {
15321561
// Check if we should cleanup everything.
15331562
bool forced_cleanup = p_force_cleanup || !enabled || !is_inside_tree() || tile_set.is_null();
1563+
if (forced_cleanup && _scenes_was_cleaned_up) {
1564+
return;
1565+
}
15341566

15351567
if (forced_cleanup) {
15361568
// Clean everything.
@@ -1686,7 +1718,7 @@ void TileMapLayer::_build_runtime_update_tile_data(bool p_force_cleanup) {
16861718
}
16871719

16881720
// -----------
1689-
// Mark the navigation state as up to date.
1721+
// Mark the tile data state as up to date.
16901722
_runtime_update_tile_data_was_cleaned_up = forced_cleanup;
16911723
}
16921724

scene/2d/tile_map_layer.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -440,14 +440,15 @@ class TileMapLayer : public Node2D {
440440
// Per-system methods.
441441
#ifdef DEBUG_ENABLED
442442
HashMap<Vector2i, Ref<DebugQuadrant>> debug_quadrant_map;
443-
bool _debug_was_cleaned_up = false;
443+
bool _debug_was_cleaned_up = true;
444444
void _debug_update(bool p_force_cleanup);
445445
void _debug_quadrants_update_cell(CellData &r_cell_data);
446446
void _get_debug_quadrant_for_cell(const Vector2i &p_coords);
447447
#endif // DEBUG_ENABLED
448448

449449
HashMap<Vector2i, Ref<RenderingQuadrant>> rendering_quadrant_map;
450-
bool _rendering_was_cleaned_up = false;
450+
bool _rendering_was_cleaned_up = true;
451+
bool _occlusion_was_cleaned_up = true;
451452
void _rendering_update(bool p_force_cleanup);
452453
void _rendering_notification(int p_what);
453454
void _rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list);
@@ -460,7 +461,7 @@ class TileMapLayer : public Node2D {
460461
#ifndef PHYSICS_2D_DISABLED
461462
HashMap<Vector2i, Ref<PhysicsQuadrant>> physics_quadrant_map;
462463
HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords.
463-
bool _physics_was_cleaned_up = false;
464+
bool _physics_was_cleaned_up = true;
464465
void _physics_update(bool p_force_cleanup);
465466
void _physics_notification(int p_what);
466467
void _physics_quadrants_update_cell(CellData &r_cell_data, SelfList<PhysicsQuadrant>::List &r_dirty_physics_quadrant_list);
@@ -472,7 +473,7 @@ class TileMapLayer : public Node2D {
472473
#endif // PHYSICS_2D_DISABLED
473474

474475
#ifndef NAVIGATION_2D_DISABLED
475-
bool _navigation_was_cleaned_up = false;
476+
bool _navigation_was_cleaned_up = true;
476477
void _navigation_update(bool p_force_cleanup);
477478
void _navigation_notification(int p_what);
478479
void _navigation_clear_cell(CellData &r_cell_data);
@@ -482,7 +483,7 @@ class TileMapLayer : public Node2D {
482483
#endif // DEBUG_ENABLED
483484
#endif // NAVIGATION_2D_DISABLED
484485

485-
bool _scenes_was_cleaned_up = false;
486+
bool _scenes_was_cleaned_up = true;
486487
void _scenes_update(bool p_force_cleanup);
487488
void _scenes_clear_cell(CellData &r_cell_data);
488489
void _scenes_update_cell(CellData &r_cell_data);

0 commit comments

Comments
 (0)