Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix terrain cache not updating on setFeatureState #11209

Merged
merged 6 commits into from
Nov 4, 2021

Conversation

SnailBones
Copy link
Contributor

@SnailBones SnailBones commented Nov 3, 2021

Closes https://github.com/mapbox/gl-js-team/issues/312

Currently, feature-state doesn't update on terrain until the map is zoomed a certain amount (possibly an integer zoom level).Demonstration here.

This is because the terrain render cache doesn't update. This P.R. fixes that.

This issue is a regression introduced in 2.4, probably from #10701. #10302 may be a related issue, but predates this regression.

Launch Checklist

  • briefly describe the changes in this PR
  • include before/after visuals or gifs if this PR includes visual changes
  • write tests for all new functionality
  • manually test the debug page
  • tagged @mapbox/gl-native if this PR includes shader changes or needs a native port
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog>Fixes feature-state not updating when terrain is enabled.</changelog>

Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I think this fix is valid, but I left a comment to investigate whether we could be more granular in the way we invalidate the cache.

src/terrain/terrain.js Outdated Show resolved Hide resolved
@@ -1120,6 +1120,7 @@ class Style extends Evented {
for (const sourceCache of sourceCaches) {
sourceCache.setFeatureState(sourceLayer, target.id, state);
}
this.fire(new Event('setfeaturestate'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix should also apply when removeFeatureState is called to clear a value. When you do that, maybe a different name is appropriate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch @asheemmamoowala!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimnaaji Thoughts on how to get this behavior working now that this is no longer using events? Should removeFeatureState call a new function tile.removeFeatureState to trigger this update?

Copy link
Contributor

@karimnaaji karimnaaji Nov 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't stepped through the code in debug, but from reading it removeFeatureState should eventually result in a bucket update. I'd verify that with a step through to confirm.

If we tie a render cache invalidation to a buffer update, we ensure that when something actually changes visually (like you do now in this PR) we invalidate the draping cache entry. bucket.update should be the end result of any mutation of feature state changes, which is the end result of going through source_state:coalesceChanges.

But to confirm that some unit test using these cases would be necessary (to check that we invalidate the cache correctly).

Copy link
Contributor Author

@SnailBones SnailBones Nov 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debugging shows that source_state:coalesceChanges (and thus the code in this fix) is indeed being called after removeFeatureState. I'm not totally sure how that works, but I can confirm that it works as expected in browser testing.

src/style/style.js Outdated Show resolved Hide resolved
src/terrain/terrain.js Outdated Show resolved Hide resolved
Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SnailBones LGTM!

Is it possible to add some unit tests covering this to prevent further regression?

src/source/tile.js Outdated Show resolved Hide resolved
@SnailBones SnailBones changed the title Fix terrain cache not updating on style.setFeatureState Fix terrain cache not updating on setFeatureState Nov 4, 2021
@@ -527,6 +531,12 @@ class Tile {
if (!sourceLayer || !sourceLayerStates || Object.keys(sourceLayerStates).length === 0) continue;

bucket.update(sourceLayerStates, sourceLayer, availableImages, this.imageAtlas && this.imageAtlas.patternPositions || {});
if (bucket instanceof LineBucket || bucket instanceof FillBucket || bucket instanceof FillExtrusionBucket || bucket instanceof CircleBucket) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move this as a function on a bucket, instead of all of these instanceof checks?

Copy link
Contributor

@arindam1993 arindam1993 Nov 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also is FillExtrusion right here? because thats not draped? same with circle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The instance checks are necessary for Flow. Really we're just checking that it's not a SymbolBucket, since SymbolBucket doesn't have the programConfigurations.

Good point about draping, should this just be LineBucket and FillBucket?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well symbols are draped in certain situations 😅 (map aligned)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😓 Hmmm... If this bug exists for symbols then this fix won't work as is. Though we could bypass the check for bucket.programConfigurations.needsUpload and clear the cache for all tiles.

Do we have an examples of feature-state on a symbol layer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked that symbols are not yet draped in any situation on gl-js, pending #10365. The draped layer list is https://github.com/mapbox/mapbox-gl-js/blob/main/src/style/style.js#L116.

So this check should be good now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!
Tested that symbol layers don't have this bug and that the fix works with line layers as well as fill layers.

@SnailBones SnailBones merged commit 2843074 into main Nov 4, 2021
@SnailBones SnailBones deleted the aidan/feature-state-terrain branch November 4, 2021 18:26
ansis pushed a commit that referenced this pull request Nov 4, 2021
* Invalidating terrain render cache on style.setFeatureState

* Changed approach to directly clear render cache from Tile

* Only on LineBucket and FillBucket

Tests will be in a new PR
@SnailBones SnailBones restored the aidan/feature-state-terrain branch November 4, 2021 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants