This repository has been archived by the owner on Apr 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mac overlays: Clean up partial swap code
Remove use of linked_ptr, because it's not necessary now that we have C++11 support. Separate out functions to be a bit easier to read and follow. Remove unnecessary uses of RectF when Rect would do. BUG=533681 Review URL: https://codereview.chromium.org/1643043002 Cr-Commit-Position: refs/heads/master@{#372707} (cherry picked from commit 4d0aa96) Mac overlays: Move CALayerPartialDamageTree to its own file Direct copy-paste, no changes. BUG=533681 TBR=erikchen Review URL: https://codereview.chromium.org/1647523002 Cr-Commit-Position: refs/heads/master@{#371871} (cherry picked from commit 9a9014a) Mac overlays: Isolate partial swap support The logic to maintain a CALayer tree for partial swap support is complicated and should be removed, but that would compromise battery usage. Once the CoreAniamtion renderer is handling ~99% of the frames, we can remove it. In the mean time, isolate it. Create a CALayerPartialDamageTree to track the layer tree of partially swapped backbuffers. Do this in-place to minimize diffs, so that this patch can be reasonably reviewed. A follow-on patch will move it to a separate file. Slightly reorganize the logic so that CALayerPartialDamageTree matches the general structure of CALayerTree, where this a pending (not swapped) tree, a tree for each pending swap, and a tree for what is currently being displayed. BUG=533681 Review URL: https://codereview.chromium.org/1640093002 Cr-Commit-Position: refs/heads/master@{#371831} (cherry picked from commit 8aa00fc) Review URL: https://codereview.chromium.org/1661453003 . Cr-Commit-Position: refs/branch-heads/2623@{#249} Cr-Branched-From: 92d7753-refs/heads/master@{#369907}
- Loading branch information
1 parent
1fb5ee6
commit 04f51c6
Showing
5 changed files
with
376 additions
and
281 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2016 The Chromium 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 CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ | ||
#define CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ | ||
|
||
#include <IOSurface/IOSurface.h> | ||
#include <QuartzCore/QuartzCore.h> | ||
#include <deque> | ||
|
||
#include "base/mac/scoped_cftyperef.h" | ||
#include "base/memory/scoped_ptr.h" | ||
#include "ui/gfx/geometry/rect.h" | ||
#include "ui/gfx/geometry/rect_f.h" | ||
|
||
namespace content { | ||
|
||
class CALayerPartialDamageTree { | ||
public: | ||
CALayerPartialDamageTree(bool allow_partial_swap, | ||
base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | ||
const gfx::Rect& pixel_frame_rect); | ||
~CALayerPartialDamageTree(); | ||
|
||
base::ScopedCFTypeRef<IOSurfaceRef> RootLayerIOSurface(); | ||
void CommitCALayers(CALayer* superlayer, | ||
scoped_ptr<CALayerPartialDamageTree> old_tree, | ||
float scale_factor, | ||
const gfx::Rect& pixel_damage_rect); | ||
|
||
private: | ||
class OverlayPlane; | ||
|
||
// This will populate |partial_damage_planes_|, potentially re-using the | ||
// CALayers and |partial_damage_planes_| from |old_tree|. After this function | ||
// completes, the back() of |partial_damage_planes_| is the plane that will | ||
// be updated this frame (and if it is empty, then the root plane will be | ||
// updated). | ||
void UpdatePartialDamagePlanes(CALayerPartialDamageTree* old_tree, | ||
const gfx::Rect& pixel_damage_rect); | ||
|
||
void UpdateRootAndPartialDamagePlanes( | ||
scoped_ptr<CALayerPartialDamageTree> old_tree, | ||
const gfx::Rect& pixel_damage_rect); | ||
|
||
void UpdateCALayers(CALayer* superlayer, float scale_factor); | ||
|
||
const bool allow_partial_swap_; | ||
scoped_ptr<OverlayPlane> root_plane_; | ||
std::deque<scoped_ptr<OverlayPlane>> partial_damage_planes_; | ||
}; | ||
|
||
} // content | ||
|
||
#endif // CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
// Copyright 2016 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "content/common/gpu/ca_layer_partial_damage_tree_mac.h" | ||
|
||
#include "base/command_line.h" | ||
#include "base/mac/scoped_nsobject.h" | ||
#include "base/mac/sdk_forward_declarations.h" | ||
#include "ui/base/ui_base_switches.h" | ||
#include "ui/gfx/transform.h" | ||
|
||
@interface CALayer(Private) | ||
-(void)setContentsChanged; | ||
@end | ||
|
||
namespace content { | ||
namespace { | ||
|
||
// When selecting a CALayer to re-use for partial damage, this is the maximum | ||
// fraction of the merged layer's pixels that may be not-updated by the swap | ||
// before we consider the CALayer to not be a good enough match, and create a | ||
// new one. | ||
const float kMaximumPartialDamageWasteFraction = 1.2f; | ||
|
||
// The maximum number of partial damage layers that may be created before we | ||
// give up and remove them all (doing full damage in the process). | ||
const size_t kMaximumPartialDamageLayers = 8; | ||
|
||
} // namespace | ||
|
||
class CALayerPartialDamageTree::OverlayPlane { | ||
public: | ||
OverlayPlane(base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | ||
const gfx::Rect& pixel_frame_rect, | ||
const gfx::RectF& contents_rect) | ||
: io_surface(io_surface), | ||
contents_rect(contents_rect), | ||
pixel_frame_rect(pixel_frame_rect), | ||
layer_needs_update(true) {} | ||
|
||
~OverlayPlane() { | ||
[ca_layer setContents:nil]; | ||
[ca_layer removeFromSuperlayer]; | ||
ca_layer.reset(); | ||
} | ||
|
||
const base::ScopedCFTypeRef<IOSurfaceRef> io_surface; | ||
const gfx::RectF contents_rect; | ||
const gfx::Rect pixel_frame_rect; | ||
bool layer_needs_update; | ||
base::scoped_nsobject<CALayer> ca_layer; | ||
|
||
void TakeCALayerFrom(OverlayPlane* other_plane) { | ||
ca_layer.swap(other_plane->ca_layer); | ||
} | ||
|
||
void UpdateProperties(float scale_factor) { | ||
if (layer_needs_update) { | ||
[ca_layer setOpaque:YES]; | ||
|
||
id new_contents = static_cast<id>(io_surface.get()); | ||
if ([ca_layer contents] == new_contents) | ||
[ca_layer setContentsChanged]; | ||
else | ||
[ca_layer setContents:new_contents]; | ||
[ca_layer setContentsRect:contents_rect.ToCGRect()]; | ||
|
||
[ca_layer setAnchorPoint:CGPointZero]; | ||
|
||
if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | ||
[ca_layer setContentsScale:scale_factor]; | ||
gfx::RectF dip_frame_rect = gfx::RectF(pixel_frame_rect); | ||
dip_frame_rect.Scale(1 / scale_factor); | ||
[ca_layer setBounds:CGRectMake(0, 0, dip_frame_rect.width(), | ||
dip_frame_rect.height())]; | ||
[ca_layer | ||
setPosition:CGPointMake(dip_frame_rect.x(), dip_frame_rect.y())]; | ||
} | ||
static bool show_borders = | ||
base::CommandLine::ForCurrentProcess()->HasSwitch( | ||
switches::kShowMacOverlayBorders); | ||
if (show_borders) { | ||
base::ScopedCFTypeRef<CGColorRef> color; | ||
if (!layer_needs_update) { | ||
// Green represents contents that are unchanged across frames. | ||
color.reset(CGColorCreateGenericRGB(0, 1, 0, 1)); | ||
} else { | ||
// Red represents damaged contents. | ||
color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); | ||
} | ||
[ca_layer setBorderWidth:1]; | ||
[ca_layer setBorderColor:color]; | ||
} | ||
layer_needs_update = false; | ||
} | ||
|
||
private: | ||
}; | ||
|
||
void CALayerPartialDamageTree::UpdatePartialDamagePlanes( | ||
CALayerPartialDamageTree* old_tree, | ||
const gfx::Rect& pixel_damage_rect) { | ||
// Don't create partial damage layers if partial swap is disabled. | ||
if (!allow_partial_swap_) | ||
return; | ||
// Only create partial damage layers when building on top of an existing tree. | ||
if (!old_tree) | ||
return; | ||
// If the frame size has changed, discard all of the old partial damage | ||
// layers. | ||
if (old_tree->root_plane_->pixel_frame_rect != root_plane_->pixel_frame_rect) | ||
return; | ||
// If there is full damage, discard all of the old partial damage layers. | ||
if (pixel_damage_rect == root_plane_->pixel_frame_rect) | ||
return; | ||
|
||
// If there is no damage, don't change anything. | ||
if (pixel_damage_rect.IsEmpty()) { | ||
std::swap(partial_damage_planes_, old_tree->partial_damage_planes_); | ||
return; | ||
} | ||
|
||
// Find the last partial damage plane to re-use the CALayer from. Grow the | ||
// new rect for this layer to include this damage, and all nearby partial | ||
// damage layers. | ||
scoped_ptr<OverlayPlane> plane_for_swap; | ||
{ | ||
auto plane_to_reuse_iter = old_tree->partial_damage_planes_.end(); | ||
gfx::Rect plane_to_reuse_enlarged_pixel_damage_rect; | ||
|
||
for (auto old_plane_iter = old_tree->partial_damage_planes_.begin(); | ||
old_plane_iter != old_tree->partial_damage_planes_.end(); | ||
++old_plane_iter) { | ||
gfx::Rect enlarged_pixel_damage_rect = | ||
(*old_plane_iter)->pixel_frame_rect; | ||
enlarged_pixel_damage_rect.Union(pixel_damage_rect); | ||
|
||
// Compute the fraction of the pixels that would not be updated by this | ||
// swap. If it is too big, try another layer. | ||
float waste_fraction = enlarged_pixel_damage_rect.size().GetArea() * 1.f / | ||
pixel_damage_rect.size().GetArea(); | ||
if (waste_fraction > kMaximumPartialDamageWasteFraction) | ||
continue; | ||
|
||
plane_to_reuse_iter = old_plane_iter; | ||
plane_to_reuse_enlarged_pixel_damage_rect.Union( | ||
enlarged_pixel_damage_rect); | ||
} | ||
if (plane_to_reuse_iter != old_tree->partial_damage_planes_.end()) { | ||
gfx::RectF enlarged_contents_rect = | ||
gfx::RectF(plane_to_reuse_enlarged_pixel_damage_rect); | ||
enlarged_contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(), | ||
1. / root_plane_->pixel_frame_rect.height()); | ||
|
||
plane_for_swap.reset(new OverlayPlane( | ||
root_plane_->io_surface, plane_to_reuse_enlarged_pixel_damage_rect, | ||
enlarged_contents_rect)); | ||
|
||
plane_for_swap->TakeCALayerFrom((*plane_to_reuse_iter).get()); | ||
if (*plane_to_reuse_iter != old_tree->partial_damage_planes_.back()) { | ||
CALayer* superlayer = [plane_for_swap->ca_layer superlayer]; | ||
[plane_for_swap->ca_layer removeFromSuperlayer]; | ||
[superlayer addSublayer:plane_for_swap->ca_layer]; | ||
} | ||
} | ||
} | ||
|
||
// If we haven't found an appropriate layer to re-use, create a new one, if | ||
// we haven't already created too many. | ||
if (!plane_for_swap.get() && | ||
old_tree->partial_damage_planes_.size() < kMaximumPartialDamageLayers) { | ||
gfx::RectF contents_rect = gfx::RectF(pixel_damage_rect); | ||
contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(), | ||
1. / root_plane_->pixel_frame_rect.height()); | ||
plane_for_swap.reset(new OverlayPlane(root_plane_->io_surface, | ||
pixel_damage_rect, contents_rect)); | ||
} | ||
|
||
// And if we still don't have a layer, do full damage. | ||
if (!plane_for_swap.get()) | ||
return; | ||
|
||
// Walk all old partial damage planes. Remove anything that is now completely | ||
// covered, and move everything else into the new |partial_damage_planes_|. | ||
for (auto& old_plane : old_tree->partial_damage_planes_) { | ||
if (!old_plane.get()) | ||
continue; | ||
// Intersect the planes' frames with the new root plane to ensure that | ||
// they don't get kept alive inappropriately. | ||
gfx::Rect old_plane_frame_rect = old_plane->pixel_frame_rect; | ||
old_plane_frame_rect.Intersect(root_plane_->pixel_frame_rect); | ||
|
||
bool old_plane_covered_by_swap = false; | ||
if (plane_for_swap.get() && | ||
plane_for_swap->pixel_frame_rect.Contains(old_plane_frame_rect)) { | ||
old_plane_covered_by_swap = true; | ||
} | ||
if (!old_plane_covered_by_swap) { | ||
DCHECK(old_plane->ca_layer); | ||
partial_damage_planes_.push_back(std::move(old_plane)); | ||
} | ||
} | ||
|
||
partial_damage_planes_.push_back(std::move(plane_for_swap)); | ||
} | ||
|
||
void CALayerPartialDamageTree::UpdateRootAndPartialDamagePlanes( | ||
scoped_ptr<CALayerPartialDamageTree> old_tree, | ||
const gfx::Rect& pixel_damage_rect) { | ||
// First update the partial damage tree. | ||
UpdatePartialDamagePlanes(old_tree.get(), pixel_damage_rect); | ||
if (old_tree) { | ||
if (partial_damage_planes_.empty()) { | ||
// If there are no partial damage planes, then we will be updating the | ||
// root layer. Take the CALayer from the old tree. | ||
root_plane_->TakeCALayerFrom(old_tree->root_plane_.get()); | ||
} else { | ||
// If there is a partial damage tree, then just take the old plane | ||
// from the previous frame, so that there is no update to it. | ||
root_plane_.swap(old_tree->root_plane_); | ||
} | ||
} | ||
} | ||
|
||
void CALayerPartialDamageTree::UpdateCALayers(CALayer* superlayer, | ||
float scale_factor) { | ||
if (!allow_partial_swap_) { | ||
DCHECK(partial_damage_planes_.empty()); | ||
return; | ||
} | ||
|
||
// Allocate and update CALayers for the backbuffer and partial damage layers. | ||
if (!root_plane_->ca_layer) { | ||
DCHECK(partial_damage_planes_.empty()); | ||
root_plane_->ca_layer.reset([[CALayer alloc] init]); | ||
[superlayer setSublayers:nil]; | ||
[superlayer addSublayer:root_plane_->ca_layer]; | ||
} | ||
for (auto& plane : partial_damage_planes_) { | ||
if (!plane->ca_layer) { | ||
DCHECK(plane == partial_damage_planes_.back()); | ||
plane->ca_layer.reset([[CALayer alloc] init]); | ||
} | ||
if (![plane->ca_layer superlayer]) { | ||
DCHECK(plane == partial_damage_planes_.back()); | ||
[superlayer addSublayer:plane->ca_layer]; | ||
} | ||
} | ||
root_plane_->UpdateProperties(scale_factor); | ||
for (auto& plane : partial_damage_planes_) | ||
plane->UpdateProperties(scale_factor); | ||
} | ||
|
||
CALayerPartialDamageTree::CALayerPartialDamageTree( | ||
bool allow_partial_swap, | ||
base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | ||
const gfx::Rect& pixel_frame_rect) | ||
: allow_partial_swap_(allow_partial_swap) { | ||
root_plane_.reset( | ||
new OverlayPlane(io_surface, pixel_frame_rect, gfx::RectF(0, 0, 1, 1))); | ||
} | ||
|
||
CALayerPartialDamageTree::~CALayerPartialDamageTree() {} | ||
|
||
base::ScopedCFTypeRef<IOSurfaceRef> | ||
CALayerPartialDamageTree::RootLayerIOSurface() { | ||
return root_plane_->io_surface; | ||
} | ||
|
||
void CALayerPartialDamageTree::CommitCALayers( | ||
CALayer* superlayer, | ||
scoped_ptr<CALayerPartialDamageTree> old_tree, | ||
float scale_factor, | ||
const gfx::Rect& pixel_damage_rect) { | ||
UpdateRootAndPartialDamagePlanes(std::move(old_tree), pixel_damage_rect); | ||
UpdateCALayers(superlayer, scale_factor); | ||
} | ||
|
||
} // namespace content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.