blob: 33b6e2e39da5dceaf2d4b1161da0ccf5ab561a8c [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 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 {
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?
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.
HitTest(uint32 node_id, fuchsia.ui.gfx.vec3 ray_origin, fuchsia.ui.gfx.vec3 ray_direction)
-> (vector<fuchsia.ui.gfx.Hit>? hits);
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.
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.
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);
};