In a typical frame, the order of events when using the Flatland API goes like this1:
- The client calls
Flatland::Present()
. - Scenic waits until
PresentArgs::requested_presentation_time
has been reached andPresentArgs::server_wait_fences
have been signaled.requested_presentation_time
is the earliest possible time the present may appear on the display.server_wait_fences
is a set of zircon events ("fences") which must all be signaled before the content submitted with thePresent()
call may appear on the display.
- Scenic composites the content from all clients this frame and sends it off to the display.
- Scenic sends
Flatland::->OnNextFrameBegin()
to the client. - The client starts creating their next frame.
- Once the image has actually been displayed Scenic sends
Flatland::->OnFramePresented()
to the client. - Repeat from 1.
This document explains what each of these signals mean.
Present()
As clients make Flatland API calls, those operations are not actually applied
right away. Instead these updates are bundled and committed atomically when
Present()
is called. The set of updates between two calls to Present()
is
referred to in this document as a present
.
When calling Present()
the client passes a table of arguments, PresentArgs
,
which contain arguments for how the Present()
call should be handed. The most
important arguments for deciding when the present appears on the display are the
requested_presentation_time
and server_wait_fences
.
For more information on how Present()
calls are handled, see
frame scheduling.
->OnNextFrameBegin()
->OnNextFrameBegin()
is sent as a hint to the client for when they should
begin creating their next frame. It does not explicitly say anything about the
state of Scenic, except that Scenic thinks resource contention should be
relatively low. OnNextFrameBegin()
is only sent after the client have made
previous Present()
calls, and only when the client has present credits
remaining.
->OnFramePresented()
->OnFramePresented()
is sent when one or more presents have actually appeared
on the display (i.e. after Scenic receives the VSync signal). It provides two
main pieces of information:
- Timing feedback to the client so they can evaluate how their frame scheduling strategy is working (latency, dropped frames, etc).
- It is signal for when the effects of a present has updated the state of the
ViewTree). After
->OnFramePresented()
Scenic guarantees that any subsequent calls to APIs that interact with theViewTree
(such as those inFlatland::ViewBoundProtocols
) will act as if the previous present has been applied (though more presents may have been applied afterwards).
-
The exact order of these events is not guaranteed. For example
->OnNextFrameBegin()
may happen after->OnFramePresented()
, or the client may callPresent()
again before receiving->OnFramePresented()
. For most clients these edge cases should not be a concern. They should just use the signal from->OnNextFrameBegin()
to draw their next frame and use->OnNextFramePresented()
to collect data, in which case there should be no conflicts. ↩