App 2.40.2: the Grid map moves on the GPU

The map was hardware-rendered, but every frame recomputed every road
point, rebuilt every path and drew the big roads three times, at 20
frames a second, and the car jumped with each GPS fix. Now it is its own
view under the Grid (MapLayerView, a hardware layer): drawn once into a
GPU texture and only redrawn when tiles change or after about 230 m;
each display frame only sets its translation and rotation. The car
glides between fixes, and the Grid over the map redraws only with the
readings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
2026-10-27 00:32:50 +01:00
co-authored by Claude Opus 5.5
parent c3c47f5159
commit f7c489858e
7 changed files with 293 additions and 129 deletions
@@ -65,6 +65,8 @@ final class MapRoads {
return t;
});
private volatile Fix fix;
/** Goes up whenever a tile arrives or is dropped, so a view knows to rebuild its shapes. */
private volatile int version;
/** The last bearing while moving; GPS has none at a standstill. */
private volatile float bearing = Float.NaN;
private volatile boolean serverMissing;
@@ -100,6 +102,10 @@ final class MapRoads {
return f == null || SystemClock.elapsedRealtime() - f.elapsedMs > FIX_FRESH_MS ? null : f;
}
int version() {
return version;
}
Collection<RoadTile> tiles() {
return tiles.values();
}
@@ -116,7 +122,10 @@ final class MapRoads {
/** Queues the 3×3 tiles round (cx, cy), the car's own first, and forgets far ones. */
private void want(int cx, int cy) {
for (Long key : tiles.keySet()) {
if (Math.abs(MapGeometry.keyX(key) - cx) > 2 || Math.abs(MapGeometry.keyY(key) - cy) > 2) tiles.remove(key);
if (Math.abs(MapGeometry.keyX(key) - cx) > 2 || Math.abs(MapGeometry.keyY(key) - cy) > 2) {
tiles.remove(key);
version++;
}
}
int[][] order = { {0, 0}, {0, -1}, {1, 0}, {0, 1}, {-1, 0}, {1, -1}, {1, 1}, {-1, 1}, {-1, -1} };
long now = SystemClock.elapsedRealtime();
@@ -152,6 +161,7 @@ final class MapRoads {
}
if (cached != null) {
tiles.put(key, cached);
version++;
if (System.currentTimeMillis() - file.lastModified() < DISK_AGE_MS) return;
}
ServerConfig config = ServerConfig.get(context);
@@ -172,6 +182,7 @@ final class MapRoads {
}
failedAt.remove(key);
tiles.put(key, tile);
version++;
save(file, r.body);
} catch (Exception e) {
Log.w(TAG, "Map tile not loaded: " + e.getClass().getSimpleName());