|  | // 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; | 
|  | using fuchsia.sysmem; | 
|  |  | 
|  | /// Arguments passed into Present2(). Note that every argument is mandatory. | 
|  | type Present2Args = resource table { | 
|  | /// `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: requested_presentation_time zx.time; | 
|  |  | 
|  | /// Scenic will wait until all of a session's `acquire_fences` are ready | 
|  | /// before it will execute the presented commands. | 
|  | 2: acquire_fences vector<zx.handle:EVENT>; | 
|  |  | 
|  | /// `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: release_fences vector<zx.handle:EVENT>; | 
|  |  | 
|  | /// `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: requested_prediction_span zx.duration; | 
|  | }; | 
|  |  | 
|  | /// Client use Sessions to interact with a Scenic instance by enqueuing commands | 
|  | /// that create or modify resources. | 
|  | protocol Session { | 
|  | Enqueue(resource struct { | 
|  | cmds vector<Command>; | 
|  | }); | 
|  |  | 
|  | // 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(fxbug.dev/23637): 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(resource struct { | 
|  | presentation_time uint64; | 
|  | acquire_fences vector<zx.handle:EVENT>; | 
|  | release_fences vector<zx.handle:EVENT>; | 
|  | }) -> (struct { | 
|  | presentation_info fuchsia.images.PresentationInfo; | 
|  | }); | 
|  |  | 
|  | /// 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(resource struct { | 
|  | args Present2Args; | 
|  | }) -> (struct { | 
|  | request_presentation_times_info fuchsia.scenic.scheduling.FuturePresentationTimes; | 
|  | }); | 
|  |  | 
|  | /// This event is fired whenever a set of one or more Present2s are | 
|  | /// presented simultaenously, and are therefore no longer in flight. | 
|  | -> OnFramePresented(struct { | 
|  | frame_presented_info fuchsia.scenic.scheduling.FramePresentedInfo; | 
|  | }); | 
|  |  | 
|  | /// 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(struct { | 
|  | requested_prediction_span zx.duration; | 
|  | }) -> (struct { | 
|  | request_presentation_times_info fuchsia.scenic.scheduling.FuturePresentationTimes; | 
|  | }); | 
|  |  | 
|  | /// Registers BufferCollection referenced by the `token` and sets contraints on it. | 
|  | /// It does not block on the buffers being allocated until content backed by one of the | 
|  | /// collection's VMOs is created, e.g. an Image2. | 
|  | /// | 
|  | /// A value of 0 for the `buffer_id` is invalid. All other values are valid as long as they | 
|  | /// are not currently in use. | 
|  | RegisterBufferCollection(resource struct { | 
|  | buffer_id uint32; | 
|  | token client_end:fuchsia.sysmem.BufferCollectionToken; | 
|  | }); | 
|  |  | 
|  | /// Deregisters the BufferCollection previously registered with the `buffer_id` and sets it | 
|  | /// to be garbage collected as soon as it is no longer referenced by any resources. | 
|  | /// | 
|  | /// Only `buffer_id` that have been previously registered and not yet deregistered are valid. | 
|  | DeregisterBufferCollection(struct { | 
|  | buffer_id uint32; | 
|  | }); | 
|  |  | 
|  | /// Set an optional debug name for the session. The debug name will be | 
|  | /// output in things such as logging and trace events. | 
|  | SetDebugName(struct { | 
|  | debug_name string; | 
|  | }); | 
|  | }; | 
|  |  | 
|  | /// Listens for events which occur within the session. | 
|  | protocol SessionListener { | 
|  | /// Called when an error has occurred and the session will be torn down. | 
|  | OnScenicError(struct { | 
|  | error string; | 
|  | }); | 
|  |  | 
|  | /// Called to deliver a batch of one or more events to the listener. | 
|  | /// Use `SetEventMaskCmd` to enable event delivery for a resource. | 
|  | OnScenicEvent(resource struct { | 
|  | events vector<Event>; | 
|  | }); | 
|  | }; |