-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Source / tile architecture thoughts #8476
Comments
Noting that GL JS keeps a copy of vector tile (and feature index) data both on worker threads and the main thread for exactly this reason. (That's a different axis of separation than the main-vs-render split we're talking about here, but still a similar problem.) |
I'd prefer to not think of this in a manner of threads, and instead of "who has access to what, and how does the information/ownership flow". The model I'd like to see us move to doesn't necessarily have a render thread, instead it has a render tree which is entirely self contained. This render tree could then be rendered on any thread (including the main thread in the case of iOS/macOS/GLFW), or a separate render thread (in the case of Android/Qt). Control would still remain on the main thread, and we'd send new render objects via message passing. Whenever the UI system decides that it needs to render the frame, we empty the mailbox and integrate the new data into the render tree, potentially removing old data. Currently, we are defining rendering by the tiles we have parsed. This leads to a number of problems:
Instead, I'd like to move to a model where we create metatiles/render tiles that represent the "ideal tiles", but are synthesized from various sources by creating buckets for all layers that are clipped to that render tile extent. The supporting meta data would still live on the main thread, but the actual GL objects would be created/maintained/owned on the GL "thread". |
To clarify, what Qt and Android expects here is pretty much a data structure like Having a clear line separating the |
This ticket is a meandering brain dump as I started looking into preparing our source- and tile-related architecture for asynchronous rendering.
At a high level, the goal is to draw a line between two different sets of runtime data based on thread affinity:
(From a design purity standpoint, it would be better to motivate this division based on good design principles like SRP rather than a preconceived notion of a particular threading model. But I think the result would be largely the same.)
On possible first step is to split
Source::Impl
along these lines, separating the implementation of the style specification notion of aSource
from tile management and rendering-related tasks. A basic attempt at performing this split revealed many questions:setData
method on a main-threadGeoJSONSource
object. The corresponding rendering-side objects must be somehow notified of the mutation and efficiently provided with the new source data.SourceObserver
andTileObserver
interfaces must be rationalized. This will require its own requirements investigation.RenderSource
,RenderTileSource
,RenderVectorSource
,RenderGeoJSONSource
?Source
object (which is a copy of or immutable reference to the main-side object), and aRenderSource
, should the former own the latter, or vice versa?When considering possible class designs for source and tile related classes, it's worth noting that gl-js has a design history we can draw on:
Source
andSourceCache
classes.Source
is the style specification domain object;SourceCache
has the tile loading logic.SourceCache
owns an instance ofSource
. This essentially inverts a relationship found in a prior revision of the gl-js source architecture, where there wereSource
s which ownedTilePyramid
s.Whenever I get deep into considering these types of questions, I find myself wanting to rebuild rendering from scratch in a purely functional style, where everything is a function accepting immutable inputs and calculating an immutable output and nothing is cached or stateful or side-effecting. (And when I say nothing, I mean nothing: the rewrite would start off by having tiles re-requested, re-parsed, re-bucketed on every frame.) Then see how to add back statefullness, caching, and reasonable performance in a controlled manner.
The text was updated successfully, but these errors were encountered: