OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/image_transport_surface_overlay_mac.h" | 5 #include "content/common/gpu/image_transport_surface_overlay_mac.h" |
6 | 6 |
7 #include <CoreGraphics/CoreGraphics.h> | 7 #include <CoreGraphics/CoreGraphics.h> |
8 #include <IOSurface/IOSurface.h> | 8 #include <IOSurface/IOSurface.h> |
9 #include <OpenGL/CGLRenderers.h> | 9 #include <OpenGL/CGLRenderers.h> |
10 #include <OpenGL/CGLTypes.h> | 10 #include <OpenGL/CGLTypes.h> |
11 #include <OpenGL/gl.h> | 11 #include <OpenGL/gl.h> |
12 #include <stddef.h> | 12 #include <stddef.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 | 15 |
16 // This type consistently causes problem on Mac, and needs to be dealt with | 16 // This type consistently causes problem on Mac, and needs to be dealt with |
17 // in a systemic way. | 17 // in a systemic way. |
18 // http://crbug.com/517208 | 18 // http://crbug.com/517208 |
19 #ifndef GL_OES_EGL_image | 19 #ifndef GL_OES_EGL_image |
20 typedef void* GLeglImageOES; | 20 typedef void* GLeglImageOES; |
21 #endif | 21 #endif |
22 | 22 |
23 #include "base/command_line.h" | |
24 #include "base/mac/scoped_cftyperef.h" | 23 #include "base/mac/scoped_cftyperef.h" |
25 #include "base/mac/sdk_forward_declarations.h" | 24 #include "content/common/gpu/ca_layer_partial_damage_tree_mac.h" |
26 #include "content/common/gpu/ca_layer_tree_mac.h" | 25 #include "content/common/gpu/ca_layer_tree_mac.h" |
27 #include "content/common/gpu/gpu_messages.h" | 26 #include "content/common/gpu/gpu_messages.h" |
28 #include "ui/accelerated_widget_mac/io_surface_context.h" | 27 #include "ui/accelerated_widget_mac/io_surface_context.h" |
29 #include "ui/base/cocoa/animation_utils.h" | 28 #include "ui/base/cocoa/animation_utils.h" |
30 #include "ui/base/cocoa/remote_layer_api.h" | 29 #include "ui/base/cocoa/remote_layer_api.h" |
31 #include "ui/base/ui_base_switches.h" | |
32 #include "ui/gfx/geometry/rect_conversions.h" | 30 #include "ui/gfx/geometry/rect_conversions.h" |
33 #include "ui/gfx/transform.h" | 31 #include "ui/gfx/transform.h" |
34 #include "ui/gl/gl_context.h" | 32 #include "ui/gl/gl_context.h" |
35 #include "ui/gl/gl_fence.h" | 33 #include "ui/gl/gl_fence.h" |
36 #include "ui/gl/gl_image_io_surface.h" | 34 #include "ui/gl/gl_image_io_surface.h" |
37 #include "ui/gl/gpu_switching_manager.h" | 35 #include "ui/gl/gpu_switching_manager.h" |
38 #include "ui/gl/scoped_api.h" | 36 #include "ui/gl/scoped_api.h" |
39 #include "ui/gl/scoped_cgl.h" | 37 #include "ui/gl/scoped_cgl.h" |
40 | 38 |
41 namespace { | 39 namespace { |
(...skipping 10 matching lines...) Expand all Loading... |
52 // the next frame. | 50 // the next frame. |
53 const double kVSyncIntervalFractionForDisplayCallback = 0.5; | 51 const double kVSyncIntervalFractionForDisplayCallback = 0.5; |
54 | 52 |
55 // If swaps arrive regularly and nearly at the vsync rate, then attempt to | 53 // If swaps arrive regularly and nearly at the vsync rate, then attempt to |
56 // make animation smooth (each frame is shown for one vsync interval) by sending | 54 // make animation smooth (each frame is shown for one vsync interval) by sending |
57 // them to the window server only when their GL work completes. If frames are | 55 // them to the window server only when their GL work completes. If frames are |
58 // not coming in with each vsync, then just throw them at the window server as | 56 // not coming in with each vsync, then just throw them at the window server as |
59 // they come. | 57 // they come. |
60 const double kMaximumVSyncsBetweenSwapsForSmoothAnimation = 1.5; | 58 const double kMaximumVSyncsBetweenSwapsForSmoothAnimation = 1.5; |
61 | 59 |
62 // When selecting a CALayer to re-use for partial damage, this is the maximum | |
63 // fraction of the merged layer's pixels that may be not-updated by the swap | |
64 // before we consider the CALayer to not be a good enough match, and create a | |
65 // new one. | |
66 const float kMaximumPartialDamageWasteFraction = 1.2f; | |
67 | |
68 // The maximum number of partial damage layers that may be created before we | |
69 // give up and remove them all (doing full damage in the process). | |
70 const size_t kMaximumPartialDamageLayers = 8; | |
71 | |
72 void CheckGLErrors(const char* msg) { | 60 void CheckGLErrors(const char* msg) { |
73 GLenum gl_error; | 61 GLenum gl_error; |
74 while ((gl_error = glGetError()) != GL_NO_ERROR) { | 62 while ((gl_error = glGetError()) != GL_NO_ERROR) { |
75 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; | 63 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; |
76 } | 64 } |
77 } | 65 } |
78 | 66 |
79 void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { | 67 void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { |
80 } | 68 } |
81 | 69 |
82 } // namespace | 70 } // namespace |
83 | 71 |
84 @interface CALayer(Private) | 72 @interface CALayer(Private) |
85 -(void)setContentsChanged; | 73 -(void)setContentsChanged; |
86 @end | 74 @end |
87 | 75 |
88 namespace content { | 76 namespace content { |
89 | 77 |
90 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( | 78 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( |
91 GpuChannelManager* manager, | 79 GpuChannelManager* manager, |
92 GpuCommandBufferStub* stub, | 80 GpuCommandBufferStub* stub, |
93 gfx::PluginWindowHandle handle) { | 81 gfx::PluginWindowHandle handle) { |
94 return new ImageTransportSurfaceOverlayMac(manager, stub, handle); | 82 return new ImageTransportSurfaceOverlayMac(manager, stub, handle); |
95 } | 83 } |
96 | 84 |
97 class ImageTransportSurfaceOverlayMac::OverlayPlane { | |
98 public: | |
99 static linked_ptr<OverlayPlane> CreateWithFrameRect( | |
100 int z_order, | |
101 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | |
102 const gfx::RectF& pixel_frame_rect, | |
103 const gfx::RectF& contents_rect) { | |
104 gfx::Transform transform; | |
105 transform.Translate(pixel_frame_rect.x(), pixel_frame_rect.y()); | |
106 return linked_ptr<OverlayPlane>( | |
107 new OverlayPlane(z_order, io_surface, contents_rect, pixel_frame_rect)); | |
108 } | |
109 | |
110 ~OverlayPlane() { | |
111 [ca_layer setContents:nil]; | |
112 [ca_layer removeFromSuperlayer]; | |
113 ca_layer.reset(); | |
114 } | |
115 | |
116 const int z_order; | |
117 const base::ScopedCFTypeRef<IOSurfaceRef> io_surface; | |
118 const gfx::RectF contents_rect; | |
119 const gfx::RectF pixel_frame_rect; | |
120 bool layer_needs_update; | |
121 base::scoped_nsobject<CALayer> ca_layer; | |
122 | |
123 void TakeCALayerFrom(OverlayPlane* other_plane) { | |
124 ca_layer.swap(other_plane->ca_layer); | |
125 } | |
126 | |
127 void UpdateProperties(float scale_factor) { | |
128 if (layer_needs_update) { | |
129 [ca_layer setOpaque:YES]; | |
130 | |
131 id new_contents = static_cast<id>(io_surface.get()); | |
132 if ([ca_layer contents] == new_contents && z_order == 0) | |
133 [ca_layer setContentsChanged]; | |
134 else | |
135 [ca_layer setContents:new_contents]; | |
136 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | |
137 | |
138 [ca_layer setAnchorPoint:CGPointZero]; | |
139 | |
140 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | |
141 [ca_layer setContentsScale:scale_factor]; | |
142 gfx::RectF dip_frame_rect = gfx::RectF(pixel_frame_rect); | |
143 dip_frame_rect.Scale(1 / scale_factor); | |
144 [ca_layer setBounds:CGRectMake(0, 0, dip_frame_rect.width(), | |
145 dip_frame_rect.height())]; | |
146 [ca_layer | |
147 setPosition:CGPointMake(dip_frame_rect.x(), dip_frame_rect.y())]; | |
148 } | |
149 static bool show_borders = | |
150 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
151 switches::kShowMacOverlayBorders); | |
152 if (show_borders) { | |
153 base::ScopedCFTypeRef<CGColorRef> color; | |
154 if (!layer_needs_update) { | |
155 // Green represents contents that are unchanged across frames. | |
156 color.reset(CGColorCreateGenericRGB(0, 1, 0, 1)); | |
157 } else { | |
158 // Red represents damaged contents. | |
159 color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); | |
160 } | |
161 [ca_layer setBorderWidth:1]; | |
162 [ca_layer setBorderColor:color]; | |
163 } | |
164 layer_needs_update = false; | |
165 } | |
166 | |
167 private: | |
168 OverlayPlane(int z_order, | |
169 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | |
170 const gfx::RectF& contents_rect, | |
171 const gfx::RectF& pixel_frame_rect) | |
172 : z_order(z_order), | |
173 io_surface(io_surface), | |
174 contents_rect(contents_rect), | |
175 pixel_frame_rect(pixel_frame_rect), | |
176 layer_needs_update(true) {} | |
177 }; | |
178 | |
179 class ImageTransportSurfaceOverlayMac::PendingSwap { | 85 class ImageTransportSurfaceOverlayMac::PendingSwap { |
180 public: | 86 public: |
181 PendingSwap() {} | 87 PendingSwap() {} |
182 ~PendingSwap() { DCHECK(!gl_fence); } | 88 ~PendingSwap() { DCHECK(!gl_fence); } |
183 | 89 |
184 gfx::Size pixel_size; | 90 gfx::Size pixel_size; |
185 float scale_factor; | 91 float scale_factor; |
186 gfx::Rect pixel_damage_rect; | 92 gfx::Rect pixel_damage_rect; |
187 | 93 |
188 linked_ptr<OverlayPlane> root_plane; | 94 scoped_ptr<CALayerPartialDamageTree> partial_damage_tree; |
189 scoped_ptr<CALayerTree> ca_layer_tree; | 95 scoped_ptr<CALayerTree> ca_layer_tree; |
190 std::vector<ui::LatencyInfo> latency_info; | 96 std::vector<ui::LatencyInfo> latency_info; |
191 | 97 |
192 // A fence object, and the CGL context it was issued in. | 98 // A fence object, and the CGL context it was issued in. |
193 base::ScopedTypeRef<CGLContextObj> cgl_context; | 99 base::ScopedTypeRef<CGLContextObj> cgl_context; |
194 scoped_ptr<gfx::GLFence> gl_fence; | 100 scoped_ptr<gfx::GLFence> gl_fence; |
195 | 101 |
196 // The earliest time that this frame may be drawn. A frame is not allowed | 102 // The earliest time that this frame may be drawn. A frame is not allowed |
197 // to draw until a fraction of the way through the vsync interval after its | 103 // to draw until a fraction of the way through the vsync interval after its |
198 // This extra latency is to allow wiggle-room for smoothness. | 104 // This extra latency is to allow wiggle-room for smoothness. |
199 base::TimeTicks earliest_display_time_allowed; | 105 base::TimeTicks earliest_display_time_allowed; |
200 | 106 |
201 // The time that this will wake up and draw, if a following swap does not | 107 // The time that this will wake up and draw, if a following swap does not |
202 // cause it to draw earlier. | 108 // cause it to draw earlier. |
203 base::TimeTicks target_display_time; | 109 base::TimeTicks target_display_time; |
204 }; | 110 }; |
205 | 111 |
206 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( | 112 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( |
207 GpuChannelManager* manager, | 113 GpuChannelManager* manager, |
208 GpuCommandBufferStub* stub, | 114 GpuCommandBufferStub* stub, |
209 gfx::PluginWindowHandle handle) | 115 gfx::PluginWindowHandle handle) |
210 : use_remote_layer_api_(ui::RemoteLayerAPISupported()), | 116 : use_remote_layer_api_(ui::RemoteLayerAPISupported()), |
211 scale_factor_(1), | 117 scale_factor_(1), |
212 gl_renderer_id_(0), | 118 gl_renderer_id_(0), |
213 vsync_parameters_valid_(false), | 119 vsync_parameters_valid_(false), |
214 next_ca_layer_z_order_(1), | |
215 display_pending_swap_timer_(true, false), | 120 display_pending_swap_timer_(true, false), |
216 weak_factory_(this) { | 121 weak_factory_(this) { |
217 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); | 122 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); |
218 ui::GpuSwitchingManager::GetInstance()->AddObserver(this); | 123 ui::GpuSwitchingManager::GetInstance()->AddObserver(this); |
219 } | 124 } |
220 | 125 |
221 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { | 126 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { |
222 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); | 127 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); |
223 Destroy(); | 128 Destroy(); |
224 } | 129 } |
(...skipping 11 matching lines...) Expand all Loading... |
236 ca_root_layer_.reset([[CALayer alloc] init]); | 141 ca_root_layer_.reset([[CALayer alloc] init]); |
237 [ca_root_layer_ setGeometryFlipped:YES]; | 142 [ca_root_layer_ setGeometryFlipped:YES]; |
238 [ca_root_layer_ setOpaque:YES]; | 143 [ca_root_layer_ setOpaque:YES]; |
239 [ca_context_ setLayer:ca_root_layer_]; | 144 [ca_context_ setLayer:ca_root_layer_]; |
240 } | 145 } |
241 return true; | 146 return true; |
242 } | 147 } |
243 | 148 |
244 void ImageTransportSurfaceOverlayMac::Destroy() { | 149 void ImageTransportSurfaceOverlayMac::Destroy() { |
245 DisplayAndClearAllPendingSwaps(); | 150 DisplayAndClearAllPendingSwaps(); |
246 current_partial_damage_planes_.clear(); | 151 |
247 current_root_plane_.reset(); | 152 current_partial_damage_tree_.reset(); |
| 153 current_ca_layer_tree_.reset(); |
248 } | 154 } |
249 | 155 |
250 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { | 156 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { |
251 return false; | 157 return false; |
252 } | 158 } |
253 | 159 |
254 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( | 160 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( |
255 const gfx::Rect& pixel_damage_rect) { | 161 const gfx::Rect& pixel_damage_rect) { |
256 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); | 162 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); |
257 next_ca_layer_z_order_ = 1; | |
258 | 163 |
259 // Use the same concept of 'now' for the entire function. The duration of | 164 // Use the same concept of 'now' for the entire function. The duration of |
260 // this function only affect the result if this function lasts across a vsync | 165 // this function only affect the result if this function lasts across a vsync |
261 // boundary, in which case smooth animation is out the window anyway. | 166 // boundary, in which case smooth animation is out the window anyway. |
262 const base::TimeTicks now = base::TimeTicks::Now(); | 167 const base::TimeTicks now = base::TimeTicks::Now(); |
263 | 168 |
264 // Decide if the frame should be drawn immediately, or if we should wait until | 169 // Decide if the frame should be drawn immediately, or if we should wait until |
265 // its work finishes before drawing immediately. | 170 // its work finishes before drawing immediately. |
266 bool display_immediately = false; | 171 bool display_immediately = false; |
267 if (vsync_parameters_valid_ && | 172 if (vsync_parameters_valid_ && |
(...skipping 10 matching lines...) Expand all Loading... |
278 if (IsFirstPendingSwapReadyToDisplay(now)) | 183 if (IsFirstPendingSwapReadyToDisplay(now)) |
279 DisplayFirstPendingSwapImmediately(); | 184 DisplayFirstPendingSwapImmediately(); |
280 } | 185 } |
281 | 186 |
282 // The remainder of the function will populate the PendingSwap structure and | 187 // The remainder of the function will populate the PendingSwap structure and |
283 // then enqueue it. | 188 // then enqueue it. |
284 linked_ptr<PendingSwap> new_swap(new PendingSwap); | 189 linked_ptr<PendingSwap> new_swap(new PendingSwap); |
285 new_swap->pixel_size = pixel_size_; | 190 new_swap->pixel_size = pixel_size_; |
286 new_swap->scale_factor = scale_factor_; | 191 new_swap->scale_factor = scale_factor_; |
287 new_swap->pixel_damage_rect = pixel_damage_rect; | 192 new_swap->pixel_damage_rect = pixel_damage_rect; |
288 new_swap->root_plane = pending_root_plane_; | 193 new_swap->partial_damage_tree.swap(pending_partial_damage_tree_); |
289 pending_root_plane_ = linked_ptr<OverlayPlane>(); | |
290 new_swap->ca_layer_tree.swap(pending_ca_layer_tree_); | 194 new_swap->ca_layer_tree.swap(pending_ca_layer_tree_); |
291 new_swap->latency_info.swap(latency_info_); | 195 new_swap->latency_info.swap(latency_info_); |
292 | 196 |
293 // A flush is required to ensure that all content appears in the layer. | 197 // A flush is required to ensure that all content appears in the layer. |
294 { | 198 { |
295 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; | 199 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
296 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); | 200 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); |
297 CheckGLErrors("before flushing frame"); | 201 CheckGLErrors("before flushing frame"); |
298 new_swap->cgl_context.reset(CGLGetCurrentContext(), | 202 new_swap->cgl_context.reset(CGLGetCurrentContext(), |
299 base::scoped_policy::RETAIN); | 203 base::scoped_policy::RETAIN); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 // If there is a fence for this object, delete it. | 263 // If there is a fence for this object, delete it. |
360 if (swap->gl_fence) { | 264 if (swap->gl_fence) { |
361 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; | 265 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
362 gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); | 266 gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); |
363 | 267 |
364 CheckGLErrors("before deleting active fence"); | 268 CheckGLErrors("before deleting active fence"); |
365 swap->gl_fence.reset(); | 269 swap->gl_fence.reset(); |
366 CheckGLErrors("while deleting active fence"); | 270 CheckGLErrors("while deleting active fence"); |
367 } | 271 } |
368 | 272 |
369 // Update the plane lists. | 273 // Update the CALayer hierarchy. |
370 { | 274 { |
371 // Sort the input planes by z-index, and remove any overlays from the | |
372 // damage rect. | |
373 gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect); | 275 gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect); |
374 ScopedCAActionDisabler disabler; | 276 ScopedCAActionDisabler disabler; |
375 UpdateRootAndPartialDamagePlanes(swap->root_plane, pixel_damage_rect); | 277 if (swap->ca_layer_tree) { |
376 UpdateRootAndPartialDamageCALayers(swap->scale_factor); | 278 swap->ca_layer_tree->CommitScheduledCALayers( |
377 UpdateCALayerTree(std::move(swap->ca_layer_tree), swap->scale_factor); | 279 ca_root_layer_.get(), std::move(current_ca_layer_tree_), |
| 280 swap->scale_factor); |
| 281 current_ca_layer_tree_.swap(swap->ca_layer_tree); |
| 282 current_partial_damage_tree_.reset(); |
| 283 } else if (swap->partial_damage_tree) { |
| 284 swap->partial_damage_tree->CommitCALayers( |
| 285 ca_root_layer_.get(), std::move(current_partial_damage_tree_), |
| 286 swap->scale_factor, swap->pixel_damage_rect); |
| 287 current_partial_damage_tree_.swap(swap->partial_damage_tree); |
| 288 current_ca_layer_tree_.reset(); |
| 289 } else { |
| 290 [ca_root_layer_ setSublayers:nil]; |
| 291 } |
| 292 swap->ca_layer_tree.reset(); |
| 293 swap->partial_damage_tree.reset(); |
378 } | 294 } |
379 | 295 |
380 // Update the latency info to reflect the swap time. | 296 // Update the latency info to reflect the swap time. |
381 base::TimeTicks swap_time = base::TimeTicks::Now(); | 297 base::TimeTicks swap_time = base::TimeTicks::Now(); |
382 for (auto latency_info : swap->latency_info) { | 298 for (auto latency_info : swap->latency_info) { |
383 latency_info.AddLatencyNumberWithTimestamp( | 299 latency_info.AddLatencyNumberWithTimestamp( |
384 ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); | 300 ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); |
385 latency_info.AddLatencyNumberWithTimestamp( | 301 latency_info.AddLatencyNumberWithTimestamp( |
386 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, | 302 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, |
387 swap_time, 1); | 303 swap_time, 1); |
388 } | 304 } |
389 | 305 |
390 // Send acknowledgement to the browser. | 306 // Send acknowledgement to the browser. |
391 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | 307 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
392 if (use_remote_layer_api_) { | 308 if (use_remote_layer_api_) { |
393 params.ca_context_id = [ca_context_ contextId]; | 309 params.ca_context_id = [ca_context_ contextId]; |
394 } else if (current_root_plane_.get()) { | 310 } else if (current_partial_damage_tree_) { |
395 params.io_surface.reset( | 311 params.io_surface.reset(IOSurfaceCreateMachPort( |
396 IOSurfaceCreateMachPort(current_root_plane_->io_surface)); | 312 current_partial_damage_tree_->RootLayerIOSurface())); |
397 } | 313 } |
398 params.size = swap->pixel_size; | 314 params.size = swap->pixel_size; |
399 params.scale_factor = swap->scale_factor; | 315 params.scale_factor = swap->scale_factor; |
400 params.latency_info.swap(swap->latency_info); | 316 params.latency_info.swap(swap->latency_info); |
401 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | 317 helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
402 | 318 |
403 // Remove this from the queue, and reset any callback timers. | 319 // Remove this from the queue, and reset any callback timers. |
404 pending_swaps_.pop_front(); | 320 pending_swaps_.pop_front(); |
405 } | 321 } |
406 | 322 |
407 void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes( | |
408 const linked_ptr<OverlayPlane>& new_root_plane, | |
409 const gfx::RectF& pixel_damage_rect) { | |
410 std::list<linked_ptr<OverlayPlane>> old_partial_damage_planes; | |
411 old_partial_damage_planes.swap(current_partial_damage_planes_); | |
412 linked_ptr<OverlayPlane> plane_for_swap; | |
413 | |
414 // If there is no new root plane, remove everything. | |
415 if (!new_root_plane.get()) { | |
416 old_partial_damage_planes.clear(); | |
417 current_root_plane_.reset(); | |
418 return; | |
419 } | |
420 | |
421 // If the frame's size changed, if we haven't updated the root layer, if | |
422 // we have full damage, or if we don't support remote layers, then use the | |
423 // root layer directly. | |
424 if (!use_remote_layer_api_ || !current_root_plane_.get() || | |
425 current_root_plane_->pixel_frame_rect != | |
426 new_root_plane->pixel_frame_rect || | |
427 pixel_damage_rect == new_root_plane->pixel_frame_rect) { | |
428 plane_for_swap = new_root_plane; | |
429 } | |
430 | |
431 // Walk though the existing partial damage layers and see if there is one that | |
432 // is appropriate to re-use. | |
433 if (!plane_for_swap.get() && !pixel_damage_rect.IsEmpty()) { | |
434 gfx::RectF plane_to_reuse_dip_enlarged_rect; | |
435 | |
436 // Find the last partial damage plane to re-use the CALayer from. Grow the | |
437 // new rect for this layer to include this damage, and all nearby partial | |
438 // damage layers. | |
439 linked_ptr<OverlayPlane> plane_to_reuse; | |
440 for (auto& old_plane : old_partial_damage_planes) { | |
441 gfx::RectF dip_enlarged_rect = old_plane->pixel_frame_rect; | |
442 dip_enlarged_rect.Union(pixel_damage_rect); | |
443 | |
444 // Compute the fraction of the pixels that would not be updated by this | |
445 // swap. If it is too big, try another layer. | |
446 float waste_fraction = dip_enlarged_rect.size().GetArea() * 1.f / | |
447 pixel_damage_rect.size().GetArea(); | |
448 if (waste_fraction > kMaximumPartialDamageWasteFraction) | |
449 continue; | |
450 | |
451 plane_to_reuse = old_plane; | |
452 plane_to_reuse_dip_enlarged_rect.Union(dip_enlarged_rect); | |
453 } | |
454 | |
455 if (plane_to_reuse.get()) { | |
456 gfx::RectF enlarged_contents_rect = plane_to_reuse_dip_enlarged_rect; | |
457 enlarged_contents_rect.Scale( | |
458 1. / new_root_plane->pixel_frame_rect.width(), | |
459 1. / new_root_plane->pixel_frame_rect.height()); | |
460 | |
461 plane_for_swap = OverlayPlane::CreateWithFrameRect( | |
462 0, new_root_plane->io_surface, plane_to_reuse_dip_enlarged_rect, | |
463 enlarged_contents_rect); | |
464 | |
465 plane_for_swap->TakeCALayerFrom(plane_to_reuse.get()); | |
466 if (plane_to_reuse != old_partial_damage_planes.back()) | |
467 [plane_for_swap->ca_layer removeFromSuperlayer]; | |
468 } | |
469 } | |
470 | |
471 // If we haven't found an appropriate layer to re-use, create a new one, if | |
472 // we haven't already created too many. | |
473 if (!plane_for_swap.get() && !pixel_damage_rect.IsEmpty() && | |
474 old_partial_damage_planes.size() < kMaximumPartialDamageLayers) { | |
475 gfx::RectF contents_rect = gfx::RectF(pixel_damage_rect); | |
476 contents_rect.Scale(1. / new_root_plane->pixel_frame_rect.width(), | |
477 1. / new_root_plane->pixel_frame_rect.height()); | |
478 plane_for_swap = OverlayPlane::CreateWithFrameRect( | |
479 0, new_root_plane->io_surface, pixel_damage_rect, contents_rect); | |
480 } | |
481 | |
482 // And if we still don't have a layer, use the root layer. | |
483 if (!plane_for_swap.get() && !pixel_damage_rect.IsEmpty()) | |
484 plane_for_swap = new_root_plane; | |
485 | |
486 // Walk all old partial damage planes. Remove anything that is now completely | |
487 // covered, and move everything else into the new | |
488 // |current_partial_damage_planes_|. | |
489 for (auto& old_plane : old_partial_damage_planes) { | |
490 // Intersect the planes' frames with the new root plane to ensure that | |
491 // they don't get kept alive inappropriately. | |
492 gfx::RectF old_plane_frame_rect = old_plane->pixel_frame_rect; | |
493 old_plane_frame_rect.Intersect(new_root_plane->pixel_frame_rect); | |
494 | |
495 bool old_plane_covered_by_swap = false; | |
496 if (plane_for_swap.get() && | |
497 plane_for_swap->pixel_frame_rect.Contains(old_plane_frame_rect)) { | |
498 old_plane_covered_by_swap = true; | |
499 } | |
500 if (!old_plane_covered_by_swap) { | |
501 DCHECK(old_plane->ca_layer); | |
502 current_partial_damage_planes_.push_back(old_plane); | |
503 } | |
504 } | |
505 | |
506 // Finally, add the new swap's plane at the back of the list, if it exists. | |
507 if (plane_for_swap == new_root_plane) { | |
508 current_root_plane_ = new_root_plane; | |
509 } else if (plane_for_swap.get()) { | |
510 current_partial_damage_planes_.push_back(plane_for_swap); | |
511 } | |
512 } | |
513 | |
514 void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamageCALayers( | |
515 float scale_factor) { | |
516 if (!use_remote_layer_api_) { | |
517 DCHECK(current_partial_damage_planes_.empty()); | |
518 return; | |
519 } | |
520 | |
521 // Allocate and update CALayers for the backbuffer and partial damage layers. | |
522 if (current_root_plane_.get()) { | |
523 if (!current_root_plane_->ca_layer) { | |
524 current_root_plane_->ca_layer.reset([[CALayer alloc] init]); | |
525 [ca_root_layer_ setSublayers:nil]; | |
526 [ca_root_layer_ addSublayer:current_root_plane_->ca_layer]; | |
527 } | |
528 } | |
529 for (auto& plane : current_partial_damage_planes_) { | |
530 if (!plane->ca_layer) { | |
531 DCHECK(plane == current_partial_damage_planes_.back()); | |
532 plane->ca_layer.reset([[CALayer alloc] init]); | |
533 } | |
534 if (![plane->ca_layer superlayer]) { | |
535 DCHECK(plane == current_partial_damage_planes_.back()); | |
536 [ca_root_layer_ addSublayer:plane->ca_layer]; | |
537 } | |
538 } | |
539 if (current_root_plane_.get()) | |
540 current_root_plane_->UpdateProperties(scale_factor); | |
541 for (auto& plane : current_partial_damage_planes_) | |
542 plane->UpdateProperties(scale_factor); | |
543 } | |
544 | |
545 void ImageTransportSurfaceOverlayMac::UpdateCALayerTree( | |
546 scoped_ptr<CALayerTree> ca_layer_tree, | |
547 float scale_factor) { | |
548 if (ca_layer_tree) { | |
549 ca_layer_tree->CommitScheduledCALayers( | |
550 ca_root_layer_.get(), std::move(current_ca_layer_tree_), scale_factor); | |
551 current_ca_layer_tree_.swap(ca_layer_tree); | |
552 ca_layer_tree.reset(); | |
553 } else { | |
554 current_ca_layer_tree_.reset(); | |
555 } | |
556 } | |
557 | |
558 void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() { | 323 void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() { |
559 TRACE_EVENT0("gpu", | 324 TRACE_EVENT0("gpu", |
560 "ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps"); | 325 "ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps"); |
561 while (!pending_swaps_.empty()) | 326 while (!pending_swaps_.empty()) |
562 DisplayFirstPendingSwapImmediately(); | 327 DisplayFirstPendingSwapImmediately(); |
563 } | 328 } |
564 | 329 |
565 void ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback() { | 330 void ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback() { |
566 TRACE_EVENT0("gpu", | 331 TRACE_EVENT0("gpu", |
567 "ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback"); | 332 "ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback"); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
638 const gfx::Rect& pixel_frame_rect, | 403 const gfx::Rect& pixel_frame_rect, |
639 const gfx::RectF& crop_rect) { | 404 const gfx::RectF& crop_rect) { |
640 if (transform != gfx::OVERLAY_TRANSFORM_NONE) { | 405 if (transform != gfx::OVERLAY_TRANSFORM_NONE) { |
641 DLOG(ERROR) << "Invalid overlay plane transform."; | 406 DLOG(ERROR) << "Invalid overlay plane transform."; |
642 return false; | 407 return false; |
643 } | 408 } |
644 if (z_order) { | 409 if (z_order) { |
645 DLOG(ERROR) << "Invalid non-zero Z order."; | 410 DLOG(ERROR) << "Invalid non-zero Z order."; |
646 return false; | 411 return false; |
647 } | 412 } |
648 | 413 if (pending_partial_damage_tree_) { |
649 pending_root_plane_ = OverlayPlane::CreateWithFrameRect( | 414 DLOG(ERROR) << "Only one overlay per swap is allowed."; |
650 z_order, static_cast<gl::GLImageIOSurface*>(image)->io_surface(), | 415 return false; |
651 gfx::RectF(pixel_frame_rect), crop_rect); | 416 } |
| 417 pending_partial_damage_tree_.reset(new CALayerPartialDamageTree( |
| 418 use_remote_layer_api_, |
| 419 static_cast<gl::GLImageIOSurface*>(image)->io_surface(), |
| 420 pixel_frame_rect)); |
652 return true; | 421 return true; |
653 } | 422 } |
654 | 423 |
655 bool ImageTransportSurfaceOverlayMac::ScheduleCALayer( | 424 bool ImageTransportSurfaceOverlayMac::ScheduleCALayer( |
656 gl::GLImage* contents_image, | 425 gl::GLImage* contents_image, |
657 const gfx::RectF& contents_rect, | 426 const gfx::RectF& contents_rect, |
658 float opacity, | 427 float opacity, |
659 unsigned background_color, | 428 unsigned background_color, |
660 unsigned edge_aa_mask, | 429 unsigned edge_aa_mask, |
661 const gfx::RectF& rect, | 430 const gfx::RectF& rect, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 // Compute the previous vsync time. | 509 // Compute the previous vsync time. |
741 base::TimeTicks previous_vsync = | 510 base::TimeTicks previous_vsync = |
742 vsync_interval_ * ((from - vsync_timebase_) / vsync_interval_) + | 511 vsync_interval_ * ((from - vsync_timebase_) / vsync_interval_) + |
743 vsync_timebase_; | 512 vsync_timebase_; |
744 | 513 |
745 // Return |interval_fraction| through the next vsync. | 514 // Return |interval_fraction| through the next vsync. |
746 return previous_vsync + (1 + interval_fraction) * vsync_interval_; | 515 return previous_vsync + (1 + interval_fraction) * vsync_interval_; |
747 } | 516 } |
748 | 517 |
749 } // namespace content | 518 } // namespace content |
OLD | NEW |