blob: 46c39f6b5520c4da5841f183eb32b98a374b0652 [file] [log] [blame]
// Copyright 2017 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.
#ifndef SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_SCHEDULER_H_
#define SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_SCHEDULER_H_
#include <fuchsia/images/cpp/fidl.h>
#include <fuchsia/scenic/scheduling/cpp/fidl.h>
#include <lib/fit/function.h>
#include <lib/zx/time.h>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <variant>
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/ui/scenic/lib/scheduling/frame_timings.h"
#include "src/ui/scenic/lib/scheduling/id.h"
#include "src/ui/scenic/lib/scheduling/present2_info.h"
namespace scheduling {
// Callback used for Present1 and ImagePipe::Present
using OnPresentedCallback = fit::function<void(fuchsia::images::PresentationInfo)>;
// Callback used for Present2.
using OnFramePresentedCallback =
fit::function<void(fuchsia::scenic::scheduling::FramePresentedInfo info)>;
// Interface for performing session updates.
class SessionUpdater {
public:
// Returned by |UpdateSessions()|.
struct UpdateResults {
// SessionIds whose updates failed.
std::unordered_set<SessionId> sessions_with_failed_updates;
};
virtual ~SessionUpdater() = default;
// For each known session in |sessions_to_update|, apply all of the "ready" updates. A "ready"
// update is one that is scheduled at or before |presentation_time|, and for which all other
// preconditions have been met (for example, all acquire fences have been signaled).
virtual UpdateResults UpdateSessions(
const std::unordered_map<SessionId, PresentId>& sessions_to_update, uint64_t trace_id) = 0;
};
// Result of a call to FrameRenderer::RenderFrame(). See below.
enum RenderFrameResult { kRenderSuccess, kRenderFailed, kNoContentToRender };
// Interface for rendering frames.
class FrameRenderer {
public:
virtual ~FrameRenderer() = default;
// Called when it's time to render a new frame. The FrameTimings object is used to accumulate
// timing for all swapchains that are used as render targets in that frame.
//
// If RenderFrame() returns true, the delegate is responsible for calling
// FrameTimings::OnFrameRendered/Presented/Dropped(). Otherwise, rendering did not occur for some
// reason, and the FrameScheduler should not expect to receive any timing information for that
// frame.
// TODO(SCN-1089): these return value semantics are not ideal. See comments in
// Engine::RenderFrame() regarding this same issue.
virtual RenderFrameResult RenderFrame(fxl::WeakPtr<FrameTimings> frame_timings,
zx::time presentation_time) = 0;
};
// The FrameScheduler is responsible for scheduling frames to be drawn in response to requests from
// clients. When a frame is requested, the FrameScheduler will decide at which Vsync the frame
// should be displayed at. This time will be no earlier than the requested time, and will be as
// close as possible to the requested time, subject to various constraints. For example, if the
// requested time is earlier than the time that rendering would finish, were it started immediately,
// then the frame will be scheduled for a later Vsync.
class FrameScheduler {
public:
virtual ~FrameScheduler() = default;
// Set the renderer that will be used to render frames. Can be set exactly once. Must be set
// before any frames are rendered.
virtual void SetFrameRenderer(fxl::WeakPtr<FrameRenderer> frame_renderer) = 0;
// Add a session updater to the FrameScheduler. This is safe to do between frames (i.e. not while
// sessions are being updated before a frame is rendered).
virtual void AddSessionUpdater(fxl::WeakPtr<SessionUpdater> session_updater) = 0;
// If |render_continuously|, we keep scheduling new frames immediately after each presented frame,
// regardless of whether they're explicitly requested using RequestFrame().
virtual void SetRenderContinuously(bool render_continuously) = 0;
// Sets a callback to handle a failed session update. This should only be
// called once per session. When triggered, all references to the Session are also removed from
// FrameScheduler.
using OnSessionUpdateFailedCallback = std::function<void()>;
virtual void SetOnUpdateFailedCallbackForSession(
SessionId session, OnSessionUpdateFailedCallback update_failed_callback) = 0;
// Registers per-present information with the frame scheduler and returns an incrementing
// PresentId unique to that session. The |present_id| argument should only be set when
// transferring sessions between frame schedulers.
virtual PresentId RegisterPresent(
SessionId session_id, std::variant<OnPresentedCallback, Present2Info> present_information,
std::vector<zx::event> release_fences, PresentId present_id = 0) = 0;
// Tell the FrameScheduler to schedule a frame. This is also used for updates triggered by
// something other than a Session update i.e. an ImagePipe with a new Image to present.
virtual void ScheduleUpdateForSession(zx::time presentation_time, SchedulingIdPair id_pair) = 0;
// Gets the predicted latch points and presentation times for the frames at or before the next
// |requested_prediction_span| time span. Uses the FramePredictor to do so.
using GetFuturePresentationInfosCallback =
fit::function<void(std::vector<fuchsia::scenic::scheduling::PresentationInfo>)>;
virtual void GetFuturePresentationInfos(zx::duration requested_prediction_span,
GetFuturePresentationInfosCallback callback) = 0;
// Sets the |fuchsia::ui::scenic::Session::OnFramePresented| event handler. This should only be
// called once per session.
virtual void SetOnFramePresentedCallbackForSession(SessionId session,
OnFramePresentedCallback callback) = 0;
// Removes all references to |session_id|.
virtual void RemoveSession(SessionId session_id) = 0;
// Clients cannot call Present() anymore when |presents_in_flight_| reaches this value. Scenic
// uses this to apply backpressure to clients.
// TODO(44211): Move into implementation.
static constexpr int64_t kMaxPresentsInFlight = 5;
};
} // namespace scheduling
#endif // SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_SCHEDULER_H_