Mozart: Improve internal scene graph representation.

This patch changes the internal scene graph representation into an
immutable data structure which allows for multiple versions to be
maintained simultaneously as well as for the node structure to be
preserved during snapshot operations.

Previously the node structure was traversed once during snapshot
with the intent that all relevant information would be recorded
info an immutable |RenderFrame| object for rasterization and for
hit testing.  However it proved prohibitively expensive to copy
the necessary node structure information into the |RenderFrame|
for hit testing.  So this change does away with all of that.

The compositor now keeps three levels of structural information
to be generated and traversed as required.

1. |SceneDef| which holds a table of immutable |NodeDef| objects
   describing the currently presented state of the scene graph
   and pending updates which have yet to be applied.

2. |SceneContent| which is generated from a |SceneDef| when the
   scene graph is presented.  It consists of an immutable index
   of |NodeDef| objects for a particular version of the scene
   graph as it existed at the time of presentation.  This index
   contains sufficient linkage information to ensure that the
   scene does not contain any internal cross-node cycles and
   that all references resources and nodes are reachable.

3. |Snapshot| which is generated from a collection of |SceneContent|
   objects when the frame is snapshotted.  When producing the
   snapshot, all scene references are resolved and combinator
   rules are evaluated to produce a final description of a single
   frame of graphical content to be rasterized.  The |Snapshot|
   can also be traversed later for hit testing purposes since
   it retains a record of the disposition of each node (whether
   they were blocked).

Altogether, these new representations resolve numerous issues with
the old model such as how we can retain multiple versions of a
scene for as long as required or how we can traverse particular
versions or snapshots of the scene graph to execute queries such
as hit testing.

There are still many optimizations we could apply to the structure
but it's already looking much better overall and there is
significantly less wasted effort during snapshotting when blocked
nodes are discovered.

This also puts us in a nice position to start dealing with
synchronization issues such as applications which publish scenes
referencing textures which have yet to be produced: while walking
the tree we can make a decision of whether to wait or to fallback
on previously published content which may be already be ready with
per-scene granularity.  (To do later.)

(Hit testing itself will be implemented in a later patch.)

BUG=
R=abarth@google.com

Review URL: https://codereview.chromium.org/1749063002 .
24 files changed
tree: a63621f91148f40a97deffbc1053cab91f6f1cb6
  1. apps/
  2. benchmarks/
  3. build/
  4. crypto/
  5. device/
  6. docs/
  7. examples/
  8. fusl/
  9. gin/
  10. gpu/
  11. mojo/
  12. mojom/
  13. sandbox/
  14. sdk_build/
  15. services/
  16. shell/
  17. skia/
  18. testing/
  19. third_party/
  20. tonic/
  21. tools/
  22. ui/
  23. url/
  24. .clang-format
  25. .gitattributes
  26. .gitignore
  27. .gn
  28. AUTHORS
  29. BUILD.gn
  30. codereview.settings
  31. DEPS
  32. DEPS.nacl
  33. LICENSE
  34. mojoconfig
  35. OWNERS
  36. PRESUBMIT.py
  37. PRESUBMIT_test.py
  38. PRESUBMIT_test_mocks.py
  39. README.md
  40. WATCHLISTS
README.md

Mojo

Mojo is a collection of interprocess communication technologies, protocols and a runtime for creating applications and services that are composable while being loosely coupled. It simplifies the creation of fully asynchronous component-based systems and provides guarantees so that components made by different vendors and in different programming languages can interoperate.

Set-up and code check-out

The instructions below only need to be done once. Note that a simple “git clone” command is not sufficient to build the source code because this repo uses the gclient command from depot_tools to manage most third party dependencies.

  1. Download depot_tools and make sure it is in your path.
  2. [Googlers only] Install Goma in ~/goma.
  3. Create a directory somewhere for your checkout (preferably on an SSD), cd into it, and run the following commands:
$ fetch mojo # append --target_os=android to include Android build support.
$ cd src

# Or install-build-deps-android.sh if you plan to build for Android.
$ ./build/install-build-deps.sh

$ mojo/tools/mojob.py gn

The fetch mojo command does the following:

  • creates a directory called ‘src’ under your checkout directory
  • clones the repository using git clone
  • clones dependencies with gclient sync

install-build-deps.sh installs any packages needed to build, then mojo/tools/mojob.py gn runs gn args and configures the build directory, out/Debug.

If the fetch command fails, you will need to delete the src directory and start over.

Adding Android bits in an existing checkout

If you configured your set-up for Linux and now wish to build for Android, edit the .gclient file in your root Mojo directory (the parent directory to src.) and add this line at the end of the file:

target_os = [u'android',u'linux']

Bring in Android-specific build dependencies:

$ build/install-build-deps-android.sh 

Pull down all of the packages with this command:

$ gclient sync

Update your checkout

You can update your checkout like this. The order is important. You must do the git pull first because gclient sync is dependent on the current revision.

# Fetch changes from upstream and rebase the current branch on top
$ git pull --rebase
# Update all modules as directed by the DEPS file
$ gclient sync

You do not need to rerun gn gen out/Debug - ninja does so automatically each time you build. You might need to rerun mojo/tools/mojob.py gn if the GN flags have changed.

Build Mojo

Linux

Build Mojo for Linux by running:

$ ninja -C out/Debug -j 10

You can also use the mojob.py script for building. This script automatically calls ninja and sets -j to an appropriate value based on whether Goma (see the section on Goma below) is present. You cannot specify a target name with this script.

mojo/tools/mojob.py gn
mojo/tools/mojob.py build

Run a demo:

out/Debug/mojo_shell mojo:spinning_cube

Run the tests:

mojo/tools/mojob.py test

Run the benchmarks:

mojo/devtools/common/mojo_benchmark mojo/tools/data/benchmarks

Create a release build:

mojo/tools/mojob.py gn --release
mojo/tools/mojob.py build --release
mojo/tools/mojob.py test --release

Android

To build for Android, first make sure that your checkout is configured to build for Android. After that you can use the mojob script as follows:

$ mojo/tools/mojob.py gn --android
$ mojo/tools/mojob.py build --android

The result will be in out/android_Debug. If you see javac compile errors, make sure you have an up-to-date JDK

Goma (Googlers only)

If you're a Googler, you can use Goma, a distributed compiler service for open-source projects such as Chrome and Android. If Goma is installed in the default location (~/goma), it will work out-of-the-box with the mojob.py gn, mojob.py build workflow described above.

You can also manually add:

use_goma = true

at the end of the file opened through:

$ gn args out/Debug

After you close the editor gn gen out/Debug will run automatically. Now you can dramatically increase the number of parallel tasks:

$ ninja -C out/Debug -j 1000

Official builds

Official builds for android generate a signed Mojo Shell intended for distribution. You normally should not need to produce one. If you have any questions, reach out to etiennej@chromium.org.

Run Mojo Shell

Devtools mojo_run is a universal shell runner abstracting away the differences between running on Linux and Android.

Having built Mojo as described above, a demo app can be run as follows:

mojo/devtools/common/mojo_run https://core.mojoapps.io/spinning_cube.mojo  # Linux
mojo/devtools/common/mojo_run https://core.mojoapps.io/spinning_cube.mojo --android  # Android

Development server

Whenever mojo_run is run, a development server is set up according to the config file. The server runs on your machine, serving the locally built apps, but appears to the shell under the https://core.mojoapps.io host.

You can ignore the config file and skip spawning the local server (for example, in order to use apps at the actual https://core.mojoapps.io web host) by passing --no-config-file to mojo_run.

More examples

Some applications can be run directly from the source tree. The development server serves the src directory, allowing to refer to these apps. For instance, this command serves a dart Mojo app from the source at examples/dart/device_info/main.dart:

mojo/devtools/common/mojo_run https://core.mojoapps.io/examples/dart/device_info/lib/main.dart [--android]

Some applications are meant to be run embedded in a window manager. To run these, you can pass the app url using the --embed flag. This will run the window manager and pass the given url to it:

mojo/devtools/common/mojo_run --embed https://core.mojoapps.io/ganesh_app.mojo [--android]

By default, mojo_run uses mojo:kiosk_wm as the window manager. You can pass a different window manager url using the --window-manager flag to override this.

For additional information on mojo_run refer to the built-in help and the documentation. You can also request more information on what the tool is doing for you by passing the --verbose flag.

Debugging, tracing, profiling

Devtools mojo_debug allows you to interactively inspect a running shell, collect performance traces and attach a gdb debugger.

For additional information refer to the built-in help and the documentation.

Android set-up

Adb

For the Android tooling to work, you will need to have adb in your PATH. For that, you can either run:

source build/android/envsetup.sh

each time you open a fresh terminal, or add something like:

export PATH="$PATH":$MOJO_DIR/src/third_party/android_tools/sdk/platform-tools

to your ~/.bashrc file, $MOJO_DIR being a path to your Mojo checkout.

Device

The device has to be running Android 5.0 (Lollipop) or newer.

Many features useful for development (ie. streaming of the shell stdout when running shell on the device) will not work unless the device is rooted and running a userdebug build. For Googlers, follow the instructions at this link.

Running manually on Linux

If you wish to, you can also run the Linux Mojo shell directly with no wrappers:

./out/Debug/mojo_shell out/Debug/spinning_cube.mojo

Contribute

With git you should make all your changes in a local branch. Once your change is committed, you can delete this branch.

Create a local branch named “mywork” and make changes to it.

  cd src
  git new-branch mywork
  vi ...

Commit your change locally. (this doesn't commit your change to the SVN or Git server)

  git commit -a

Fix your source code formatting.

$ git cl format

Upload your change for review.

$ git cl upload

Respond to review comments.

See Contributing code for more detailed git instructions, including how to update your CL when you get review comments. There's a short tutorial that might be helpful to try before making your first change: C++ in Chromium 101.

To land a change after receiving LGTM:

$ git cl land

Monitoring

Our waterfall continuously builds and tests the code. Don't break the build!

Benchmarks

One of the bots, Mojo Linux Perf runs a suite of benchmarks and uploads the results to the performance dashboard. You can browse the results here, putting mojo_benchmarks as the “test suite”.

Automated alerts about performance regressions are sent to mojo-perf-alerts@chromium.org.

For examples of interesting sets of graphs see: