We only emit signals when the number of buckets increase (i.e. the
new data that arrived added a new bucket to the tile).
Also, if we try to reparse a partial tile but it is not possible, we
keep the flag up for trying to reparse it again on the next update,
because the data might have arrived after the bucket that is waiting
for the data was processed but before the end of the parsing.
Fixes#1458
When parsing a tile, we request resources from the network, like
sprites and glyphs.
In the rare case of the resources arriving before the tile is
parsed for the first time, if we don't mark it for being parsed
again, it can end up with a tile eternally stuck in the partial
state.
Partial tiles are now only processed again when there is a new resource
available. If we don't have new resources - like new glyphs - the end result
of the reparsing is the same, because no new SymbolBuckets would are created.
In my tests debugging with PowerTOP, this patch drops the CPU utilization
during the sampling period from 100ms/s to 40ms/s. The improvements on
slow connections (i.e. more time waiting for resources) are even more
noticeable.
We were previously emitting the signal on the thread parsing the
glyph, but signals can only be trigger from the MapThread
because the observers are living there.
For now, keep a pointer so we can subscribe/unsubscribe to events. In
the future, we should move this object completely to ResourceLoader, but
we can't do it now because we delete the ResourceLoader when changing
the style.
When processing a layer, we request the dependencies of all the
SymbolBuckets even if we are not processing it completely.
By doing that we are now requesting glyphs in parallel instead of
sequentially as we were doing before.
This patch is also simplifying the SymbolBucket creation code by getting
rid of the ugly "needsResources" return value passed by reference as
argument.
If the request is cancelled, the response callback won't be called, and
~Source ensures that the request is cancelled. So it's safe to bind
`this` in the lambda.
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.