From 2ebe9d21bd2810bdfbb60ef53d0863708bdad3b3 Mon Sep 17 00:00:00 2001 From: liu weikai Date: Tue, 16 Jun 2026 22:26:59 +0800 Subject: [PATCH] fix(esp): stabilize map tile cache and boot flush --- .../src/ui/runtime/memory_profile.cpp | 4 +- .../include/ui/widgets/map/map_tiles.h | 2 +- .../src/ui/widgets/map/map_tiles.cpp | 62 ++++++++++++++++--- .../boards/src/display/DisplayInterface.cpp | 4 +- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/modules/ui_shared/src/ui/runtime/memory_profile.cpp b/modules/ui_shared/src/ui/runtime/memory_profile.cpp index 69f3519e..72abf74b 100644 --- a/modules/ui_shared/src/ui/runtime/memory_profile.cpp +++ b/modules/ui_shared/src/ui/runtime/memory_profile.cpp @@ -26,8 +26,8 @@ MemoryProfile make_standard_profile() profile.max_locale_font_ram_bytes = 768U * 1024U; profile.max_content_supplement_ram_bytes = 640U * 1024U; profile.max_content_supplement_packs = 2; - // 320x240 touch map views need 6 visible 256px tiles plus pan cushion. - profile.max_map_decode_tiles = 9; + // 320x240 and pager touch map views need visible 256px tiles plus pan cushion. + profile.max_map_decode_tiles = 12; profile.retain_map_decode_cache_on_page_exit = false; return profile; } diff --git a/platform/esp/arduino_common/include/ui/widgets/map/map_tiles.h b/platform/esp/arduino_common/include/ui/widgets/map/map_tiles.h index 5ba6d7a2..d68ea085 100644 --- a/platform/esp/arduino_common/include/ui/widgets/map/map_tiles.h +++ b/platform/esp/arduino_common/include/ui/widgets/map/map_tiles.h @@ -48,7 +48,7 @@ struct DecodedTileCache ui::map_tiles::MapTileLayer layer; // Base or contour layer represented by this cache entry lv_image_dsc_t* img_dsc; // Decoded image descriptor (RGB565 data in RAM) uint32_t last_used_ms; // For LRU eviction - bool bound_to_lvgl_object; // True while referenced by a live LVGL image object + uint8_t lvgl_ref_count; // Number of live LVGL image objects referencing img_dsc }; // Map tile structure diff --git a/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp b/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp index fa796ee1..fc503eb3 100644 --- a/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp +++ b/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp @@ -1100,7 +1100,7 @@ class LvglDecodedTileCache final : public ui::map_tiles::IMapTileDecoderCache { return &slots_[i]; } - if (!slots_[i].bound_to_lvgl_object) + if (slots_[i].lvgl_ref_count == 0) { found_unused = true; if (slots_[i].last_used_ms < oldest_ms) @@ -1141,7 +1141,7 @@ class LvglDecodedTileCache final : public ui::map_tiles::IMapTileDecoderCache const uint32_t now_ms = sys::millis_now(); for (std::size_t i = 0; i < kCapacity; ++i) { - slots_[i].bound_to_lvgl_object = false; + slots_[i].lvgl_ref_count = 0; if (slots_[i].img_dsc != NULL) { slots_[i].last_used_ms = now_ms; @@ -1187,7 +1187,7 @@ class LvglDecodedTileCache final : public ui::map_tiles::IMapTileDecoderCache slot.layer = ui::map_tiles::MapTileLayer::Osm; slot.img_dsc = NULL; slot.last_used_ms = 0; - slot.bound_to_lvgl_object = false; + slot.lvgl_ref_count = 0; } mutable DecodedTileCache slots_[kCapacity]{}; @@ -1716,6 +1716,15 @@ static DecodedTileCache* get_lru_cache_slot(size_t active_limit) return decoded_tile_cache().acquireSlot(active_limit); } +static bool cache_matches_ref(const DecodedTileCache& cache, + const ui::map_tiles::MapTileRef& ref) +{ + return cache.x == static_cast(ref.x) && + cache.y == static_cast(ref.y) && + cache.z == static_cast(ref.z) && + cache.layer == ref.layer; +} + /** * Normalize tile coordinates to valid range (wrap x, clamp y) */ @@ -2049,7 +2058,10 @@ static void release_tile_decoded_cache(MapTile& tile) { if (tile.cached_img != NULL) { - tile.cached_img->bound_to_lvgl_object = false; + if (tile.cached_img->lvgl_ref_count > 0) + { + --tile.cached_img->lvgl_ref_count; + } tile.cached_img = NULL; } } @@ -2058,7 +2070,10 @@ static void release_contour_decoded_cache(MapTile& tile) { if (tile.contour_cached_img != NULL) { - tile.contour_cached_img->bound_to_lvgl_object = false; + if (tile.contour_cached_img->lvgl_ref_count > 0) + { + --tile.contour_cached_img->lvgl_ref_count; + } tile.contour_cached_img = NULL; } } @@ -2066,7 +2081,10 @@ static void release_contour_decoded_cache(MapTile& tile) static void bind_tile_decoded_cache(MapTile& tile, DecodedTileCache& cache) { release_tile_decoded_cache(tile); - cache.bound_to_lvgl_object = true; + if (cache.lvgl_ref_count < UINT8_MAX) + { + ++cache.lvgl_ref_count; + } cache.last_used_ms = sys::millis_now(); tile.cached_img = &cache; } @@ -2074,7 +2092,10 @@ static void bind_tile_decoded_cache(MapTile& tile, DecodedTileCache& cache) static void bind_contour_decoded_cache(MapTile& tile, DecodedTileCache& cache) { release_contour_decoded_cache(tile); - cache.bound_to_lvgl_object = true; + if (cache.lvgl_ref_count < UINT8_MAX) + { + ++cache.lvgl_ref_count; + } cache.last_used_ms = sys::millis_now(); tile.contour_cached_img = &cache; } @@ -2095,7 +2116,6 @@ static void touch_tile_decoded_cache(MapTile& tile) } else if (tile.cached_img != NULL) { - tile.cached_img->bound_to_lvgl_object = true; tile.cached_img->last_used_ms = sys::millis_now(); } @@ -2105,7 +2125,6 @@ static void touch_tile_decoded_cache(MapTile& tile) } else if (tile.contour_cached_img != NULL) { - tile.contour_cached_img->bound_to_lvgl_object = true; tile.contour_cached_img->last_used_ms = sys::millis_now(); } } @@ -2396,7 +2415,7 @@ static DecodedTileCache* decode_payload_to_cache(TileContext& ctx, cache_slot->layer = ref.layer; cache_slot->map_source = map_source_for_layer(ref.layer); cache_slot->last_used_ms = sys::millis_now(); - cache_slot->bound_to_lvgl_object = false; + cache_slot->lvgl_ref_count = 0; lv_image_decoder_close(&decoder_dsc); return cache_slot; @@ -2409,6 +2428,17 @@ static bool render_base_tile_from_cache(TileContext& ctx, MapTile& tile, Decoded return false; } + const ui::map_tiles::MapTileRef expected_ref = base_tile_ref_for_tile(tile); + if (!cache_matches_ref(cache, expected_ref)) + { + log_map_tile_decode_failure("cache_ref_mismatch", + expected_ref, + ui::map_tiles::MapTileFormat::Unknown, + 0, + static_cast(cache.layer)); + return false; + } + int screen_x = 0; int screen_y = 0; if (!tile_screen_pos_xyz(ctx, tile.x, tile.y, tile.z, screen_x, screen_y)) @@ -2461,6 +2491,18 @@ static bool render_contour_from_cache(MapTile& tile, DecodedTileCache& cache) return false; } + ui::map_tiles::MapTileRef expected_ref{}; + if (!contour_tile_ref(tile.z, static_cast(tile.x), static_cast(tile.y), expected_ref) || + !cache_matches_ref(cache, expected_ref)) + { + log_map_tile_decode_failure("contour_cache_ref_mismatch", + expected_ref, + ui::map_tiles::MapTileFormat::Unknown, + 0, + static_cast(cache.layer)); + return false; + } + if (tile.contour_obj == NULL) { tile.contour_obj = lv_image_create(tile.img_obj); diff --git a/platform/esp/boards/src/display/DisplayInterface.cpp b/platform/esp/boards/src/display/DisplayInterface.cpp index 8b23acc4..07ddf279 100644 --- a/platform/esp/boards/src/display/DisplayInterface.cpp +++ b/platform/esp/boards/src/display/DisplayInterface.cpp @@ -13,8 +13,8 @@ static LilyGoDispArduinoSPI* g_display_spi = nullptr; namespace { -constexpr TickType_t kDisplayFrameLockWait = 0; -constexpr TickType_t kDisplayControlLockWait = pdMS_TO_TICKS(80); +constexpr TickType_t kDisplayFrameLockWait = pdMS_TO_TICKS(8); +constexpr TickType_t kDisplayControlLockWait = pdMS_TO_TICKS(50); constexpr uint32_t kDisplayLockTimeoutLogIntervalMs = 1000; uint32_t s_last_display_lock_timeout_log_ms = 0;