blob: 4dd3a4d21b077fcba3063b8c64a1aebf034ed09a [file] [log] [blame]
// 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);
};