// 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);
|
};
|