In order to calculate the collision correctly, the layer ordering
matters. Because of that, when we find the first incomplete symbol
bucket, we stop processing any furter SymbolBucket.
The side effect of this change is, if the first SymbolBucket is the
last to receive its resources, we won't see any label at all on
the screen until the last moment, when everything will be draw at
once.
We keep the Collision object alive longer because we need it
for the SymbolBuckets yet to be created in case more data
resources arrive. When the tile is no longer needed or if it
is completely parsed or obsolete (i.e. in a immutable state)
we throw the Collision object away.
Also add a virtual setState() method to give subclasses a chance
to intercept the change of state. This will be used by VectorTileData
to release resources when the TileData becomes immutable.
This still has the unwanted side effect off blocking the Map thread
waiting for the workers to return (because they hold a reference
to the Map thread main loop).
Maybe the only way to solve this would be having a I/O thread for
dispatching messages.
The Request is not bound anymore to the invoker thread because the workers
will request for glyphs, but the reply will arrive at the Map thread.
For now, the buckets depending on Glyphs that are not yet available
are simply not created (or created and discarded). In the future
we could refactor the code to not create the bucket at all or put
the bucket in a suspended state until the glyph range is available.
GlyphStore will notify observers when a glyph range is loaded. By now
the notification is generic, but could be fine grained, causing the
processing of buckets depending on this particular range.
This change will add a new state to the tile called "partial" which
is a state where the tile can be rendered but some information might
be missing.
For now we skip the SymbolBucket if the Sprites are not loaded (will
also do the same for the glyphs in the future). When the Sprites are
finally loaded, we trigger another update, this time the Tile will
get completely re-rendered and change the state to "parsed".
This is the first concrete step to remove promises from the parsing
pipeline. Buckets depending on the Sprite (i.e. SymbolBucket) won't
be created if the Sprite is not loaded yet. When the Sprite finally gets
loaded, it will fire a signal that will ultimately trigger a reparse.
We still have to expose the Sprite to the Map object as it is needed
for getting offset pixels for annotation symbols, but we can probably
improve that.
This pattern, in contrast with callbacks, allows us to clearly see
the dependency and hierarchy between the objects. It will also help
on writing unit tests as we can count how many times a notification
was triggered.
ResourceLoader will handle all the tile changes and notifications
through the Source object owned by the Style. This object lives
entirely on the Map thread and should be only accessed by it.
The observer will receive notifications every time the tile data changes
and this will probably trigger a new rendering operation.
This first patch will delegate Source loading to the ResourceLoader.
- previously, we reallocated the glyph atlas on every upload. Instead, we're now using glTexSubImage2D to reuse the existing buffer
- we're no longer forcing a texture upload when we remove glyphs; they won't be rendered anyway
- we're now only doing a texture upload once per frame; previously, worker threads that added glyphs mid-render could trigger a texture upload while rendering is in progress