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

Schedule the "main thread" part of tile loading more intentionally #507

Open
kring opened this issue May 31, 2022 · 1 comment
Open

Schedule the "main thread" part of tile loading more intentionally #507

kring opened this issue May 31, 2022 · 1 comment
Labels
performance Improvements to performance, including reductions in memory usage research Explore an idea or prototype a concept and share the results

Comments

@kring
Copy link
Member

kring commented May 31, 2022

Currently, the process of loading a tile is split into two parts:

Future-based load pipeline

This happens almost entirely in a worker thread, and consists of:

  1. A network request to get the tile content.
  2. Parsing of the tile content.
  3. Loading additional network resouces (e.g. textures external to the glTF).
  4. Decoding images (JPG, KTX2, etc)
  5. Decoding geometry (Draco, etc.)
  6. Creating "load thread" renderer (e.g. Unreal) resources.

At the end of this process, the Tile is in the ContentLoaded state.

Main thread update

This happens during tile selection in the main thread. Whenever we visit a tile in the ContentLoaded state, we do some additional processing and immediately (synchronously) move it to the Done state. The work done here consists of:

  1. Updating the main-thread Tile data structure with new information loaded in the background (e.g. new child tiles, new bounding volume).
  2. Creating "main thread" renderer (e.g. Unreal) resources.

#473 suggests separating step 1 from the rest, so that we can, say, have 20 network requests in flight at once but use a smaller number of threads for the CPU work in steps 2-6.

But this issue is about step 8. cesium-native basically assumes that ContentLoaded and Done are equivalent for selection purposes, because a ContentLoaded tile can and will be synchronously moved to Done. We should allow more flexibility in when this happens. We don't need to do it for every tile we visit; only tiles that we're actually going to render. And conversely, too many tiles sometimes hit the ContentLoaded state all at once, causing noticeable rendering pauses as we create renderer resources (including uploading data to the GPU) all at once.

With more flexibility, we can avoid eagerly creating GPU resources for tiles we're unlikely to need. And we can also throttle and prioritize resource creation to avoid major frame rate drops.

@kring kring added research Explore an idea or prototype a concept and share the results performance Improvements to performance, including reductions in memory usage labels May 31, 2022
@nithinp7
Copy link
Contributor

This was mostly addressed in #565, where the ContentLoaded --> Done transition was throttled. During the traversal, a priority-based queue is created amongst all visited tiles that are in ContentLoaded. Then a soft time-limited main-thread loading happens from the front of the list.

I'm going to leave the issue open because we could probably do more like:

  • Maybe we should have three priority queues like we have for loading: high (holes), medium (tiles meeting sse), low (pre-loaded tiles). This may not have a huge impact, since the background load prioritization naturally influences the order tiles even get to ContentLoaded. So e.g., explicitly prioritizing transitioning "hole" tiles to Done may not actually noticeably reduce holes.
  • Maybe main thread loading could be throttled together somehow across multiple tilesets.
  • Raster tile main thread loading should be throttled, although raster tiles don't have as much impact as glTF main thread loading.
  • Break up "prepareInMainThread" so it is a time-allotted polling-based task that might need to be called several times before it "finishes" (but it should always make progress). In Cesium for Unreal, this would be useful to break up primitive loads for glTFs that have multiple primitives. If we could load the first few primitives, stop, then next frame load the rest - and somehow prepareInMainThread could encapsulate that pattern - we could be a bit more robust to glTFs with many primitives. Perhaps more importantly, this would also allow client implementations (who have a better sense of the main-thread load cost breakdown) to influence throttling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Improvements to performance, including reductions in memory usage research Explore an idea or prototype a concept and share the results
Projects
None yet
Development

No branches or pull requests

2 participants