liyujie
2025-08-28 b3810562527858a3b3d98ffa6e9c9c5b0f4a9a8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
library fuchsia.ui.scenic;
 
using fuchsia.images;
using fuchsia.ui.gfx;
 
// Client use Sessions to interact with a Mozart instance by enqueuing commands
// that create or modify resources.
interface Session {
    1: Enqueue(vector<Command> cmds);
 
    // Present all previously enqueued operations.  In order to pipeline the
    // preparation of the resources required to render the scene, two lists of
    // fences (implemented as events) are passed.
    //
    // SCHEDULING PRESENTATION
    //
    // |presentation_time| specifies the time on or after which the
    // client would like the enqueued operations should take visible effect
    // (light up pixels on the screen), expressed in nanoseconds in the
    // |CLOCK_MONOTONIC| timebase.  Desired presentation times must be
    // monotonically non-decreasing.
    //
    // Using a desired presentation time in the present or past (such as 0)
    // schedules enqueued operations to take visible effect as soon as possible
    // (during the next frame to be prepared).
    //
    // Using a desired presentation time in the future schedules the enqueued
    // operations to take visible effect as closely as possible to or after
    // the stated time (but no earlier).
    //
    // Each rendered frame has a target presentation time.  Before rendering
    // a frame, the scene manager applies all enqueued operations associated
    // with all prior calls to |Present()| whose desired presentation time
    // is on or before the frame's target presentation time.
    //
    // The |Present()| method does not return until the scene manager begins
    // preparing the first frame which includes its presented content.
    // Upon return, the |PresentationInfo| provides timing information for the
    // frame which includes the presented content.
    //
    // To present new content on each successive frame, wait for |Present()|
    // to return before calling |Present()| again with content for the next
    // frame.
    //
    // It is also possible to enqueue and present successive frames of content
    // all at once with increasing desired presentation times, incrementing by
    // |PresentationInfo.presentation_interval| for each one.
    //
    // Animation updates are also coordinated in terms of presentation time.
    //
    // TODO(jeffbrown): Defining presentation time in terms of |CLOCK_MONOTONIC|
    // simplifies synchronization across subsystems but it might be too simple.
    // We should consider using a synthetic timebase and describing its relation
    // to other clocks separately.  That would make it possible to present
    // content (animations, media, and UI) in "slow mode" simply by varying the
    // timing relation, assuming clients play along.
    //
    // SYNCHRONIZATION
    //
    // |acquire_fences| are used by Mozart to wait until all of the session's
    // resources are ready to render (or to allow downstream components, such as
    // the Vulkan driver, to wait for these resources).
    //
    // For example, Fuchsia's Vulkan driver allows an zx::event to be obtained
    // from a VkSemaphore.  This allows a Mozart client to submit a Vulkan command
    // buffer to generate images/meshes/etc., and instructing Vulkan to signal a
    // VkSemaphore when it is done.  By inserting the zx::event corresponding to
    // this semaphore into |acquire_fences|, the client allows Mozart to submit work
    // to the Vulkan driver without waiting on the CPU for the event to be
    // signalled.
    //
    // |release_fences| is a list of events that will be signalled by Mozart when
    // the updated session state has been fully committed: future frames will be
    // rendered using this state, and all frames generated using previous session
    // states have been fully-rendered and presented to the display.
    //
    // Together, |acquire_fences| and |release_fences| are intended to allow clients
    // to implement strategies such as double-buffering.  For example, a client
    // might do the following in the Scenic subsystem:
    //   1) create two Image with resource IDs #1 and #2.
    //   2) create two Materials with resource IDs #3 and #4, which respectively
    //      use Images #1 and #2 as their texture.
    //   3) create a tree of Nodes and attach them to the scene.
    //   4) set one of the nodes above, say #5, to use Material #3.
    //   5) submit a Vulkan command-buffer which renders into Image #1, and
    //      will signal a VkSemaphore.
    //   6) call Present() with one acquire-fence (obtained from the VkSemaphore
    //      above) and one newly-created release-fence.
    //
    // After the steps above, Mozart will use the committed session state to render
    // frames whenever necessary.  When the client wants to display something
    // different than Image #1, it would do something similar to steps 4) to 6):
    //   7) set Node #5 to use Material #4.
    //   8) submit a Vulkan command-buffer which renders into Image #1, and
    //      will signal a VkSemaphore.
    //   9) call Present() with one acquire-fence (obtained from the VkSemaphore
    //      above) and one newly-created release-fence.
    //
    // Finally, to continually draw new content, the client could repeat steps
    // 4) to 9), with one important difference: step 5) must wait on the event
    // signalled by step 9).  Otherwise, it might render into Image #1 while that
    // image is still being used by Mozart to render a frame.  Similarly, step 8)
    // must wait on the event signalled by step 6).
    //
    // The scenario described above uses one acquire-fence and one release-fence,
    // but it is easy to imagine cases that require more.  For example, in addition
    // to using Vulkan to render into Images #1 and #2, the client might also
    // upload other resources to Vulkan on a different VkQueue, which would
    // would signal a separate semaphore, and therefore require an additional
    // acquire-fence.
    //
    // Note: |acquire_fences| and |release_fences| are only necessary to synchronize
    // access to memory (and other external resources).  Any modification to
    // resources made via the Session API are automatically synchronized.
    //
    // TODO(MZ-400): document invariants that apply to |presentation_info|.  Is it
    // strong enough to guarantee that receiving the response means that all
    // previously-enqueued Commands have been applied?  Or does it need to be stronger,
    // e.g. that all frames based on previous presentations are completely done,
    // and subsequent frames will be rendered based on the most recent presented
    // content?
    2: Present(uint64 presentation_time,
               vector<handle<event>> acquire_fences, vector<handle<event>> release_fences)
           -> (fuchsia.images.PresentationInfo presentation_info);
 
    // TODO(MZ-422) Remove these methods from the FIDL; they should just be
    // exposed to View Manager directly using a C++ interface.
    3: HitTest(uint32 node_id, fuchsia.ui.gfx.vec3 ray_origin, fuchsia.ui.gfx.vec3 ray_direction)
           -> (vector<fuchsia.ui.gfx.Hit>? hits);
    4: HitTestDeviceRay(fuchsia.ui.gfx.vec3 ray_origin, fuchsia.ui.gfx.vec3 ray_direction)
           -> (vector<fuchsia.ui.gfx.Hit>? hits);
 
    // Set an optional debug name for the session.  The debug name will be
    // output in things such as logging and trace events.
    5: SetDebugName(string debug_name);
};
 
// Listens for events which occur within the session.
interface SessionListener {
    // Called when an error has occurred and the session will be torn down.
    1: OnScenicError(string error);
 
    // Called to deliver a batch of one or more events to the listener.
    // Use |SetEventMaskCmd| to enable event delivery for a resource.
    2: OnScenicEvent(vector<Event> events);
};