| // 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 zx; |
| using fuchsia.images; |
| using fuchsia.scenic.scheduling; |
| |
| /// Arguments passed into Present2(). Note that every argument is mandatory. |
| table Present2Args { |
| /// |requested_presentation_time| specifies the time on or after which the |
| /// client would like the enqueued operations to take visible effect |
| /// (light up pixels on the screen), expressed in nanoseconds in the |
| /// `CLOCK_MONOTONIC` timebase. |
| /// |
| /// Using a |requested_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. Requested presentation |
| /// times must be monotonically increasing. |
| /// |
| /// Using a |requested_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. This is when Scenic |
| /// aims to have the frame presented to the user. Before rendering a frame, |
| /// the scene manager applies all enqueued operations associated with all |
| /// prior calls to Present2 whose |requested_presentation_time| is on or |
| /// before the frame's target presentation time. |
| 1: zx.time requested_presentation_time; |
| |
| /// Scenic will wait until all of a session's |acquire_fences| are ready |
| /// before it will execute the presented commands. |
| 2: vector<handle<event>> acquire_fences; |
| |
| /// |release_fences| is the list of events that will be signalled by Scenic when |
| /// the following Present2 call's |acquire_fences| has been signalled, and |
| /// 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. |
| 3: vector<handle<event>> release_fences; |
| |
| /// |requested_prediction_span| is the amount of time into the future Scenic |
| /// will provide predictions for. A span of 0 is guaranteed to provide at |
| /// least one future time. |
| 4: zx.duration requested_prediction_span; |
| }; |
| |
| /// Client use Sessions to interact with a Scenic instance by enqueuing commands |
| /// that create or modify resources. |
| protocol Session { |
| Enqueue(vector<Command> cmds); |
| |
| // 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. |
| // TODO(SCN-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? |
| /// 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. |
| /// |
| /// SYNCHRONIZATION |
| /// |
| /// `acquire_fences` are used by Scenic 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 Scenic 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 Scenic 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 Scenic 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, Scenic 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 Scenic 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. |
| [Transitional]Present(uint64 presentation_time, |
| vector<handle<event>> acquire_fences, vector<handle<event>> release_fences) |
| -> (fuchsia.images.PresentationInfo presentation_info); |
| |
| /// 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. |
| /// |
| /// When a client calls Present2, they receive an immediate callback |
| /// consisting of the same information they would get as if they had called |
| /// |RequestPresentationTimes| with the equivalent |
| /// |requested_prediction_span|. See its documentation below for more |
| /// information, as Present2's functionality is a superset of it. |
| /// |
| /// Then, when the commands flushed by Present2 make it to display, an |
| /// |OnFramePresented| event is fired. This event includes information |
| /// pertaining to all Present2s that had content that were part of that |
| /// frame. |
| /// |
| /// Clients may only use one of Present/Present2 per Session. |
| /// Switching between both is an error that will result in the Session being |
| /// closed. |
| /// |
| /// See |Present2Args| documentation above for more detailed information on |
| /// what arguments are passed in and their role. |
| Present2(Present2Args args) |
| -> (fuchsia.scenic.scheduling.FuturePresentationTimes request_presentation_times_info); |
| |
| /// This event is fired whenever a set of one or more Present2s are |
| /// presented simultaenously, and are therefore no longer in flight. |
| -> OnFramePresented(fuchsia.scenic.scheduling.FramePresentedInfo frame_presented_info); |
| |
| /// Returns information about future presentation times, and their |
| /// respective latch points. Clients can use the returned information to |
| /// make informed scheduling decisions: if a client wants their frame to be |
| /// displayed at a given |presentation_time|, they should aim to have all |
| /// |acquire_fences| fired before the associated |latch_point|. |
| /// |
| /// Scenic will attempt to return predictions that span a duration equal to |
| /// |requested_prediction_span|, up to a limit. |
| /// |
| /// A value of 0 is guaranteed to give at least one future presentation info. |
| RequestPresentationTimes(zx.duration requested_prediction_span) |
| -> (fuchsia.scenic.scheduling.FuturePresentationTimes request_presentation_times_info); |
| |
| /// Set an optional debug name for the session. The debug name will be |
| /// output in things such as logging and trace events. |
| SetDebugName(string debug_name); |
| }; |
| |
| /// Listens for events which occur within the session. |
| protocol SessionListener { |
| /// Called when an error has occurred and the session will be torn down. |
| 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. |
| OnScenicEvent(vector<Event> events); |
| }; |