blob: 3eb0ba095bf4bb3b6cc0756fc1fdf6dc8f7f712e [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/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 {
class DefaultFrameScheduler : public FrameScheduler {
public:
explicit DefaultFrameScheduler(Display* display);
~DefaultFrameScheduler();
// |FrameScheduler|
//
// Helper method for ScheduleFrame(). Returns 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> ComputeTargetPresentationAndWakeupTimes(
zx_time_t requested_presentation_time) const override;
// |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(uint64_t presentation_time,
scenic_impl::SessionId session) override;
protected:
// |FrameScheduler|
void OnFramePresented(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()(
std::pair<PresentationTime, scenic_impl::SessionId> updatable_session1,
std::pair<PresentationTime, scenic_impl::SessionId>
updatable_session2) {
return updatable_session1.first > updatable_session2.first;
}
};
// Request a frame to be scheduled at or after |presentation_time|, which
// may be in the past.
void RequestFrame(zx_time_t presentation_time);
// 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, after this frame
// was scheduled, another frame was scheduled to be rendered at an earlier
// time, and not enough time has elapsed to render this frame. Etc.
void MaybeRenderFrame(zx_time_t presentation_time, zx_time_t wakeup_time);
// Schedule a frame for the earliest of |requested_presentation_times_|. The
// scheduled time will be the earliest achievable time, such that rendering
// can start early enough to hit the next Vsync.
void ScheduleFrame();
// Returns true to apply back-pressure when we cannot hit our target frame
// rate. Otherwise, return false to indicate that it is OK to immediately
// render a frame.
// TODO(MZ-225): We need to track backpressure so that the frame scheduler
// doesn't get too far ahead. With that in mind, Renderer::DrawFrame should
// have a callback which is invoked when the frame is fully flushed through
// the graphics pipeline. Then Engine::RenderFrame itself should have a
// callback which is invoked when all renderers finish work for that frame.
// Then FrameScheduler should listen to the callback to count how many
bool TooMuchBackPressure();
// Helper method for ScheduleFrame(). Returns the target presentation time
// for the next frame, 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> ComputeNextPresentationAndWakeupTimes() 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,
uint64_t presentation_time,
uint64_t presentation_interval);
// Apply updates to all sessions who have updates and have acquired all
// fences. Return true if there were any updates applied.
bool UpdateSessions(uint64_t presentation_time,
uint64_t presentation_interval,
uint64_t frame_number_for_tracing);
async_dispatcher_t* const dispatcher_;
Display* const display_;
std::priority_queue<zx_time_t, std::vector<zx_time_t>,
std::greater<zx_time_t>>
requested_presentation_times_;
uint64_t frame_number_ = 0;
constexpr static size_t kMaxOutstandingFrames = 2;
std::vector<FrameTimingsPtr> outstanding_frames_;
bool back_pressure_applied_ = false;
bool render_continuously_ = false;
// Lists all Session that have updates to apply, sorted by the earliest
// requested presentation time of each update.
std::priority_queue<
std::pair<PresentationTime, scenic_impl::SessionId>,
std::vector<std::pair<PresentationTime, scenic_impl::SessionId>>,
UpdatableSessionsComparator>
updatable_sessions_;
FrameSchedulerDelegate delegate_;
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_