blob: f4cbab46b745f20a7ebbd21178ae9b28263ba5b6 [file] [log] [blame]
// Copyright 2019 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 GARNET_LIB_UI_GFX_ENGINE_DEFAULT_FRAME_SCHEDULER_H_
#define GARNET_LIB_UI_GFX_ENGINE_DEFAULT_FRAME_SCHEDULER_H_
#include <queue>
#include <lib/async/cpp/task.h>
#include <lib/async/dispatcher.h>
#include <lib/zx/time.h>
#include "garnet/lib/ui/gfx/engine/frame_scheduler.h"
#include "garnet/lib/ui/gfx/id.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/ref_ptr.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace scenic_impl {
namespace gfx {
using SessionUpdate = SessionUpdater::SessionUpdate;
class Display;
class DefaultFrameScheduler : public FrameScheduler {
public:
explicit DefaultFrameScheduler(const Display* display);
~DefaultFrameScheduler();
// |FrameScheduler|
void SetDelegate(FrameSchedulerDelegate delegate) override {
delegate_ = delegate;
};
// |FrameScheduler|
//
// If |render_continuously|, we keep rendering frames regardless of whether
// they're requested using RequestFrame().
void SetRenderContinuously(bool render_continuously) override;
// |FrameScheduler|
//
// 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.
void ScheduleUpdateForSession(zx_time_t presentation_time,
scenic_impl::SessionId session) override;
protected:
// |FrameScheduler|
void OnFramePresented(const FrameTimings& timings) override;
// |FrameScheduler|
void OnFrameRendered(const FrameTimings& timings) override;
private:
// Used to compare presentation times so that the priority_queue acts as a min
// heap, placing the earliest PresentationTime at the top.
class UpdatableSessionsComparator {
public:
bool operator()(SessionUpdate updatable_session1,
SessionUpdate updatable_session2) {
return updatable_session1.requested_presentation_time >
updatable_session2.requested_presentation_time;
}
};
// Requests a new frame to be drawn, which schedules the next wake up time for
// rendering. If we've already scheduled a wake up time, it checks if it needs
// rescheduling and deals with it appropriately.
void RequestFrame();
// Update the global scene and then draw it... maybe. There are multiple
// reasons why this might not happen. For example, the swapchain might apply
// back-pressure if we can't hit our target frame rate. Or, the frame before
// this one has yet to finish rendering. Etc.
void MaybeRenderFrame(async_dispatcher_t*, async::TaskBase*, zx_status_t);
// Computes the target presentation time for the requested presentation time,
// and a wake-up time that is early enough to start rendering in order to hit
// the target presentation time.
std::pair<zx_time_t, zx_time_t>
ComputePresentationAndWakeupTimesForTargetTime(
zx_time_t requested_presentation_time) const;
// Return the predicted amount of time required to render a frame.
zx_time_t PredictRequiredFrameRenderTime() const;
// Executes updates that are scheduled up to and including a given
// presentation time. Returns true if rendering is needed.
bool ApplyScheduledSessionUpdates(uint64_t frame_number,
zx_time_t presentation_time,
zx_duration_t presentation_interval);
// References.
async_dispatcher_t* const dispatcher_;
const Display* const display_;
FrameSchedulerDelegate delegate_;
// State.
uint64_t frame_number_ = 0;
constexpr static size_t kMaxOutstandingFrames = 2;
std::vector<FrameTimingsPtr> outstanding_frames_;
bool render_continuously_ = false;
bool currently_rendering_ = false;
bool render_pending_ = false;
zx_time_t wakeup_time_;
zx_time_t next_presentation_time_;
// The async task that wakes up to start rendering.
async::TaskMethod<DefaultFrameScheduler,
&DefaultFrameScheduler::MaybeRenderFrame>
frame_render_task_{this};
// Sessions that have updates to apply, sorted by requested presentation time
// from earliest to latest.
std::priority_queue<SessionUpdate, std::vector<SessionUpdate>,
UpdatableSessionsComparator>
updatable_sessions_;
fxl::WeakPtrFactory<DefaultFrameScheduler> weak_factory_; // must be last
FXL_DISALLOW_COPY_AND_ASSIGN(DefaultFrameScheduler);
};
} // namespace gfx
} // namespace scenic_impl
#endif // GARNET_LIB_UI_GFX_ENGINE_DEFAULT_FRAME_SCHEDULER_H_