display_ca_layer_tree.mm 5.4 KB

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