Lifecycle of a Scene Graph Resource

This document describes the lifecycle of the basic resources that a client adds to and removes from the scene graph. It focuses on resources that are attached as Nodes and Views, and is a reference for Scenic's internal handling of these resources.

Many Resources follow the Node lifecycle: Resources are created and added to the ResourceMap. Resources are kept alive by reference counting. As such, inter-scene graph references will keep resources in the scene graph alive, even if the client calls ReleaseResource. The release command removes the Resource from the client‘s internally-managed ResourceMap, which means that the client cannot apply any future commands to that Resource. This document highlights how the scene graph can keep Resources added to it alive, with the key exception of the View resource -- which is solely held onto via the client’s ResourceMap.

This follows a simple embedded-embeddee client pair, and assumes the clients have set up all necessary resources to add Nodes and Views to the global, retained scene graph.

Note: the code shown below is typically handled by the UI C++ SDK wrappers. All code examples show FIDL commands, as they are seen by Scenic.

Node Lifecycle

Adding a Node to the Scene

Say the embedder client (Client A) has created a root Scene node in its Session, accessed via root_id. Client A can create children and add that to the root node via the following commands:

CreateScene(root_id);
CreateEntityNode(entity_node_id);
AddChild(root_id, entity_node_id);

Internally, this creates a Node, adds it to the Session's ResourceMap, and sets the EntityNode as the child of the root node in the scene graph:

Image of a simple scene graph. There is a root Scene node with a strong linkto its child entity node. Client A's ResourceMap also has a strong reference toboth the root node and the entity node. There is a second image to the right,labeled projected scene, that shows a blank screen.

Client A can apply commands to the EntityNode as long as it maintains a reference to it in the ResourceMap. For example:

SetTranslation(entity_node_id, {0, h/2, 0});
CreateShapeNode(shape_node_id);
CreateShape(shape_node_id, triangle);
AddChild(entity_node_id, shape_node_id);

Image of the expanded scene graph. There is a root Scene node with a stronglink to its child entity node. The entity node has a strong link to is child,a shape node with a triangle shape. Client A's ResourceMap also has a strongreference to all the nodes in the scene. There is a second image to the right,labeled projected scene, that shows a triangle on the bottom half of thescreen.

Removing a Node

Releasing the Resource releases it from the ResourceMap. It does not release it from the Scene graph, due to a strong reference from the parent. Client A can release the Resources backing the “triangle dialog”, and it will still remain on the screen:

ReleaseResource(entity_node_id);

Image of the scene graph in the image above. Client A's ResourceMap no longerhas a strong reference to the entity node. The projected scene image isunchanged.

To remove the triangle from the screen, the client would have to explicitly detach the nodes from the scene graph. When the Resource is removed from both the ResourceMap and from the scene graph, the resource is destroyed.

DetachChildren(root_id);

Image of the scene graph. Its only node is the root scene node. TheResourceMap has a strong reference to the root node and the shape nodecontaining the triangle shape. There is no entity node. The projected sceneimage is a blank screen

Embedding a View

Add a ViewHolder to the SceneGraph

To embed a View from another Session, Client A must make a ViewHolder Resource, and add it as a child of a node to add it to the scene graph.

CreateEntityNode(entity_node_id);
AddChild(root_id, entity_node_id);

CreateViewHolder(view_holder_id, view_holder_token);
AddChild(entity_node_id, view_holder_id);

Image of the scene graph containing a scene root node with a child EntityNode.The EntityNode has a ViewHolder child. Client A's ResourceMap has a strongreference to the Scene, EntityNode, and the ViewHolder.

The ViewHolder follows the same lifecycle rules as a Node, described above. It will remain part of the scene graph as long as it is connected to something in the scene graph. However, the client cannot add children to the ViewHolder: instead, its corresponding View is linked by Scenic.

Link a View to a ViewHolder

The view_token from the ViewHolder/View token pair is passed to the embedded Session (Client B). When Client B creates a View from that token, a View is created and added to the client‘s ResourceMap. Scenic creates links between the View to the ViewHolder to establish this cross-Session connection. The View then creates a “phantom ViewNode”, and sets that as the child of the ViewHolder. The ViewNode represents Client B’s root node in the scene graph.

CreateView(view_id, view_token);

Image of the scene graph above: Client As ResourceMap maintains a strongreference to the ViewHolder, EntityNode, and Scene, all added to the scenegraph. Client Bs View and ViewNode are also added to the scene graph: theViewHolder maintains a strong reference to the ViewNode, and a weak reference tothe View. The View also maintains a strong reference to the ViewNode. Client B'sResourceMap only points to the View.

Client B can then add children to the View, just like it can to Nodes. Under the hood, the ViewNode maintains the children's connections to the scene graph:

CreateShapeNode(shape_node_id);
CreateShape(shape_node_id, rectangle);
AddChild(view_id, shape_node_id);

Image of the scene graph above. A ShapeNode containing a rectangle is added tothe scene graph as the child of the ViewNode. Client B's ResourceMap also has astrong reference to the ShapeNode. The projected scene image shows a rectangleon the screen.

Removing a View

A View is a viable Resource and added to the scene as long as it is in the client's ResourceMap. It differs from a traditional Node because the scene graph does not maintain a strong reference to the View Resource. To perform removal of a View, Client B must command Scenic to release the View resource. Unlike a node, the client does not have to command Scenic to detach it from the scene graph. Releasing the View Resource destroys the View and its phantom ViewNode, and detaches the View and its subtree from the global scene graph:

ReleaseResource(view_id);

Image of the scene graph with Client As nodes still attached. Client Bs Viewand ViewNode are destroyed, but its ResourceMap maintains a strong reference tothe ShapeNode.

Note: if either the View or ViewHolder is destroyed, its pair is delivered a disconnected event (i.e. fuchsia.ui.gfx.ViewHolderDisconnected or fuchsia.ui.gfx.ViewDisconnected, respectively).

Removing a ViewHolder

A ViewHolder is treated as another child node in a Session, and so follows the same lifecycle rules. If a ViewHolder is released as a Resource, and detached from the scene graph, the ViewHolder is destroyed.

Say that Client B has not released its View. When the ViewHolder is destroyed, this breaks any link to the View, and destroys the strong reference to the child ViewNode. The embedded View is thus detached from the scene. The embedded Session and embedded View's subtree may still be intact, though no longer visible.

Detach(view_holder_id);
ReleaseResource(view_holder_id);

Image of the scene graph shows just the Scene root in the graph; Client Amaintains a strong reference to the Scene node. There is no ViewHolder. ClientBs subtree maintains the strong reference between the ViewNode and its childShapeNode, and Client Bs ResourceMap maintains its links to the View and theShapeNode. The projected scene image is a blank screen.

Note: Any embedded Sessions are notified if they are detached from the scene via the fuchsia.ui.gfx.ViewDetachedFromSceneEvent.