Helium314 / SCEE

OpenStreetMap surveyor app for experienced OSM contributors
GNU General Public License v3.0
116 stars 8 forks source link

Maplibre #516

Closed Helium314 closed 3 weeks ago

Helium314 commented 4 months ago

For simple comparison with master, and for discussions.

to do

to do SCEE

upstream blockers


old observations below

Performance regarding icons (symbol layers, mostly about quest pins):

Other things:

Helium314 commented 2 months ago

It's not really important to be done immediately on start, we could e.g. delay it by 30 seconds.

I'll do this, and also upgrade to pre-6

Helium314 commented 2 months ago

maybe https://github.com/maplibre/maplibre-native/issues/2217 is fixed

I guess so, looks good now.

Helium314 commented 2 months ago

preset icons in shop overlay do not appear

Look like it's related to text. All overlays work, except places and addresses. Found 2 places in places overlay, a clothing shop and a vacant shop, both without a name. However, when I create a vacant or clothing shop it's not displayed in the overlay.

Helium314 commented 2 months ago

There is some other issue related to text. There are no addresses displayed at all, there are very few road names, and road names are hidden by quest dots (but not by the pins).

westnordost commented 2 months ago

Is this caused by pre6? I hope so, otherwise it is might be some weird device-specific issue that is more difficult to find :-/

Helium314 commented 2 months ago

Also happens on pre-5. I'll try and go back to older versions to maybe find where it stopped working.

btw not loading any icons at all results in the map being displayed ~5 seconds after tapping the icon, instead of 6. So I get the impression there is limited gain from making everything run in parallel. For fast phones it's much faster anyway (as you reported), and slow phones probably don't have any unused of their 2-4 cores anyway (during startup).

Helium314 commented 2 months ago

[edit: nope, need to re-check it... actually it's working with de7bd79e8f87a9c278c05761655c5b8c9383b936. I'm confused, but ok.]

Helium314 commented 2 months ago

Weird thing. Apparently got fixed by going back to an older state... Everything working now on a fresh install.

Screenshot_20240420-085050_Street­Complete_Dev

Helium314 commented 2 months ago

Btw iconAllowOverlap for overlays is true only at z19, while the + button is already enabled at z18. I think the zoom levels should be aligned to avoid users not seeing mapped things and adding duplicates.

Helium314 commented 2 months ago

The overlay weirdness I sometimes noticed (see first post) is reproducible, at least for me:

  1. Enable address overlay, notice addresses do not show. (on this step it really has to be address overlay)
  2. Switch to other overlay, notice it does not show.
  3. Zoom in or out to another zoom level, overlay shows up.
  4. Zoom back to original zoom, overlay is gone again.
  5. Pan the map and notice the overlay is showing in other tiles.
westnordost commented 2 months ago

Oh dear, I surely hope that the issue is on our end, because that sounds like a hell of a bug, difficult to debug / prove/reproduce to maplibre maintainers.

Two ideas:

westnordost commented 2 months ago

The screenshot from https://github.com/Helium314/SCEE/pull/516#issuecomment-2067581158 is from current HEAD of this branch?

Helium314 commented 2 months ago

The screenshot from https://github.com/Helium314/SCEE/pull/516#issuecomment-2067581158 is from current HEAD of this branch?

Yes, I think you were asking for this in the SDF branch.

It is the only overlay that hides another layer when it is activated and un-hides when it is turned off. You could try commenting out this behavior to find if the issue is somehow caused by that.

Thanks! I guess that's a good place to start checking.

Helium314 commented 2 months ago

It is the only overlay that hides another layer when it is activated and un-hides when it is turned off. You could try commenting out this behavior to find if the issue is somehow caused by that.

Commenting override val hidesLayers = listOf("labels-housenumbers") didn't help.

I even did a fresh install to make sure eveything is working / using only fresh data, only to stumble across the missing place overlay icons again... arrrgh

westnordost commented 2 months ago

So, it can be reproduced without the address overlay?

Helium314 commented 2 months ago

So, it can be reproduced without the address overlay?

No, it only happens with the address overlay. But it happens even when I remove the hidesLayers val that makes the address overlay unique in some sense.

Helium314 commented 2 months ago

No, it only happens with the address overlay. But it happens even when I remove the hidesLayers val that makes the address overlay unique in some sense.

But interestingly when I comment the code in MainMapFragment.onSelectedOverlayChanged it works. Even though as far as I understand this should have the same effect as previouslyHiddenLayers is always an empty list. At this point (also considering my place overlay icons not showing bug) I'm not sure whether I want to trust the phone...

[edit: or possibly I shouldn't trust launching the app from Android Studio without a clean build?]

Helium314 commented 2 months ago

I would really like to understand this. I added a short delay between setting layer visibilities in MainMapFragment.onSelectedOverlayChanged, and it worked, Then I removed the delay (reverted all my changes), uninstalled the app, and did a clean build and it still worked. I don't understand it at all.

westnordost commented 2 months ago

It looks like a Heisenbug, then. I have to admit, I noticed this bug on my phone, also. I disregarded it then, because I was busy looking into other stuff and - one issue at a time. I think I remember that there was even an issue with quest pins, i.e. the circles were displayed but not the icons. Maybe I changed addImagesAsync to addImages or maybe I didn't do anything, then, don't quite remember. In any case, I disregarded it then because it looked like rather an issue with the *Manager class(es) which you were working on making superfluous at that time.

So, it seems worthwhile to me to prove that the *Manager classes cannot be the source of the bug before diving deeper into this. I.e. is the area that ought to be displayed retrieved by the manager? Is there anything we can say for sure about when or when the bug is reproducible? Doing clean Android build sounds like a good idea. Also, the thing with the manager,

Helium314 commented 2 months ago

Is there anything we can say for sure about when or when the bug is reproducible?

Not at all... Maybe it's still ok to put a small delay between setting layers visible and invisible? But currently I think this cannot actually have had any effect, because all overlays either hide nothing, or the housenumbers layer. In both cases, either nothing is set visible or nothing is set invisible, and thus the delay in between cannot make things suddenly work.

Do you have any idea where logging could be added that might help finding a pattern? I'm pretty certain the data is retrieved by the manager, but will add some test logging there.

Helium314 commented 2 months ago

quest pins: try replacing quest dots with clustering

I played a little with clustering, but without any results other than seeing fewer pins... My guess is that a key is withClusterProperty, but I don't understand it and couldn't find any example to copy from.

westnordost commented 2 months ago

Maybe this is helpful? https://maplibre.org/maplibre-gl-js/docs/examples/cluster/

After all, all this Java typesafe API just wraps the JS/JSON-based api on maplibre-gl-js.

Is there anything we can say for sure about when or when the bug is reproducible?

Not at all...

Well. If we can't know the shape of the bug, maybe we can first ascertain what shape it isn't. It's not spherical, right? (I can very much recommend the short stories in the Antimemetics Division hub if you like this kind of literature, the stories by qntm have even been published as a book)

So, that's why I suggested to first check if the error could lie in the Managers, because if it doesn't, we can already exclude that as the source and move on.

Does it also affect quest pins? If not, we can check what are the differences between quest pins and icons in overlays. The halo? The fact that they are SDFs? The fact that they have (sometimes) text? Etc., and so you can cross off one possible cause after another after the number of suspects becomes smaller and smaller.

westnordost commented 2 months ago

This video shows the bug you (and I) are seeing, right?

https://github.com/Helium314/SCEE/assets/4661658/090a86ca-f636-4adc-b97f-c3de82a1dc32

Helium314 commented 2 months ago

This video shows the bug you (and I) are seeing, right?

Not really. For you, there are just a few icons missing. The issue I had was no icons and no text, except for very few icons. Both of them had no name, thus no text to be expected. But other place icons without name were not shown, so it's not only connected to this.

Does it also affect quest pins?

No, pins have always been ok for me. It also happened before the SDF PR, and I think I had tried playing with halos as well. But since when it works I never know whether a change I made is responsible, I only can write down what I had when it didn't work.I'm ready for this, but now waiting for the bug to show up again...

westnordost commented 2 months ago

To clarify, what I can very well reproduce in the emulator is the following:

  1. Switch on places overlay (same issue with things overlay)
  2. pan around a lot. Eventually, some areas will have no icons. Sometimes, already areas that had icons will have no icons anymore when scrolling back.

I played around with it, disabled one feature after another until only simple icons+text for these icons was displayed. I.e. the following things can not be the cause of this because when disabling, the bug as shown in the above video persists:

Furthermore, I added a log whenever a StyleableOverlayManager::onNewTilesRect is called, and as it turns out, the bug appearing (or disappearing again), i.e. icons not showing or suddenly showing after all coincides with calls to this function.

So, it is very likely that the issue is in StyleableOverlayManager, or otherwise in MapLibre, but very unlikely in the style or how certain properties of the style are handled by MapLibre. The manager does have a lot of concurrency, maybe some assumptions that were true with tangram-es don't hold true for MapLibre anymore. Or maybe, it is even a race condition in MapLibre - e.g. the geojson is still being built when a new geojson should be pushed or something.

All I can say for almost certain at the moment is that the issue is definitely triggered by StyleableOverlayManager::onNewTilesRect, whether the root issue lies in the manager, too, is something to be found out.

Helium314 commented 2 months ago

The manager does have a lot of concurrency, maybe some assumptions that were true with tangram-es don't hold true for MapLibre anymore. Or maybe, it is even a race condition in MapLibre - e.g. the geojson is still being built when a new geojson should be pushed or something.

That's a good point. I vaguely remember when I added the updateJob that you said something like you only accept it because tangram is really slow when updating. This doesn't hold for MapLibre (well, maybe it does, but MapLibre internal stuff is happening on a different thread). So we could try getting rid of the updateJob and see how it goes.

Btw in case we get bored by the lack of hard to reproduce bugs: I just had a case when after a theme switch the quest pins were gone in some tiles, but not others. Circles were still there. Not sure what triggers it, so here what I know:

westnordost commented 2 months ago

I see, well, it is a *Manager, too. Maybe same root problem (that for some reason surfaces much more infrequently on the pins layer)

westnordost commented 2 months ago

I am looking into the *Manager now to see if I find the cause of this.

westnordost commented 2 months ago

Well, I didn't really find anything conclusive today. I found and fixed a few other things, as well as added performance improvements:

I noticed another possible performance improvement, but I am not sure how big it would be, if it will have a measurable effect. I didn't notice anything on my phone, but then again I have no performance issues at all. Currently, the sorting of quests plus creation of a GeoJson data structure is done on the UI thread. Same with overlays: The styled elements are mapped to GeoJson data structure on the UI thread. (StyledElement.toFeatures(), Pin.toFeature())

Maybe you could try if this makes any difference on an older phone? I committed the change that puts the load on a background thread in the maplibre-suspend-components branch (in your repo).

Helium314 commented 2 months ago

Maybe you could try if this makes any difference on an older phone?

I'll give it a try tomorrow at best. Currently I'm in the process of switching to a different PC, and now I'm blocked by an extremely tightened screw holding the SSD in place...

westnordost commented 2 months ago

Currently I'm in the process of switching to a different PC, and now I'm blocked by an extremely tightened screw holding the SSD in place...

😅


I created an issue for what I found regarding the vanishing icons:

I am not sure if this is the same issue you have been encountering. But on my phone, I cannot reproduce it, while on the emulator, I very reliably can.

The only thing I once or twice observed on my phone is that after install and launch of the app, some quest pins were missing while the quest dots were still visible. Not all quest pins were missing, only some. So, this sounds very much like exactly https://github.com/maplibre/maplibre-native/issues/2372 , with the difference that by zooming in, the quest pins didn't eventually appear at all (I didn't try zooming out). On the other hand, there seems to be no issue with quest pins on the emulator - which is weird, because they are just as much simple icons as the preset icons...

I also spent most of the day researching cause for issues that make it pretty impossible to test MapLibre on emulators, hmm 😕:

westnordost commented 2 months ago

I also encountered this crash right now when I reentered the app after having it lying around long. Didn't investigate much further, something with Offline Regions. That's by now almost the only area I didn't get acquainted with.

Process: de.westnordost.streetcomplete.debug, PID: 5230
java.lang.IllegalStateException: Already resumed
    at kotlin.coroutines.SafeContinuation.resumeWith(SafeContinuationJvm.kt:44)
    at de.westnordost.streetcomplete.screens.main.map.maplibre.OfflineManagerKt$awaitDownload$2$1.onStatusChanged(OfflineManager.kt:81)
    at org.maplibre.android.offline.OfflineRegion$setObserver$1.onStatusChanged$lambda$0(OfflineRegion.kt:249)
    at org.maplibre.android.offline.OfflineRegion$setObserver$1.$r8$lambda$rUt7TfKIBCanK55ACsV3Si7sCqg(OfflineRegion.kt:0)
    at org.maplibre.android.offline.OfflineRegion$setObserver$1$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:0)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Helium314 commented 2 months ago

I also encountered this crash right now when I reentered the app after having it lying around long. Didn't investigate much further, something with Offline Regions. That's by now almost the only area I didn't get acquainted with.

I never had this, but looks like onStatusChanged may be called with status.isComplete more than once for some reason.

Helium314 commented 2 months ago

Maybe you could try if this makes any difference on an older phone?

On the A3 there is no noticeable difference. Creating mapLibreFeatures for ~1000 pins usually takes between 5 and 15 ms, for ~1000 overlay features it's between 15 and 25 ms. [edit: measured time is about the same with and without suspend-component changes]

westnordost commented 2 months ago

Thanks! So I'll not pursue this further. I didn't commit it to the maplibre branch because I was not sure if it would be clean to have all these functions suspend. (Measured time is not meaningful here though, as it doesn't take less time, only less things are done on the UI thread. It's more about whether map updates look smooth or not.)

Helium314 commented 1 month ago

I also encountered this crash right now when I reentered the app after having it lying around long. Didn't investigate much further, something with Offline Regions. That's by now almost the only area I didn't get acquainted with.

The crash can be reproduced by starting a dowload where you don't already have map tiles, and disabling network connection right after start. Then both onError and onStatusChanged with status complete are called, which triggers the crash. The only solution I currently see is using a var resumed: Boolean to avoid resuming twice.

westnordost commented 1 month ago

Cool, thank you for investigating this! I guess this is expected behavior of MapLibre, because the status when an error is encountered does change - the download state becomes inactive.

westnordost commented 1 month ago

I think awaitDownload is also wrong for other reasons: It adds an observer to the OfflineRegion, but never removes the observer. So, I figure that this could/should also be solved by removing the observer once the first callback has been received.

(The API is a little odd here, all other methods accept an observer within the startDoingSomething method itself)

Helium314 commented 1 month ago

if quest pin size has considerable impact on performance with MapLibre, a SCEE setting to half the size of quest pins would be conceivable (maybe some sort of ancient-phone-mode)

I'd like to try this on my S4 Mini, but even on much faster A3 there is a noticeably difference. Shrinking the bitmaps to 25%, and increasing the symbol scale and offsets accordingly, results in clearly smoother zooming, especially when zooming out at low zoom levels when pins start disappearing.

westnordost commented 1 month ago

Oh, so the performance issue scales with the size of the source bitmap, rather than the actually displayed size of the bitmap?

westnordost commented 1 month ago

By the way, we may need to downgrade maplibre to v10 again because of the two critical issues. Specificall, I don't expect the (for us) more critical issue of some icons sometimes not being displayed to get any love soon, as it has been flagged as a simulator(only) issue. Is there anything that we absolutely need from v11?

Helium314 commented 1 month ago

Oh, so the performance issue scales with the size of the source bitmap, rather than the actually displayed size of the bitmap?

Yes, definitely. You can probably trigger performance issues on your phone by increasing scale in MapIcons, and dividing iconSize and multiplying iconOffset in PinsMapComponent by the same factor.

Is there anything that we absolutely need from v11?

I don't think so. I really hope the icon issue is not also present in v10 and we just overlooked it...

westnordost commented 1 month ago

Actually, when I set the scale to anything above 3f, I get an OOM exception. I compared 3f with 1f and I am not sure, maybe there is a little difference.

westnordost commented 1 month ago

I set the pin icon scale to 1 now. Better?

westnordost commented 1 month ago

(missed the comment button)

westnordost commented 1 month ago

Hmm, if we indeed only show clusters below a certain zoom level, e.g. 16, and above that use dots for pins that don't fit (I guess the dots could also be clickable and zoom in), we'd win back that the total amount of quests is shown for the clusters, not just the number of pins. Also, we save copying all to-be-displayed pins into a Set and then also to a new List (that's what distinctBy does).

This has a few minor advantages too:

Arguably, the clusters at zoom 16 are also not all that interesting. For me, it mostly displays numbers between 2 and 4. Could just as well go with dots here.

We could also make the pin layer visible one or two zoom levels earlier (and fetch the data also at lower zoom levels). I tried it out, the performance is fine on my phone, but it should only be done if it is also smooth on yours.

Helium314 commented 1 month ago

Also, we save copying all to-be-displayed pins into a Set and then also to a new List (that's what distinctBy does).

I already had a look at this when I did the change, and found that it's ok even for many pins. Probably also for slower phones.

Arguably, the clusters at zoom 16 are also not all that interesting. For me, it mostly displays numbers between 2 and 4. Could just as well go with dots here.

Agree.

We could also make the pin layer visible one or two zoom levels earlier (and fetch the data also at lower zoom levels). I tried it out, the performance is fine on my phone, but it should only be done if it is also smooth on yours.

With one level earlier it's a noticeable difference, but could still be fine.

Helium314 commented 1 month ago

Btw for the same map area, with MapLibre much less detail is shown than with Tangram, especially fewer low priority roads: sc_maplibre sc_tangram

Possibly this is intended, but it might be bad for using SC in rural areas, forests or mountains.

westnordost commented 1 month ago

That's probably kind of intended and is likely due to the fade-in I added. I.e. many roads do not become visible immediately but fade in from 0% alpha to 100% alpha from e.g. zoom 12 to 13 (etc.)

Helium314 commented 1 month ago

clear cache directory after upgrade to MapLibre (aka clean old tiles folder)

I remember having issues with tile cache not being cleared (fully?) when it contained a lot of files. Maybe to be safe we should clear the folder more often than just on upgrade? There should not be any side effects when it's empty anyway.