Commit 22923754 authored by Sammie Quon's avatar Sammie Quon Committed by Commit Bot

wm: Create alt tab WindowPreviewView only when seen.

This will improve fade in performance by delaying the creation of the
heavy view until needed. It will transfer some delay to the tabbing
animation but I think the tradeoff is worth it as, for example with
7 initially offscreen windows:
  1) The performance drop will be split 7 ways (not exactly but rough
  estimate).
  2) Fade in performance is about 3x worse right now and arguably more
  noticeable.

Ran the test below (modified a bit) for 8 and 16 windows, 20 times each
in a loop. Values are first fade in/average fade in/average container,
machine is krane. Though would need to check the dashboards for the
real truth.

Before 8: 6/15/90
Before 16: 4/5/50
After 8: 18/61/89
After 16: 10/58/50

Test: Tast test ui.WindowCyclePerf
Bug: 1078159
Change-Id: I2e7252089b7686b109cd5b196ba847eac29e97bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2197145
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#768907}
parent adf4028d
......@@ -118,20 +118,41 @@ class CustomWindowTargeter : public aura::WindowTargeter {
class WindowCycleItemView : public WindowMiniView {
public:
explicit WindowCycleItemView(aura::Window* window) : WindowMiniView(window) {
SetShowPreview(/*show=*/true);
UpdatePreviewRoundedCorners(/*show=*/true);
SetFocusBehavior(FocusBehavior::ALWAYS);
UpdateIconView();
}
WindowCycleItemView(const WindowCycleItemView&) = delete;
WindowCycleItemView& operator=(const WindowCycleItemView&) = delete;
~WindowCycleItemView() override = default;
// Shows the preview and icon. For performance reasons, these are not created
// on construction. This should be called at most one time during the lifetime
// of |this|.
void ShowPreview() {
DCHECK(!preview_view());
UpdateIconView();
SetShowPreview(/*show=*/true);
UpdatePreviewRoundedCorners(/*show=*/true);
}
private:
// WindowMiniView:
// Returns the size for the preview view, scaled to fit within the max bounds.
// Scaling is always 1:1 and we only scale down, never up.
gfx::Size GetPreviewViewSize() const override {
// When the preview is not shown, do an estimate of the expected size.
// |this| will not be visible anyways, and will get corrected once
// ShowPreview() is called.
if (!preview_view()) {
gfx::SizeF source_size(source_window()->bounds().size());
// Windows may have no size in tests.
if (source_size.IsEmpty())
return gfx::Size();
const float aspect_ratio = source_size.width() / source_size.height();
return gfx::Size(kFixedPreviewHeightDp * aspect_ratio,
kFixedPreviewHeightDp);
}
// Returns the size for the preview view, scaled to fit within the max
// bounds. Scaling is always 1:1 and we only scale down, never up.
gfx::Size preview_pref_size = preview_view()->GetPreferredSize();
if (preview_pref_size.width() > kMaxPreviewWidthDp ||
preview_pref_size.height() > kFixedPreviewHeightDp) {
......@@ -149,6 +170,9 @@ class WindowCycleItemView : public WindowMiniView {
void Layout() override {
WindowMiniView::Layout();
if (!preview_view())
return;
// Show the backdrop if the preview view does not take up all the bounds
// allocated for it.
gfx::Rect preview_max_bounds = GetContentsBounds();
......@@ -187,6 +211,12 @@ class WindowCycleView : public views::WidgetDelegateView,
explicit WindowCycleView(const WindowCycleList::WindowList& windows) {
DCHECK(!windows.empty());
// Start the occlusion tracker pauser. It's used to increase smoothness for
// the fade in but we also create windows here which may occlude other
// windows.
occlusion_tracker_pauser_ =
std::make_unique<aura::WindowOcclusionTracker::ScopedPause>();
// The layer for |this| is responsible for showing color, background blur
// and fading in.
SetPaintToLayer(ui::LAYER_SOLID_COLOR);
......@@ -220,6 +250,8 @@ class WindowCycleView : public views::WidgetDelegateView,
auto* view = mirror_container_->AddChildView(
std::make_unique<WindowCycleItemView>(window));
window_view_map_[window] = view;
no_previews_set_.insert(view);
}
// The insets in the WindowCycleItemView are coming from its border, which
......@@ -237,6 +269,7 @@ class WindowCycleView : public views::WidgetDelegateView,
void FadeInLayer() {
DCHECK(GetWidget());
fade_in_fps_counter_ =
std::make_unique<FpsCounter>(GetWidget()->GetCompositor());
......@@ -271,11 +304,13 @@ class WindowCycleView : public views::WidgetDelegateView,
void HandleWindowDestruction(aura::Window* destroying_window,
aura::Window* new_target) {
auto view_iter = window_view_map_.find(destroying_window);
views::View* preview = view_iter->second;
WindowCycleItemView* preview = view_iter->second;
views::View* parent = preview->parent();
DCHECK_EQ(mirror_container_, parent);
window_view_map_.erase(view_iter);
no_previews_set_.erase(preview);
delete preview;
// With one of its children now gone, we must re-layout
// |mirror_container_|. This must happen before SetTargetWindow() to make
// sure our own Layout() works correctly when it's calculating highlight
......@@ -286,6 +321,7 @@ class WindowCycleView : public views::WidgetDelegateView,
void DestroyContents() {
window_view_map_.clear();
no_previews_set_.clear();
target_window_ = nullptr;
RemoveAllChildViews(true);
}
......@@ -343,6 +379,22 @@ class WindowCycleView : public views::WidgetDelegateView,
settings->SetAnimationMetricsReporter(this);
}
mirror_container_->SetBoundsRect(container_bounds);
// If an element in |no_previews_set_| is no onscreen (its bounds in |this|
// coordinates intersects |this|), create the rest of its elements and
// remove it from the set.
const gfx::RectF local_bounds(GetLocalBounds());
for (auto it = no_previews_set_.begin(); it != no_previews_set_.end();) {
WindowCycleItemView* view = *it;
gfx::RectF bounds(view->GetLocalBounds());
views::View::ConvertRectToTarget(view, this, &bounds);
if (bounds.Intersects(local_bounds)) {
view->ShowPreview();
it = no_previews_set_.erase(it);
} else {
++it;
}
}
}
View* GetInitiallyFocusedView() override {
......@@ -356,6 +408,7 @@ class WindowCycleView : public views::WidgetDelegateView,
if (smoothness > 0)
UMA_HISTOGRAM_PERCENTAGE(kShowAnimationSmoothness, smoothness);
fade_in_fps_counter_.reset();
occlusion_tracker_pauser_.reset();
}
// ui::AnimationMetricsReporter:
......@@ -371,8 +424,18 @@ class WindowCycleView : public views::WidgetDelegateView,
views::View* mirror_container_ = nullptr;
aura::Window* target_window_ = nullptr;
// Set which contains items which have been created but have some of their
// performance heavy elements not created yet. These elements will be created
// once onscreen to improve fade in performance, then removed from this set.
base::flat_set<WindowCycleItemView*> no_previews_set_;
// Records the animation smoothness of the fade in animation.
std::unique_ptr<FpsCounter> fade_in_fps_counter_;
// Used for preventng occlusion state computations for the duration of the
// fade in animation.
std::unique_ptr<aura::WindowOcclusionTracker::ScopedPause>
occlusion_tracker_pauser_;
};
WindowCycleList::WindowCycleList(const WindowList& windows)
......
......@@ -63,8 +63,6 @@ class ASH_EXPORT WindowMiniView : public views::View,
// image from |source_window_|.
void UpdateIconView();
WmHighlightItemBorder* border_ptr() { return border_ptr_; }
// Returns the bounds where the backdrop and preview should go.
gfx::Rect GetContentAreaBounds() const;
......@@ -88,6 +86,9 @@ class ASH_EXPORT WindowMiniView : public views::View,
void OnWindowDestroying(aura::Window* window) override;
void OnWindowTitleChanged(aura::Window* window) override;
aura::Window* source_window() const { return source_window_; }
WmHighlightItemBorder* border_ptr() { return border_ptr_; }
private:
// The window this class is meant to be a header for. This class also may
// optionally show a mirrored view of this window.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment