blob: 83a1227ba085614984fa0b5ff0715da7291401ec [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_
#define ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_
#include <stdint.h>
#include <vector>
#include "ash/ash_export.h"
#include "ash/frame_throttler/frame_throttling_observer.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host_observer.h"
namespace aura {
class WindowTreeHost;
class Window;
}
namespace viz {
class HostFrameSinkManager;
} // namespace viz
namespace ash {
constexpr uint8_t kDefaultThrottleFps = 20;
struct ThrottleCandidates {
ThrottleCandidates();
~ThrottleCandidates();
ThrottleCandidates(const ThrottleCandidates&);
ThrottleCandidates& operator=(const ThrottleCandidates&);
// Returns true if there are no candidates to throttle.
bool IsEmpty() const;
// The frame sink ids of the browser windows to be throttled this frame.
base::flat_set<viz::FrameSinkId> browser_frame_sink_ids;
// The lacros windows that are to be throttled this frame.
base::flat_map<aura::Window*, viz::FrameSinkId> lacros_candidates;
};
class ASH_EXPORT FrameThrottlingController final
: public aura::WindowTreeHostObserver,
public aura::WindowObserver {
public:
explicit FrameThrottlingController(
viz::HostFrameSinkManager* host_frame_sink_manager);
FrameThrottlingController(const FrameThrottlingController&) = delete;
FrameThrottlingController& operator=(const FrameThrottlingController&) =
delete;
~FrameThrottlingController() override;
// ui::WindowTreeHostObserver overrides
void OnCompositingFrameSinksToThrottleUpdated(
const aura::WindowTreeHost* host,
const base::flat_set<viz::FrameSinkId>& ids) override;
// ui::WindowObserver overrides
void OnWindowDestroying(aura::Window* window) override;
void OnWindowTreeHostCreated(aura::WindowTreeHost* host);
// Starts to throttle the frame rate of |windows| at the custom
// |requested_frame_interval|. The |requested_frame_interval| is used unless
// the controller is actively throttling other windows not specified via
// StartThrottling() at a frame rate higher than the one requested here.
//
// Examples:
// Case 1: Controller is throttling a window specified via
// OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
// StartThrottling(<new window>, 30fps) is called. Both windows
// will be throttled at 30 fps.
// Case 2: Controller is throttling a window specified via
// OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
// StartThrottling(<new window>, 15fps) is called. Both windows
// will be throttled at 20 fps.
// Case 3: Controller is not throttling any windows, and
// StartThrottling(<new window>, 15fps) is called. The new window
// will be throttled at 15 fps.
//
// The higher frame rate is always picked to ensure all UIs are smooth enough,
// even if it comes at the cost of more power consumption.
//
// If the |requested_frame_interval| is zero, the default throttled frame rate
// is used internally.
void StartThrottling(
const std::vector<aura::Window*>& windows,
base::TimeDelta requested_frame_interval = base::TimeDelta());
// Ends throttling of all windows specified via StartThrottling(). The
// throttled frame rate for any remaining windows returns to the default.
void EndThrottling();
std::vector<viz::FrameSinkId> GetFrameSinkIdsToThrottle() const;
void AddArcObserver(FrameThrottlingObserver* observer);
void RemoveArcObserver(FrameThrottlingObserver* observer);
bool HasArcObserver(FrameThrottlingObserver* observer);
// The current frame interval being used. Note this applies to all windows
// that the controller is currently throttling. The viz service does not allow
// for multiple simultaneous frame rates.
base::TimeDelta current_throttled_frame_interval() const {
return current_throttled_frame_interval_;
}
// Returns 1 / current_throttled_frame_interval() rounded to the nearest
// integer. Note if the frame interval is very large, this may legitimately
// return 0 fps.
uint8_t GetCurrentThrottledFrameRate() const;
private:
void StartThrottlingArc(const std::vector<aura::Window*>& windows,
uint8_t throttled_fps);
void EndThrottlingArc();
// Collect the lacros window in the given |window|. This function recursively
// walks through |window|'s descendents and finds the lacros window if any.
// |inside_lacros| is a flag to indicate if the functions is called inside a
// lacros window. |ids| are the ids of the frame sinks that are qualified for
// throttling. |candidates|, as output, will be filled with throttle
// candidates info. |lacros_window|, as output, will be set to the lacros
// window found.
void CollectLacrosWindowsInWindow(
aura::Window* window,
bool inside_lacros,
const base::flat_set<viz::FrameSinkId>& ids,
base::flat_map<aura::Window*, viz::FrameSinkId>* candidates,
aura::Window* lacros_window = nullptr);
// Collect the lacros candidate in the given |window|. This function
// recursively walks through |window|'s descendents and finds the lacros
// candidate if any.
void CollectLacrosCandidates(
aura::Window* window,
base::flat_map<aura::Window*, viz::FrameSinkId>* candidates,
aura::Window* lacros_window);
void UpdateThrottlingOnFrameSinks();
void SetWindowsManuallyThrottled(bool windows_manually_throttled);
void SetCurrentThrottledFrameInterval();
// Whether there are any windows to throttle besides the ones specified via
// StartThrottling().
bool HasCompositingBasedThrottling() const;
void ResetThrottleCandidates(ThrottleCandidates* candidates);
viz::HostFrameSinkManager* const host_frame_sink_manager_;
base::ObserverList<FrameThrottlingObserver> arc_observers_;
// Maps aura::WindowTreeHost* to a set of FrameSinkIds to be throttled.
using WindowTreeHostMap =
base::flat_map<const aura::WindowTreeHost*, ThrottleCandidates>;
// Compositing-based throttling updates the set of FrameSinkIds per tree and
// this map keeps each aura::WindowTreeHost* to the most recently updated
// candidates, including browser and lacros windows.
WindowTreeHostMap host_to_candidates_map_;
// Window candidates (browser and lacros windows inclusive) to be throttled in
// special UI modes, such as overview and window cycling. This will be empty
// when UI is not in such modes.
ThrottleCandidates manually_throttled_candidates_;
// The default frame interval that should be used when a custom interval is
// not requested via StartThrottling(). This value is effectively immutable.
base::TimeDelta default_throttled_frame_interval_;
// The current frame interval used for throttling. Changes according to which
// windows are throttled and what frame rates were requested by the caller.
base::TimeDelta current_throttled_frame_interval_;
// The latest |requested_frame_interval| provided in StartThrottling().
// May be zero if one was not requested.
base::TimeDelta latest_custom_throttled_frame_interval_;
bool windows_manually_throttled_ = false;
};
} // namespace ash
#endif // ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_