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 <OpenGL/gl.h> | 7 #include <IOSurface/IOSurface.h> |
| 8 #include <OpenGL/GL.h> |
8 | 9 |
| 10 // This type consistently causes problem on Mac, and needs to be dealt with |
| 11 // in a systemic way. |
| 12 // http://crbug.com/517208 |
| 13 #ifndef GL_OES_EGL_image |
| 14 typedef void* GLeglImageOES; |
| 15 #endif |
| 16 |
| 17 #include "base/mac/scoped_cftyperef.h" |
9 #include "content/common/gpu/gpu_messages.h" | 18 #include "content/common/gpu/gpu_messages.h" |
10 #include "ui/accelerated_widget_mac/surface_handle_types.h" | 19 #include "ui/accelerated_widget_mac/surface_handle_types.h" |
11 #include "ui/base/cocoa/animation_utils.h" | 20 #include "ui/base/cocoa/animation_utils.h" |
12 #include "ui/base/cocoa/remote_layer_api.h" | 21 #include "ui/base/cocoa/remote_layer_api.h" |
13 #include "ui/gfx/geometry/dip_util.h" | 22 #include "ui/gfx/geometry/dip_util.h" |
| 23 #include "ui/gl/gl_fence_apple.h" |
14 #include "ui/gl/gl_image_io_surface.h" | 24 #include "ui/gl/gl_image_io_surface.h" |
| 25 #include "ui/gl/scoped_api.h" |
| 26 #include "ui/gl/scoped_cgl.h" |
| 27 |
| 28 namespace { |
| 29 |
| 30 void CheckGLErrors(const char* msg) { |
| 31 GLenum gl_error; |
| 32 while ((gl_error = glGetError()) != GL_NO_ERROR) { |
| 33 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; |
| 34 } |
| 35 } |
| 36 |
| 37 } // namespace |
15 | 38 |
16 namespace content { | 39 namespace content { |
17 | 40 |
| 41 class ImageTransportSurfaceOverlayMac::PendingSwap : |
| 42 public base::RefCounted<PendingSwap> { |
| 43 public: |
| 44 PendingSwap() {} |
| 45 |
| 46 // The IOSurface with new content for this swap. |
| 47 base::ScopedCFTypeRef<IOSurfaceRef> io_surface; |
| 48 |
| 49 // A fence object, and the CGL context it was issued in. |
| 50 base::ScopedTypeRef<CGLContextObj> cgl_context; |
| 51 scoped_ptr<gfx::GLFenceAPPLE> fence; |
| 52 |
| 53 // The size of the full frame, in dip. |
| 54 gfx::Size dip_size; |
| 55 |
| 56 std::vector<ui::LatencyInfo> latency_info; |
| 57 |
| 58 protected: |
| 59 friend class base::RefCounted<PendingSwap>; |
| 60 |
| 61 virtual ~PendingSwap() { DCHECK(!fence); } |
| 62 }; |
| 63 |
18 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( | 64 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( |
19 GpuChannelManager* manager, | 65 GpuChannelManager* manager, |
20 GpuCommandBufferStub* stub, | 66 GpuCommandBufferStub* stub, |
21 gfx::PluginWindowHandle handle) | 67 gfx::PluginWindowHandle handle) |
22 : scale_factor_(1), pending_overlay_image_(nullptr) { | 68 : scale_factor_(1), pending_overlay_image_(nullptr), weak_factory_(this) { |
23 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); | 69 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); |
24 } | 70 } |
25 | 71 |
26 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { | 72 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { |
27 gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil); | |
28 } | 73 } |
29 | 74 |
30 bool ImageTransportSurfaceOverlayMac::Initialize() { | 75 bool ImageTransportSurfaceOverlayMac::Initialize() { |
31 if (!helper_->Initialize()) | 76 if (!helper_->Initialize()) |
32 return false; | 77 return false; |
33 | 78 |
34 // Create the CAContext to send this to the GPU process, and the layer for | 79 // Create the CAContext to send this to the GPU process, and the layer for |
35 // the context. | 80 // the context. |
36 CGSConnectionID connection_id = CGSMainConnectionID(); | 81 CGSConnectionID connection_id = CGSMainConnectionID(); |
37 ca_context_.reset( | 82 ca_context_.reset( |
38 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); | 83 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); |
39 layer_.reset([[CALayer alloc] init]); | 84 layer_.reset([[CALayer alloc] init]); |
| 85 [layer_ setGeometryFlipped:YES]; |
40 [ca_context_ setLayer:layer_]; | 86 [ca_context_ setLayer:layer_]; |
41 | 87 |
42 // Register the CALayer so that it can be picked up in GLImageIOSurface. | |
43 static intptr_t previous_widget = 0; | |
44 previous_widget += 1; | |
45 widget_ = reinterpret_cast<gfx::AcceleratedWidget>(previous_widget); | |
46 gfx::GLImageIOSurface::SetLayerForWidget(widget_, layer_); | |
47 | |
48 return true; | 88 return true; |
49 } | 89 } |
50 | 90 |
51 void ImageTransportSurfaceOverlayMac::Destroy() {} | 91 void ImageTransportSurfaceOverlayMac::Destroy() { |
| 92 FinishAllPendingSwaps(); |
| 93 } |
52 | 94 |
53 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { | 95 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { |
54 return false; | 96 return false; |
55 } | 97 } |
56 | 98 |
57 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { | 99 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( |
| 100 const gfx::Rect& pixel_damage_rect) { |
58 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); | 101 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); |
59 | 102 |
60 // A flush is required to ensure that all content appears in the layer. | 103 // The remainder of the function will populate the PendingSwap structure and |
61 { | 104 // then enqueue it. |
62 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); | 105 scoped_refptr<PendingSwap> this_swap(new PendingSwap); |
63 glFlush(); | 106 this_swap->latency_info.swap(latency_info_); |
64 } | |
65 | 107 |
66 // There should exist only one overlay image, and it should cover the whole | 108 // There should exist only one overlay image, and it should cover the whole |
67 // surface. | 109 // surface. |
68 DCHECK(pending_overlay_image_); | 110 DCHECK(pending_overlay_image_); |
69 if (pending_overlay_image_) { | 111 if (pending_overlay_image_) { |
70 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::setContents"); | 112 gfx::GLImageIOSurface* pending_overlay_image_io_surface = |
71 ScopedCAActionDisabler disabler; | 113 static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_); |
72 gfx::Rect dip_bounds = gfx::ConvertRectToDIP( | 114 this_swap->io_surface = pending_overlay_image_io_surface->io_surface(); |
73 scale_factor_, gfx::Rect(pixel_size_)); | |
74 gfx::RectF crop_rect(0, 0, 1, 1); | |
75 pending_overlay_image_->ScheduleOverlayPlane( | |
76 widget_, 0, gfx::OVERLAY_TRANSFORM_NONE, dip_bounds, crop_rect); | |
77 pending_overlay_image_ = nullptr; | 115 pending_overlay_image_ = nullptr; |
78 } | 116 } |
79 | 117 |
| 118 // A flush is required to ensure that all content appears in the layer. |
| 119 { |
| 120 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
| 121 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::glFlush", "surface", |
| 122 this_swap->io_surface.get()); |
| 123 CheckGLErrors("before flushing frame"); |
| 124 this_swap->cgl_context.reset(CGLGetCurrentContext(), |
| 125 base::scoped_policy::RETAIN); |
| 126 this_swap->fence.reset(new gfx::GLFenceAPPLE); |
| 127 CheckGLErrors("while flushing frame"); |
| 128 } |
| 129 |
| 130 this_swap->dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_); |
| 131 pending_swaps_.push_back(this_swap); |
| 132 |
| 133 PostCheckAndDisplayPendingSwaps(); |
| 134 return gfx::SwapResult::SWAP_ACK; |
| 135 } |
| 136 |
| 137 void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps( |
| 138 bool force_immediate_display) { |
| 139 TRACE_EVENT0("gpu", |
| 140 "ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps"); |
| 141 if (pending_swaps_.empty()) |
| 142 return; |
| 143 |
| 144 // Check if the pending work has finished (and early-out if it is not, and |
| 145 // this is not forced). |
| 146 scoped_refptr<PendingSwap> this_swap = pending_swaps_.front(); |
| 147 { |
| 148 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
| 149 gfx::ScopedCGLSetCurrentContext scoped_set_current(this_swap->cgl_context); |
| 150 |
| 151 CheckGLErrors("before testing fence"); |
| 152 bool result = this_swap->fence->HasCompleted(); |
| 153 CheckGLErrors("after testing fence"); |
| 154 if (!result && !force_immediate_display) { |
| 155 PostCheckAndDisplayPendingSwaps(); |
| 156 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::fenceNotReady", |
| 157 "surface", this_swap->io_surface.get()); |
| 158 return; |
| 159 } |
| 160 this_swap->fence.reset(); |
| 161 CheckGLErrors("while deleting fence"); |
| 162 } |
| 163 |
| 164 // Update the CALayer hierarchy. |
| 165 { |
| 166 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents", |
| 167 "surface", this_swap->io_surface.get()); |
| 168 ScopedCAActionDisabler disabler; |
| 169 id new_contents = static_cast<id>(this_swap->io_surface.get()); |
| 170 [layer_ setContents:new_contents]; |
| 171 CGRect new_frame = gfx::Rect(this_swap->dip_size).ToCGRect(); |
| 172 if (!CGRectEqualToRect([layer_ frame], new_frame)) |
| 173 [layer_ setFrame:new_frame]; |
| 174 } |
| 175 |
| 176 // Remove this swap from the queue. |
| 177 pending_swaps_.pop_front(); |
| 178 |
| 179 // Send acknowledgement to the browser. |
80 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | 180 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
81 params.surface_handle = | 181 params.surface_handle = |
82 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); | 182 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); |
83 params.size = pixel_size_; | 183 params.size = pixel_size_; |
84 params.scale_factor = scale_factor_; | 184 params.scale_factor = scale_factor_; |
85 params.latency_info.swap(latency_info_); | 185 params.latency_info.swap(this_swap->latency_info); |
86 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | 186 helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
87 return gfx::SwapResult::SWAP_ACK; | 187 } |
| 188 |
| 189 void ImageTransportSurfaceOverlayMac::PostCheckAndDisplayPendingSwaps() { |
| 190 bool force_immediate_display = true; |
| 191 base::TimeDelta delay; |
| 192 if (display_link_mac_) { |
| 193 base::TimeTicks timebase; |
| 194 base::TimeDelta interval; |
| 195 if (display_link_mac_->GetVSyncParameters(&timebase, &interval)) { |
| 196 base::TimeTicks now = base::TimeTicks::Now(); |
| 197 // Make the timer fire halfway through the vsync interval (since that |
| 198 // makes actual vsync alignment the most likely). |
| 199 timebase -= interval / 2; |
| 200 // Make sure that timebase is before now (to simplify the below |
| 201 // computations). |
| 202 if (timebase >= now) |
| 203 timebase -= (1 + (timebase - now) / interval) * interval; |
| 204 // Compute the target time. |
| 205 base::TimeTicks target = |
| 206 timebase + (1 + (now - timebase) / interval) * interval; |
| 207 delay = target - now; |
| 208 force_immediate_display = false; |
| 209 } |
| 210 } |
| 211 base::MessageLoop::current()->PostDelayedTask( |
| 212 FROM_HERE, |
| 213 base::Bind(&ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps, |
| 214 weak_factory_.GetWeakPtr(), force_immediate_display), |
| 215 delay); |
| 216 } |
| 217 |
| 218 void ImageTransportSurfaceOverlayMac::FinishAllPendingSwaps() { |
| 219 while (!pending_swaps_.empty()) |
| 220 CheckAndDisplayPendingSwaps(true); |
| 221 } |
| 222 |
| 223 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { |
| 224 return SwapBuffersInternal(gfx::Rect(pixel_size_)); |
88 } | 225 } |
89 | 226 |
90 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, | 227 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, |
91 int y, | 228 int y, |
92 int width, | 229 int width, |
93 int height) { | 230 int height) { |
94 return SwapBuffers(); | 231 return SwapBuffersInternal(gfx::Rect(x, y, width, height)); |
95 } | 232 } |
96 | 233 |
97 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { | 234 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { |
98 return true; | 235 return true; |
99 } | 236 } |
100 | 237 |
101 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { | 238 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { |
102 return gfx::Size(); | 239 return gfx::Size(); |
103 } | 240 } |
104 | 241 |
(...skipping 17 matching lines...) Expand all Loading... |
122 DCHECK(!pending_overlay_image_); | 259 DCHECK(!pending_overlay_image_); |
123 pending_overlay_image_ = image; | 260 pending_overlay_image_ = image; |
124 return true; | 261 return true; |
125 } | 262 } |
126 | 263 |
127 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { | 264 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { |
128 return true; | 265 return true; |
129 } | 266 } |
130 | 267 |
131 void ImageTransportSurfaceOverlayMac::OnBufferPresented( | 268 void ImageTransportSurfaceOverlayMac::OnBufferPresented( |
132 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {} | 269 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
| 270 if (display_link_mac_ && |
| 271 display_link_mac_->display_id() == params.display_id_for_vsync) |
| 272 return; |
| 273 display_link_mac_ = ui::DisplayLinkMac::GetForDisplay( |
| 274 params.display_id_for_vsync); |
| 275 } |
133 | 276 |
134 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, | 277 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, |
135 float scale_factor) { | 278 float scale_factor) { |
| 279 // Flush through any pending frames. |
| 280 FinishAllPendingSwaps(); |
136 pixel_size_ = pixel_size; | 281 pixel_size_ = pixel_size; |
137 scale_factor_ = scale_factor; | 282 scale_factor_ = scale_factor; |
138 } | 283 } |
139 | 284 |
140 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( | 285 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( |
141 const std::vector<ui::LatencyInfo>& latency_info) { | 286 const std::vector<ui::LatencyInfo>& latency_info) { |
142 latency_info_.insert( | 287 latency_info_.insert( |
143 latency_info_.end(), latency_info.begin(), latency_info.end()); | 288 latency_info_.end(), latency_info.begin(), latency_info.end()); |
144 } | 289 } |
145 | 290 |
146 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} | 291 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} |
147 | 292 |
148 } // namespace content | 293 } // namespace content |
OLD | NEW |