From b3ec8edc87ece404b5f7b3706f5acf2a70de6862 Mon Sep 17 00:00:00 2001 From: tei Date: Thu, 24 Sep 2026 14:39:39 +0900 Subject: [PATCH] feat: add STEP-093 runtime validation tooling --- include/mbgl/renderer/retained_underlay.hpp | 18 + .../MapLibreParticleRNTestHost/App.tsx | 8 + .../weather/WeatherRuntimeBridgeModule.kt | 20 +- .../ios/WeatherRuntimeBridge.mm | 21 +- .../src/NativeWeatherRuntimeBridge.ts | 10 +- packages/maplibre-particle-rn/src/types.ts | 19 + .../src/cpp/native_map_view.cpp | 21 +- .../maps/RetainedUnderlayDiagnostics.java | 62 ++- .../src/main/AndroidManifest.xml | 1 + .../ParticleCoreLayerValidationActivity.kt | 405 +++++++++++++++++- ...ctivity_particle_core_layer_validation.xml | 2 + platform/ios/src/MLNMapView.h | 19 + platform/ios/src/MLNMapView.mm | 26 ++ src/mbgl/renderer/particle_fast_path.hpp | 6 + src/mbgl/renderer/renderer_impl.cpp | 6 + src/mbgl/renderer/renderer_impl.hpp | 1 + src/mbgl/renderer/retained_underlay_cache.cpp | 16 + src/mbgl/renderer/retained_underlay_cache.hpp | 5 + .../retained_underlay_runtime_state.hpp | 78 ++++ .../renderer/retained_underlay_cache.test.cpp | 45 ++ 20 files changed, 765 insertions(+), 24 deletions(-) diff --git a/include/mbgl/renderer/retained_underlay.hpp b/include/mbgl/renderer/retained_underlay.hpp index 87a192605..4dfd3d28a 100644 --- a/include/mbgl/renderer/retained_underlay.hpp +++ b/include/mbgl/renderer/retained_underlay.hpp @@ -19,15 +19,33 @@ struct RetainedUnderlayDiagnostics { std::string endLayerId; int32_t startIndex = -1; int32_t endIndex = -1; + int32_t continuousBegin = -1; + int32_t continuousEndExclusive = -1; bool bottomPresent = false; + std::string bottomCacheState{"disabled"}; uint64_t bottomBuild = 0; uint64_t bottomReuse = 0; uint64_t bottomInvalidation = 0; + std::string bottomLastInvalidationReason{"none"}; + uint64_t bottomTextureCreate = 0; + uint64_t bottomCompositeCreate = 0; + uint64_t bottomResourceRelease = 0; bool topPresent = false; + std::string topCacheState{"disabled"}; uint64_t topBuild = 0; uint64_t topReuse = 0; uint64_t topInvalidation = 0; + std::string topLastInvalidationReason{"none"}; + uint64_t topTextureCreate = 0; + uint64_t topCompositeCreate = 0; + uint64_t topResourceRelease = 0; bool rangeFallback = false; + bool fastPathEligible = false; + bool fastPathActive = false; + std::string fastPathFallbackReason{"no-prepared-tree"}; + uint64_t fastPathHit = 0; + uint64_t fastPathMiss = 0; + uint64_t fullCpuFrame = 0; }; struct ContinuousLayerRangeConfig { diff --git a/integration/react-native/MapLibreParticleRNTestHost/App.tsx b/integration/react-native/MapLibreParticleRNTestHost/App.tsx index a253c8e64..f56283df3 100644 --- a/integration/react-native/MapLibreParticleRNTestHost/App.tsx +++ b/integration/react-native/MapLibreParticleRNTestHost/App.tsx @@ -364,6 +364,14 @@ export default function App() { Retained: {retainedSnapshot == null ? "not read" : `${retainedSnapshot.enabled ? "ON" : "OFF"} build=${retainedSnapshot.build} reuse=${retainedSnapshot.reuse} fallback=${retainedSnapshot.fallback} invalidation=${retainedSnapshot.invalidation} reason=${retainedSnapshot.lastReason}`} + {retainedSnapshot != null && ( + + {`Range ${retainedSnapshot.rangeValid ? "VALID" : "INVALID"} [${retainedSnapshot.startIndex},${retainedSnapshot.endIndex}] continuous=[${retainedSnapshot.continuousBegin},${retainedSnapshot.continuousEndExclusive})\n`} + {`Bottom ${retainedSnapshot.bottomPresent ? retainedSnapshot.bottomCacheState : "absent"} b/r/i=${retainedSnapshot.bottomBuild}/${retainedSnapshot.bottomReuse}/${retainedSnapshot.bottomInvalidation} tex/comp/rel=${retainedSnapshot.bottomTextureCreate}/${retainedSnapshot.bottomCompositeCreate}/${retainedSnapshot.bottomResourceRelease}\n`} + {`Top ${retainedSnapshot.topPresent ? retainedSnapshot.topCacheState : "absent"} b/r/i=${retainedSnapshot.topBuild}/${retainedSnapshot.topReuse}/${retainedSnapshot.topInvalidation} tex/comp/rel=${retainedSnapshot.topTextureCreate}/${retainedSnapshot.topCompositeCreate}/${retainedSnapshot.topResourceRelease}\n`} + {`Fast eligible=${retainedSnapshot.fastPathEligible} active=${retainedSnapshot.fastPathActive} hit/miss/full=${retainedSnapshot.fastPathHit}/${retainedSnapshot.fastPathMiss}/${retainedSnapshot.fullCpuFrame} reason=${retainedSnapshot.fastPathFallbackReason}`} + + )}