OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" | 5 #include "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" |
6 | 6 |
7 #include <AVFoundation/AVFoundation.h> | 7 #include <AVFoundation/AVFoundation.h> |
8 #include <CoreMedia/CoreMedia.h> | 8 #include <CoreMedia/CoreMedia.h> |
9 #include <CoreVideo/CoreVideo.h> | 9 #include <CoreVideo/CoreVideo.h> |
10 #include <GLES2/gl2extchromium.h> | 10 #include <GLES2/gl2extchromium.h> |
11 | 11 |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/lazy_instance.h" |
13 #include "base/mac/sdk_forward_declarations.h" | 14 #include "base/mac/sdk_forward_declarations.h" |
14 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
15 #include "third_party/skia/include/core/SkColor.h" | 16 #include "third_party/skia/include/core/SkColor.h" |
16 #include "ui/base/cocoa/animation_utils.h" | 17 #include "ui/base/cocoa/animation_utils.h" |
17 #include "ui/base/ui_base_switches.h" | 18 #include "ui/base/ui_base_switches.h" |
18 #include "ui/gfx/geometry/dip_util.h" | 19 #include "ui/gfx/geometry/dip_util.h" |
19 #include "ui/gl/ca_renderer_layer_params.h" | 20 #include "ui/gl/ca_renderer_layer_params.h" |
20 #include "ui/gl/gl_image_io_surface.h" | 21 #include "ui/gl/gl_image_io_surface.h" |
21 | 22 |
22 #if !defined(MAC_OS_X_VERSION_10_8) || \ | 23 #if !defined(MAC_OS_X_VERSION_10_8) || \ |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; | 123 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; |
123 return false; | 124 return false; |
124 } | 125 } |
125 | 126 |
126 return AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, | 127 return AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, |
127 cv_pixel_buffer); | 128 cv_pixel_buffer); |
128 } | 129 } |
129 | 130 |
130 } // namespace | 131 } // namespace |
131 | 132 |
| 133 class CARendererLayerTree::SolidColorContents |
| 134 : public base::RefCounted<CARendererLayerTree::SolidColorContents> { |
| 135 public: |
| 136 static scoped_refptr<SolidColorContents> Get(SkColor color); |
| 137 id GetContents() const; |
| 138 |
| 139 private: |
| 140 friend class base::RefCounted<SolidColorContents>; |
| 141 |
| 142 SolidColorContents(SkColor color, IOSurfaceRef io_surface); |
| 143 ~SolidColorContents(); |
| 144 |
| 145 SkColor color_ = 0; |
| 146 base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; |
| 147 static base::LazyInstance<std::map<SkColor, SolidColorContents*>> map_; |
| 148 }; |
| 149 |
| 150 base::LazyInstance<std::map<SkColor, CARendererLayerTree::SolidColorContents*>> |
| 151 CARendererLayerTree::SolidColorContents::map_; |
| 152 |
| 153 // static |
| 154 scoped_refptr<CARendererLayerTree::SolidColorContents> |
| 155 CARendererLayerTree::SolidColorContents::Get(SkColor color) { |
| 156 const int kSolidColorContentsSize = 16; |
| 157 |
| 158 auto found = map_.Get().find(color); |
| 159 if (found != map_.Get().end()) |
| 160 return found->second; |
| 161 |
| 162 IOSurfaceRef io_surface = CreateIOSurface( |
| 163 gfx::Size(kSolidColorContentsSize, kSolidColorContentsSize), |
| 164 gfx::BufferFormat::BGRA_8888); |
| 165 if (!io_surface) |
| 166 return nullptr; |
| 167 |
| 168 size_t bytes_per_row = IOSurfaceGetBytesPerRowOfPlane(io_surface, 0); |
| 169 IOSurfaceLock(io_surface, 0, NULL); |
| 170 char* row_base_address = |
| 171 reinterpret_cast<char*>(IOSurfaceGetBaseAddress(io_surface)); |
| 172 for (int i = 0; i < kSolidColorContentsSize; ++i) { |
| 173 unsigned int* pixel = reinterpret_cast<unsigned int*>(row_base_address); |
| 174 for (int j = 0; j < kSolidColorContentsSize; ++j) |
| 175 *(pixel++) = color; |
| 176 row_base_address += bytes_per_row; |
| 177 } |
| 178 IOSurfaceUnlock(io_surface, 0, NULL); |
| 179 |
| 180 return new SolidColorContents(color, io_surface); |
| 181 } |
| 182 |
| 183 id CARendererLayerTree::SolidColorContents::GetContents() const { |
| 184 return static_cast<id>(io_surface_.get()); |
| 185 } |
| 186 |
| 187 CARendererLayerTree::SolidColorContents::SolidColorContents( |
| 188 SkColor color, |
| 189 IOSurfaceRef io_surface) |
| 190 : color_(color), io_surface_(io_surface) { |
| 191 DCHECK(map_.Get().find(color_) == map_.Get().end()); |
| 192 map_.Get()[color_] = this; |
| 193 } |
| 194 |
| 195 CARendererLayerTree::SolidColorContents::~SolidColorContents() { |
| 196 auto found = map_.Get().find(color_); |
| 197 DCHECK(found != map_.Get().end()); |
| 198 DCHECK(found->second == this); |
| 199 map_.Get().erase(color_); |
| 200 } |
| 201 |
132 CARendererLayerTree::CARendererLayerTree( | 202 CARendererLayerTree::CARendererLayerTree( |
133 bool allow_av_sample_buffer_display_layer) | 203 bool allow_av_sample_buffer_display_layer, |
| 204 bool allow_solid_color_layers) |
134 : allow_av_sample_buffer_display_layer_( | 205 : allow_av_sample_buffer_display_layer_( |
135 allow_av_sample_buffer_display_layer) {} | 206 allow_av_sample_buffer_display_layer), |
| 207 allow_solid_color_layers_(allow_solid_color_layers) {} |
136 CARendererLayerTree::~CARendererLayerTree() {} | 208 CARendererLayerTree::~CARendererLayerTree() {} |
137 | 209 |
138 bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { | 210 bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { |
139 // Excessive logging to debug white screens (crbug.com/583805). | 211 // Excessive logging to debug white screens (crbug.com/583805). |
140 // TODO(ccameron): change this back to a DLOG. | 212 // TODO(ccameron): change this back to a DLOG. |
141 if (has_committed_) { | 213 if (has_committed_) { |
142 LOG(ERROR) << "ScheduleCALayer called after CommitScheduledCALayers."; | 214 LOG(ERROR) << "ScheduleCALayer called after CommitScheduledCALayers."; |
143 return false; | 215 return false; |
144 } | 216 } |
145 return root_layer_.AddContentLayer(this, params); | 217 return root_layer_.AddContentLayer(this, params); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 fullscreen_low_power_layer, video_layer->cv_pixel_buffer); | 281 fullscreen_low_power_layer, video_layer->cv_pixel_buffer); |
210 } else { | 282 } else { |
211 AVSampleBufferDisplayLayerEnqueueIOSurface(fullscreen_low_power_layer, | 283 AVSampleBufferDisplayLayerEnqueueIOSurface(fullscreen_low_power_layer, |
212 video_layer->io_surface); | 284 video_layer->io_surface); |
213 } | 285 } |
214 [fullscreen_low_power_layer setVideoGravity:AVLayerVideoGravityResize]; | 286 [fullscreen_low_power_layer setVideoGravity:AVLayerVideoGravityResize]; |
215 [fullscreen_low_power_layer setFrame:video_layer_frame_dip.ToCGRect()]; | 287 [fullscreen_low_power_layer setFrame:video_layer_frame_dip.ToCGRect()]; |
216 return true; | 288 return true; |
217 } | 289 } |
218 | 290 |
| 291 id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) { |
| 292 return SolidColorContents::Get(color)->GetContents(); |
| 293 } |
219 | 294 |
220 CARendererLayerTree::RootLayer::RootLayer() {} | 295 CARendererLayerTree::RootLayer::RootLayer() {} |
221 | 296 |
222 // Note that for all destructors, the the CALayer will have been reset to nil if | 297 // Note that for all destructors, the the CALayer will have been reset to nil if |
223 // another layer has taken it. | 298 // another layer has taken it. |
224 CARendererLayerTree::RootLayer::~RootLayer() { | 299 CARendererLayerTree::RootLayer::~RootLayer() { |
225 [ca_layer removeFromSuperlayer]; | 300 [ca_layer removeFromSuperlayer]; |
226 } | 301 } |
227 | 302 |
228 CARendererLayerTree::ClipAndSortingLayer::ClipAndSortingLayer( | 303 CARendererLayerTree::ClipAndSortingLayer::ClipAndSortingLayer( |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 : io_surface(io_surface), | 357 : io_surface(io_surface), |
283 cv_pixel_buffer(cv_pixel_buffer), | 358 cv_pixel_buffer(cv_pixel_buffer), |
284 contents_rect(contents_rect), | 359 contents_rect(contents_rect), |
285 rect(rect), | 360 rect(rect), |
286 background_color(background_color), | 361 background_color(background_color), |
287 ca_edge_aa_mask(0), | 362 ca_edge_aa_mask(0), |
288 opacity(opacity), | 363 opacity(opacity), |
289 ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { | 364 ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { |
290 DCHECK(filter == GL_LINEAR || filter == GL_NEAREST); | 365 DCHECK(filter == GL_LINEAR || filter == GL_NEAREST); |
291 | 366 |
| 367 // On Mac OS Sierra, solid color layers are not color color corrected to the |
| 368 // output monitor color space, but IOSurface-backed layers are color |
| 369 // corrected. Note that this is only the case when the CALayers are shared |
| 370 // across processes. To make colors consistent across both solid color and |
| 371 // IOSurface-backed layers, use a cache of solid-color IOSurfaces as contents. |
| 372 // https://crbug.com/633805 |
| 373 if (!io_surface && !tree->allow_solid_color_layers_) { |
| 374 solid_color_contents = SolidColorContents::Get(background_color); |
| 375 ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1); |
| 376 } |
| 377 |
292 // Because the root layer has setGeometryFlipped:YES, there is some ambiguity | 378 // Because the root layer has setGeometryFlipped:YES, there is some ambiguity |
293 // about what exactly top and bottom mean. This ambiguity is resolved in | 379 // about what exactly top and bottom mean. This ambiguity is resolved in |
294 // different ways for solid color CALayers and for CALayers that have content | 380 // different ways for solid color CALayers and for CALayers that have content |
295 // (surprise!). For CALayers with IOSurface content, the top edge in the AA | 381 // (surprise!). For CALayers with IOSurface content, the top edge in the AA |
296 // mask refers to what appears as the bottom edge on-screen. For CALayers | 382 // mask refers to what appears as the bottom edge on-screen. For CALayers |
297 // without content (solid color layers), the top edge in the AA mask is the | 383 // without content (solid color layers), the top edge in the AA mask is the |
298 // top edge on-screen. | 384 // top edge on-screen. |
299 // https://crbug.com/567946 | 385 // https://crbug.com/567946 |
300 if (edge_aa_mask & GL_CA_LAYER_EDGE_LEFT_CHROMIUM) | 386 if (edge_aa_mask & GL_CA_LAYER_EDGE_LEFT_CHROMIUM) |
301 ca_edge_aa_mask |= kCALayerLeftEdge; | 387 ca_edge_aa_mask |= kCALayerLeftEdge; |
302 if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) | 388 if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) |
303 ca_edge_aa_mask |= kCALayerRightEdge; | 389 ca_edge_aa_mask |= kCALayerRightEdge; |
304 if (io_surface) { | 390 if (io_surface || solid_color_contents) { |
305 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) | 391 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) |
306 ca_edge_aa_mask |= kCALayerBottomEdge; | 392 ca_edge_aa_mask |= kCALayerBottomEdge; |
307 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) | 393 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
308 ca_edge_aa_mask |= kCALayerTopEdge; | 394 ca_edge_aa_mask |= kCALayerTopEdge; |
309 } else { | 395 } else { |
310 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) | 396 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) |
311 ca_edge_aa_mask |= kCALayerTopEdge; | 397 ca_edge_aa_mask |= kCALayerTopEdge; |
312 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) | 398 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
313 ca_edge_aa_mask |= kCALayerBottomEdge; | 399 ca_edge_aa_mask |= kCALayerBottomEdge; |
314 } | 400 } |
315 | 401 |
316 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to | 402 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to |
317 // AV layers. | 403 // AV layers. |
318 if (tree->allow_av_sample_buffer_display_layer_ && | 404 if (tree->allow_av_sample_buffer_display_layer_ && |
319 IOSurfaceGetPixelFormat(io_surface) == | 405 IOSurfaceGetPixelFormat(io_surface) == |
320 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && | 406 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && |
321 contents_rect == gfx::RectF(0, 0, 1, 1)) { | 407 contents_rect == gfx::RectF(0, 0, 1, 1)) { |
322 use_av_layer = true; | 408 use_av_layer = true; |
323 } | 409 } |
324 } | 410 } |
325 | 411 |
326 CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) | 412 CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) |
327 : io_surface(layer.io_surface), | 413 : io_surface(layer.io_surface), |
328 cv_pixel_buffer(layer.cv_pixel_buffer), | 414 cv_pixel_buffer(layer.cv_pixel_buffer), |
| 415 solid_color_contents(layer.solid_color_contents), |
329 contents_rect(layer.contents_rect), | 416 contents_rect(layer.contents_rect), |
330 rect(layer.rect), | 417 rect(layer.rect), |
331 background_color(layer.background_color), | 418 background_color(layer.background_color), |
332 ca_edge_aa_mask(layer.ca_edge_aa_mask), | 419 ca_edge_aa_mask(layer.ca_edge_aa_mask), |
333 opacity(layer.opacity), | 420 opacity(layer.opacity), |
334 ca_filter(layer.ca_filter), | 421 ca_filter(layer.ca_filter), |
335 ca_layer(std::move(layer.ca_layer)), | 422 ca_layer(std::move(layer.ca_layer)), |
336 av_layer(std::move(layer.av_layer)), | 423 av_layer(std::move(layer.av_layer)), |
337 use_av_layer(layer.use_av_layer) { | 424 use_av_layer(layer.use_av_layer) { |
338 DCHECK(!layer.ca_layer); | 425 DCHECK(!layer.ca_layer); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 bool update_rect = true; | 628 bool update_rect = true; |
542 bool update_background_color = true; | 629 bool update_background_color = true; |
543 bool update_ca_edge_aa_mask = true; | 630 bool update_ca_edge_aa_mask = true; |
544 bool update_opacity = true; | 631 bool update_opacity = true; |
545 bool update_ca_filter = true; | 632 bool update_ca_filter = true; |
546 if (old_layer && old_layer->use_av_layer == use_av_layer) { | 633 if (old_layer && old_layer->use_av_layer == use_av_layer) { |
547 DCHECK(old_layer->ca_layer); | 634 DCHECK(old_layer->ca_layer); |
548 std::swap(ca_layer, old_layer->ca_layer); | 635 std::swap(ca_layer, old_layer->ca_layer); |
549 std::swap(av_layer, old_layer->av_layer); | 636 std::swap(av_layer, old_layer->av_layer); |
550 update_contents = old_layer->io_surface != io_surface || | 637 update_contents = old_layer->io_surface != io_surface || |
551 old_layer->cv_pixel_buffer != cv_pixel_buffer; | 638 old_layer->cv_pixel_buffer != cv_pixel_buffer || |
| 639 old_layer->solid_color_contents != solid_color_contents; |
552 update_contents_rect = old_layer->contents_rect != contents_rect; | 640 update_contents_rect = old_layer->contents_rect != contents_rect; |
553 update_rect = old_layer->rect != rect; | 641 update_rect = old_layer->rect != rect; |
554 update_background_color = old_layer->background_color != background_color; | 642 update_background_color = old_layer->background_color != background_color; |
555 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; | 643 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; |
556 update_opacity = old_layer->opacity != opacity; | 644 update_opacity = old_layer->opacity != opacity; |
557 update_ca_filter = old_layer->ca_filter != ca_filter; | 645 update_ca_filter = old_layer->ca_filter != ca_filter; |
558 } else { | 646 } else { |
559 if (use_av_layer) { | 647 if (use_av_layer) { |
560 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); | 648 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); |
561 ca_layer.reset([av_layer retain]); | 649 ca_layer.reset([av_layer retain]); |
(...skipping 16 matching lines...) Expand all Loading... |
578 if (update_contents) { | 666 if (update_contents) { |
579 if (cv_pixel_buffer) { | 667 if (cv_pixel_buffer) { |
580 AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, | 668 AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, |
581 cv_pixel_buffer); | 669 cv_pixel_buffer); |
582 } else { | 670 } else { |
583 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); | 671 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); |
584 } | 672 } |
585 } | 673 } |
586 } else { | 674 } else { |
587 if (update_contents) { | 675 if (update_contents) { |
588 [ca_layer setContents:static_cast<id>(io_surface.get())]; | 676 if (io_surface) { |
| 677 [ca_layer setContents:static_cast<id>(io_surface.get())]; |
| 678 } else if (solid_color_contents) { |
| 679 [ca_layer setContents:solid_color_contents->GetContents()]; |
| 680 } else { |
| 681 [ca_layer setContents:nil]; |
| 682 } |
589 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | 683 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) |
590 [ca_layer setContentsScale:scale_factor]; | 684 [ca_layer setContentsScale:scale_factor]; |
591 } | 685 } |
592 if (update_contents_rect) | 686 if (update_contents_rect) |
593 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | 687 [ca_layer setContentsRect:contents_rect.ToCGRect()]; |
594 } | 688 } |
595 if (update_rect) { | 689 if (update_rect) { |
596 gfx::RectF dip_rect = gfx::RectF(rect); | 690 gfx::RectF dip_rect = gfx::RectF(rect); |
597 dip_rect.Scale(1 / scale_factor); | 691 dip_rect.Scale(1 / scale_factor); |
598 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; | 692 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; |
(...skipping 20 matching lines...) Expand all Loading... |
619 } | 713 } |
620 | 714 |
621 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( | 715 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( |
622 switches::kShowMacOverlayBorders); | 716 switches::kShowMacOverlayBorders); |
623 if (show_borders) { | 717 if (show_borders) { |
624 base::ScopedCFTypeRef<CGColorRef> color; | 718 base::ScopedCFTypeRef<CGColorRef> color; |
625 if (update_anything) { | 719 if (update_anything) { |
626 if (use_av_layer) { | 720 if (use_av_layer) { |
627 // Yellow represents an AV layer that changed this frame. | 721 // Yellow represents an AV layer that changed this frame. |
628 color.reset(CGColorCreateGenericRGB(1, 1, 0, 1)); | 722 color.reset(CGColorCreateGenericRGB(1, 1, 0, 1)); |
| 723 } else if (io_surface) { |
| 724 // Magenta represents a CALayer that changed this frame. |
| 725 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); |
| 726 } else if (solid_color_contents) { |
| 727 // Cyan represents a solid color IOSurface-backed layer. |
| 728 color.reset(CGColorCreateGenericRGB(0, 1, 1, 1)); |
629 } else { | 729 } else { |
630 // Pink represents a CALayer that changed this frame. | 730 // Red represents a solid color layer. |
631 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); | 731 color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); |
632 } | 732 } |
633 } else { | 733 } else { |
634 // Grey represents a CALayer that has not changed. | 734 // Grey represents a CALayer that has not changed. |
635 color.reset(CGColorCreateGenericRGB(0.5, 0.5, 0.5, 1)); | 735 color.reset(CGColorCreateGenericRGB(0.5, 0.5, 0.5, 1)); |
636 } | 736 } |
637 [ca_layer setBorderWidth:1]; | 737 [ca_layer setBorderWidth:1]; |
638 [ca_layer setBorderColor:color]; | 738 [ca_layer setBorderColor:color]; |
639 } | 739 } |
640 } | 740 } |
641 | 741 |
642 } // namespace ui | 742 } // namespace ui |
OLD | NEW |