forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
display_ca_layer_tree.mm
159 lines (135 loc) · 5.21 KB
/
display_ca_layer_tree.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2018 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 "ui/accelerated_widget_mac/display_ca_layer_tree.h"
#import <Cocoa/Cocoa.h>
#include <IOSurface/IOSurface.h>
#include "base/debug/dump_without_crashing.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/trace_event/trace_event.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/gfx/geometry/dip_util.h"
@interface CALayer (PrivateAPI)
- (void)setContentsChanged;
@end
namespace ui {
namespace {
// The maximum number of times to dump before throttling (to avoid sending
// thousands of crash dumps).
const int kMaxCrashDumps = 10;
} // namespace
DisplayCALayerTree::DisplayCALayerTree(CALayer* root_layer)
: root_layer_([root_layer retain]) {
// Disable the fade-in animation as the layers are added.
ScopedCAActionDisabler disabler;
// Add a flipped transparent layer as a child, so that we don't need to
// fiddle with the position of sub-layers -- they will always be at the
// origin.
flipped_layer_.reset([[CALayer alloc] init]);
[flipped_layer_ setGeometryFlipped:YES];
[flipped_layer_ setAnchorPoint:CGPointMake(0, 0)];
[flipped_layer_
setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
[root_layer_ addSublayer:flipped_layer_];
}
DisplayCALayerTree::~DisplayCALayerTree() {
// Disable the fade-out animation as the view is removed.
ScopedCAActionDisabler disabler;
[flipped_layer_ removeFromSuperlayer];
[remote_layer_ removeFromSuperlayer];
[io_surface_layer_ removeFromSuperlayer];
remote_layer_.reset();
io_surface_layer_.reset();
}
void DisplayCALayerTree::UpdateCALayerTree(
const gfx::CALayerParams& ca_layer_params) {
// Remote layers are the most common case.
if (ca_layer_params.ca_context_id) {
GotCALayerFrame(ca_layer_params.ca_context_id);
return;
}
// IOSurfaces can be sent from software compositing, or if remote layers are
// manually disabled.
if (ca_layer_params.io_surface_mach_port) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookupFromMachPort(ca_layer_params.io_surface_mach_port));
if (io_surface) {
GotIOSurfaceFrame(io_surface, ca_layer_params.pixel_size,
ca_layer_params.scale_factor);
return;
}
LOG(ERROR) << "Unable to open IOSurface for frame.";
static int dump_counter = kMaxCrashDumps;
if (dump_counter) {
dump_counter -= 1;
base::debug::DumpWithoutCrashing();
}
}
// Warn if the frame specified neither.
if (ca_layer_params.io_surface_mach_port && !ca_layer_params.ca_context_id)
LOG(ERROR) << "Frame had neither valid CAContext nor valid IOSurface.";
// If there was an error or if the frame specified nothing, then clear all
// contents.
if (io_surface_layer_ || remote_layer_) {
ScopedCAActionDisabler disabler;
[io_surface_layer_ removeFromSuperlayer];
io_surface_layer_.reset();
[remote_layer_ removeFromSuperlayer];
remote_layer_.reset();
}
}
void DisplayCALayerTree::GotCALayerFrame(uint32_t ca_context_id) {
// Early-out if the remote layer has not changed.
if ([remote_layer_ contextId] == ca_context_id)
return;
TRACE_EVENT0("ui", "DisplayCALayerTree::GotCAContextFrame");
ScopedCAActionDisabler disabler;
// Create the new CALayerHost.
base::scoped_nsobject<CALayerHost> new_remote_layer(
[[CALayerHost alloc] init]);
[new_remote_layer setContextId:ca_context_id];
[new_remote_layer
setAutoresizingMask:kCALayerMaxXMargin | kCALayerMaxYMargin];
// Update the local CALayer tree.
[flipped_layer_ addSublayer:new_remote_layer];
[remote_layer_ removeFromSuperlayer];
remote_layer_ = new_remote_layer;
// Ensure that the IOSurface layer be removed.
if (io_surface_layer_) {
[io_surface_layer_ removeFromSuperlayer];
io_surface_layer_.reset();
}
}
void DisplayCALayerTree::GotIOSurfaceFrame(
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
const gfx::Size& pixel_size,
float scale_factor) {
DCHECK(io_surface);
TRACE_EVENT0("ui", "DisplayCALayerTree::GotIOSurfaceFrame");
ScopedCAActionDisabler disabler;
// Create (if needed) and update the IOSurface layer with new content.
if (!io_surface_layer_) {
io_surface_layer_.reset([[CALayer alloc] init]);
[io_surface_layer_ setContentsGravity:kCAGravityTopLeft];
[io_surface_layer_ setAnchorPoint:CGPointMake(0, 0)];
[flipped_layer_ addSublayer:io_surface_layer_];
}
id new_contents = static_cast<id>(io_surface.get());
if (new_contents && new_contents == [io_surface_layer_ contents])
[io_surface_layer_ setContentsChanged];
else
[io_surface_layer_ setContents:new_contents];
gfx::Size bounds_dip = gfx::ConvertSizeToDIP(scale_factor, pixel_size);
[io_surface_layer_
setBounds:CGRectMake(0, 0, bounds_dip.width(), bounds_dip.height())];
if ([io_surface_layer_ contentsScale] != scale_factor)
[io_surface_layer_ setContentsScale:scale_factor];
// Ensure that the remote layer be removed.
if (remote_layer_) {
[remote_layer_ removeFromSuperlayer];
remote_layer_.reset();
}
}
} // namespace ui