OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/common/gpu/image_transport_surface_overlay_mac.h" | |
6 | |
7 #include <CoreGraphics/CoreGraphics.h> | |
8 #include <IOSurface/IOSurface.h> | |
9 #include <OpenGL/CGLRenderers.h> | |
10 #include <OpenGL/CGLTypes.h> | |
11 #include <OpenGL/gl.h> | |
12 #include <stddef.h> | |
13 | |
14 #include <algorithm> | |
15 | |
16 // This type consistently causes problem on Mac, and needs to be dealt with | |
17 // in a systemic way. | |
18 // http://crbug.com/517208 | |
19 #ifndef GL_OES_EGL_image | |
20 typedef void* GLeglImageOES; | |
21 #endif | |
22 | |
23 #include "base/bind.h" | |
24 #include "base/bind_helpers.h" | |
25 #include "base/mac/scoped_cftyperef.h" | |
26 #include "base/trace_event/trace_event.h" | |
27 #include "content/common/gpu/ca_layer_partial_damage_tree_mac.h" | |
28 #include "content/common/gpu/ca_layer_tree_mac.h" | |
29 #include "content/common/gpu/gpu_channel_manager.h" | |
30 #include "content/common/gpu/gpu_channel_manager_delegate.h" | |
31 #include "ui/accelerated_widget_mac/io_surface_context.h" | |
32 #include "ui/base/cocoa/animation_utils.h" | |
33 #include "ui/base/cocoa/remote_layer_api.h" | |
34 #include "ui/gfx/geometry/rect_conversions.h" | |
35 #include "ui/gfx/transform.h" | |
36 #include "ui/gl/gl_context.h" | |
37 #include "ui/gl/gl_fence.h" | |
38 #include "ui/gl/gl_image_io_surface.h" | |
39 #include "ui/gl/gpu_switching_manager.h" | |
40 #include "ui/gl/scoped_api.h" | |
41 #include "ui/gl/scoped_cgl.h" | |
42 | |
43 namespace { | |
44 | |
45 // Don't let a frame draw until 5% of the way through the next vsync interval | |
46 // after the call to SwapBuffers. This slight offset is to ensure that skew | |
47 // doesn't result in the frame being presented to the previous vsync interval. | |
48 const double kVSyncIntervalFractionForEarliestDisplay = 0.05; | |
49 | |
50 // After doing a glFlush and putting in a fence in SwapBuffers, post a task to | |
51 // query the fence 50% of the way through the next vsync interval. If we are | |
52 // trying to animate smoothly, then want to query the fence at the next | |
53 // SwapBuffers. For this reason we schedule the callback for a long way into | |
54 // the next frame. | |
55 const double kVSyncIntervalFractionForDisplayCallback = 0.5; | |
56 | |
57 // If swaps arrive regularly and nearly at the vsync rate, then attempt to | |
58 // make animation smooth (each frame is shown for one vsync interval) by sending | |
59 // them to the window server only when their GL work completes. If frames are | |
60 // not coming in with each vsync, then just throw them at the window server as | |
61 // they come. | |
62 const double kMaximumVSyncsBetweenSwapsForSmoothAnimation = 1.5; | |
63 | |
64 void CheckGLErrors(const char* msg) { | |
65 GLenum gl_error; | |
66 while ((gl_error = glGetError()) != GL_NO_ERROR) { | |
67 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; | |
68 } | |
69 } | |
70 | |
71 void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 @interface CALayer(Private) | |
77 -(void)setContentsChanged; | |
78 @end | |
79 | |
80 namespace content { | |
81 | |
82 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( | |
83 GpuChannelManager* manager, | |
84 GpuCommandBufferStub* stub, | |
85 gpu::SurfaceHandle handle) { | |
86 return new ImageTransportSurfaceOverlayMac(manager, stub, handle); | |
87 } | |
88 | |
89 class ImageTransportSurfaceOverlayMac::PendingSwap { | |
90 public: | |
91 PendingSwap() {} | |
92 ~PendingSwap() { DCHECK(!gl_fence); } | |
93 | |
94 gfx::Size pixel_size; | |
95 float scale_factor; | |
96 gfx::Rect pixel_damage_rect; | |
97 | |
98 scoped_ptr<CALayerPartialDamageTree> partial_damage_tree; | |
99 scoped_ptr<CALayerTree> ca_layer_tree; | |
100 std::vector<ui::LatencyInfo> latency_info; | |
101 | |
102 // A fence object, and the CGL context it was issued in. | |
103 base::ScopedTypeRef<CGLContextObj> cgl_context; | |
104 scoped_ptr<gfx::GLFence> gl_fence; | |
105 | |
106 // The earliest time that this frame may be drawn. A frame is not allowed | |
107 // to draw until a fraction of the way through the vsync interval after its | |
108 // This extra latency is to allow wiggle-room for smoothness. | |
109 base::TimeTicks earliest_display_time_allowed; | |
110 | |
111 // The time that this will wake up and draw, if a following swap does not | |
112 // cause it to draw earlier. | |
113 base::TimeTicks target_display_time; | |
114 }; | |
115 | |
116 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( | |
117 GpuChannelManager* manager, | |
118 GpuCommandBufferStub* stub, | |
119 gpu::SurfaceHandle handle) | |
120 : manager_(manager), | |
121 stub_(stub->AsWeakPtr()), | |
122 handle_(handle), | |
123 use_remote_layer_api_(ui::RemoteLayerAPISupported()), | |
124 scale_factor_(1), | |
125 gl_renderer_id_(0), | |
126 vsync_parameters_valid_(false), | |
127 display_pending_swap_timer_(true, false), | |
128 weak_factory_(this) { | |
129 manager_->AddBufferPresentedCallback( | |
130 handle_, base::Bind(&ImageTransportSurfaceOverlayMac::BufferPresented, | |
131 base::Unretained(this))); | |
132 ui::GpuSwitchingManager::GetInstance()->AddObserver(this); | |
133 } | |
134 | |
135 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { | |
136 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); | |
137 if (stub_.get()) { | |
138 stub_->SetLatencyInfoCallback( | |
139 base::Callback<void(const std::vector<ui::LatencyInfo>&)>()); | |
140 } | |
141 Destroy(); | |
142 manager_->RemoveBufferPresentedCallback(handle_); | |
143 } | |
144 | |
145 bool ImageTransportSurfaceOverlayMac::Initialize( | |
146 gfx::GLSurface::Format format) { | |
147 if (!stub_.get() || !stub_->decoder()) | |
148 return false; | |
149 | |
150 stub_->SetLatencyInfoCallback( | |
151 base::Bind(&ImageTransportSurfaceOverlayMac::SetLatencyInfo, | |
152 base::Unretained(this))); | |
153 | |
154 // Create the CAContext to send this to the GPU process, and the layer for | |
155 // the context. | |
156 if (use_remote_layer_api_) { | |
157 CGSConnectionID connection_id = CGSMainConnectionID(); | |
158 ca_context_.reset([ | |
159 [CAContext contextWithCGSConnection:connection_id options:@{}] retain]); | |
160 ca_root_layer_.reset([[CALayer alloc] init]); | |
161 [ca_root_layer_ setGeometryFlipped:YES]; | |
162 [ca_root_layer_ setOpaque:YES]; | |
163 [ca_context_ setLayer:ca_root_layer_]; | |
164 } | |
165 return true; | |
166 } | |
167 | |
168 void ImageTransportSurfaceOverlayMac::Destroy() { | |
169 DisplayAndClearAllPendingSwaps(); | |
170 | |
171 current_partial_damage_tree_.reset(); | |
172 current_ca_layer_tree_.reset(); | |
173 } | |
174 | |
175 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { | |
176 return false; | |
177 } | |
178 | |
179 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( | |
180 const std::vector<ui::LatencyInfo>& latency_info) { | |
181 latency_info_.insert(latency_info_.end(), latency_info.begin(), | |
182 latency_info.end()); | |
183 } | |
184 | |
185 void ImageTransportSurfaceOverlayMac::BufferPresented( | |
186 int32_t surface_id, | |
187 const base::TimeTicks& vsync_timebase, | |
188 const base::TimeDelta& vsync_interval) { | |
189 vsync_timebase_ = vsync_timebase; | |
190 vsync_interval_ = vsync_interval; | |
191 vsync_parameters_valid_ = (vsync_interval_ != base::TimeDelta()); | |
192 | |
193 // Compute |vsync_timebase_| to be the first vsync after time zero. | |
194 if (vsync_parameters_valid_) { | |
195 vsync_timebase_ -= | |
196 vsync_interval_ * | |
197 ((vsync_timebase_ - base::TimeTicks()) / vsync_interval_); | |
198 } | |
199 } | |
200 | |
201 void ImageTransportSurfaceOverlayMac::SendAcceleratedSurfaceBuffersSwapped( | |
202 int32_t surface_id, | |
203 CAContextID ca_context_id, | |
204 const gfx::ScopedRefCountedIOSurfaceMachPort& io_surface, | |
205 const gfx::Size& size, | |
206 float scale_factor, | |
207 std::vector<ui::LatencyInfo> latency_info) { | |
208 // TRACE_EVENT for gpu tests: | |
209 TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", TRACE_EVENT_SCOPE_THREAD, | |
210 "GLImpl", static_cast<int>(gfx::GetGLImplementation()), | |
211 "width", size.width()); | |
212 // On mac, handle_ is a surface id. See | |
213 // GpuProcessTransportFactory::CreatePerCompositorData | |
214 manager_->delegate()->SendAcceleratedSurfaceBuffersSwapped( | |
215 surface_id, ca_context_id, io_surface, size, scale_factor, | |
216 std::move(latency_info)); | |
217 } | |
218 | |
219 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( | |
220 const gfx::Rect& pixel_damage_rect) { | |
221 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); | |
222 | |
223 // Use the same concept of 'now' for the entire function. The duration of | |
224 // this function only affect the result if this function lasts across a vsync | |
225 // boundary, in which case smooth animation is out the window anyway. | |
226 const base::TimeTicks now = base::TimeTicks::Now(); | |
227 | |
228 // Decide if the frame should be drawn immediately, or if we should wait until | |
229 // its work finishes before drawing immediately. | |
230 bool display_immediately = false; | |
231 if (vsync_parameters_valid_ && | |
232 now - last_swap_time_ > | |
233 kMaximumVSyncsBetweenSwapsForSmoothAnimation * vsync_interval_) { | |
234 display_immediately = true; | |
235 } | |
236 last_swap_time_ = now; | |
237 | |
238 // If the previous swap is ready to display, do it before flushing the | |
239 // new swap. It is desirable to always be hitting this path when trying to | |
240 // animate smoothly with vsync. | |
241 if (!pending_swaps_.empty()) { | |
242 if (IsFirstPendingSwapReadyToDisplay(now)) | |
243 DisplayFirstPendingSwapImmediately(); | |
244 } | |
245 | |
246 // The remainder of the function will populate the PendingSwap structure and | |
247 // then enqueue it. | |
248 linked_ptr<PendingSwap> new_swap(new PendingSwap); | |
249 new_swap->pixel_size = pixel_size_; | |
250 new_swap->scale_factor = scale_factor_; | |
251 new_swap->pixel_damage_rect = pixel_damage_rect; | |
252 new_swap->partial_damage_tree.swap(pending_partial_damage_tree_); | |
253 new_swap->ca_layer_tree.swap(pending_ca_layer_tree_); | |
254 new_swap->latency_info.swap(latency_info_); | |
255 | |
256 // A flush is required to ensure that all content appears in the layer. | |
257 { | |
258 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; | |
259 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); | |
260 CheckGLErrors("before flushing frame"); | |
261 new_swap->cgl_context.reset(CGLGetCurrentContext(), | |
262 base::scoped_policy::RETAIN); | |
263 if (gfx::GLFence::IsSupported() && !display_immediately) | |
264 new_swap->gl_fence.reset(gfx::GLFence::Create()); | |
265 else | |
266 glFlush(); | |
267 CheckGLErrors("while flushing frame"); | |
268 } | |
269 | |
270 // Compute the deadlines for drawing this frame. | |
271 if (display_immediately) { | |
272 new_swap->earliest_display_time_allowed = now; | |
273 new_swap->target_display_time = now; | |
274 } else { | |
275 new_swap->earliest_display_time_allowed = | |
276 GetNextVSyncTimeAfter(now, kVSyncIntervalFractionForEarliestDisplay); | |
277 new_swap->target_display_time = | |
278 GetNextVSyncTimeAfter(now, kVSyncIntervalFractionForDisplayCallback); | |
279 } | |
280 | |
281 pending_swaps_.push_back(new_swap); | |
282 if (display_immediately) | |
283 DisplayFirstPendingSwapImmediately(); | |
284 else | |
285 PostCheckPendingSwapsCallbackIfNeeded(now); | |
286 return gfx::SwapResult::SWAP_ACK; | |
287 } | |
288 | |
289 bool ImageTransportSurfaceOverlayMac::IsFirstPendingSwapReadyToDisplay( | |
290 const base::TimeTicks& now) { | |
291 DCHECK(!pending_swaps_.empty()); | |
292 linked_ptr<PendingSwap> swap = pending_swaps_.front(); | |
293 | |
294 // Frames are disallowed from drawing until the vsync interval after their | |
295 // swap is issued. | |
296 if (now < swap->earliest_display_time_allowed) | |
297 return false; | |
298 | |
299 // If we've passed that marker, then wait for the work behind the fence to | |
300 // complete. | |
301 if (swap->gl_fence) { | |
302 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; | |
303 gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); | |
304 | |
305 CheckGLErrors("before waiting on fence"); | |
306 if (!swap->gl_fence->HasCompleted()) { | |
307 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::ClientWait"); | |
308 swap->gl_fence->ClientWait(); | |
309 } | |
310 swap->gl_fence.reset(); | |
311 CheckGLErrors("after waiting on fence"); | |
312 } | |
313 return true; | |
314 } | |
315 | |
316 void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() { | |
317 TRACE_EVENT0("gpu", | |
318 "ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately"); | |
319 DCHECK(!pending_swaps_.empty()); | |
320 linked_ptr<PendingSwap> swap = pending_swaps_.front(); | |
321 | |
322 // If there is a fence for this object, delete it. | |
323 if (swap->gl_fence) { | |
324 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; | |
325 gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); | |
326 | |
327 CheckGLErrors("before deleting active fence"); | |
328 swap->gl_fence.reset(); | |
329 CheckGLErrors("while deleting active fence"); | |
330 } | |
331 | |
332 // Update the CALayer hierarchy. | |
333 { | |
334 gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect); | |
335 ScopedCAActionDisabler disabler; | |
336 if (swap->ca_layer_tree) { | |
337 swap->ca_layer_tree->CommitScheduledCALayers( | |
338 ca_root_layer_.get(), std::move(current_ca_layer_tree_), | |
339 swap->scale_factor); | |
340 current_ca_layer_tree_.swap(swap->ca_layer_tree); | |
341 current_partial_damage_tree_.reset(); | |
342 } else if (swap->partial_damage_tree) { | |
343 swap->partial_damage_tree->CommitCALayers( | |
344 ca_root_layer_.get(), std::move(current_partial_damage_tree_), | |
345 swap->scale_factor, swap->pixel_damage_rect); | |
346 current_partial_damage_tree_.swap(swap->partial_damage_tree); | |
347 current_ca_layer_tree_.reset(); | |
348 } else { | |
349 TRACE_EVENT0("gpu", "Blank frame: No overlays or CALayers"); | |
350 [ca_root_layer_ setSublayers:nil]; | |
351 current_partial_damage_tree_.reset(); | |
352 current_ca_layer_tree_.reset(); | |
353 } | |
354 swap->ca_layer_tree.reset(); | |
355 swap->partial_damage_tree.reset(); | |
356 } | |
357 | |
358 // Update the latency info to reflect the swap time. | |
359 base::TimeTicks swap_time = base::TimeTicks::Now(); | |
360 for (auto latency_info : swap->latency_info) { | |
361 latency_info.AddLatencyNumberWithTimestamp( | |
362 ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); | |
363 latency_info.AddLatencyNumberWithTimestamp( | |
364 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, | |
365 swap_time, 1); | |
366 } | |
367 | |
368 // Send acknowledgement to the browser. | |
369 CAContextID ca_context_id = 0; | |
370 gfx::ScopedRefCountedIOSurfaceMachPort io_surface; | |
371 if (use_remote_layer_api_) { | |
372 ca_context_id = [ca_context_ contextId]; | |
373 } else if (current_partial_damage_tree_) { | |
374 io_surface.reset(IOSurfaceCreateMachPort( | |
375 current_partial_damage_tree_->RootLayerIOSurface())); | |
376 } | |
377 gfx::Size size = swap->pixel_size; | |
378 float scale_factor = swap->scale_factor; | |
379 std::vector<ui::LatencyInfo> latency_info; | |
380 latency_info.swap(swap->latency_info); | |
381 SendAcceleratedSurfaceBuffersSwapped(handle_, ca_context_id, io_surface, size, | |
382 scale_factor, std::move(latency_info)); | |
383 | |
384 // Remove this from the queue, and reset any callback timers. | |
385 pending_swaps_.pop_front(); | |
386 } | |
387 | |
388 void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() { | |
389 TRACE_EVENT0("gpu", | |
390 "ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps"); | |
391 while (!pending_swaps_.empty()) | |
392 DisplayFirstPendingSwapImmediately(); | |
393 } | |
394 | |
395 void ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback() { | |
396 TRACE_EVENT0("gpu", | |
397 "ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback"); | |
398 | |
399 if (pending_swaps_.empty()) | |
400 return; | |
401 | |
402 const base::TimeTicks now = base::TimeTicks::Now(); | |
403 if (IsFirstPendingSwapReadyToDisplay(now)) | |
404 DisplayFirstPendingSwapImmediately(); | |
405 PostCheckPendingSwapsCallbackIfNeeded(now); | |
406 } | |
407 | |
408 void ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded( | |
409 const base::TimeTicks& now) { | |
410 TRACE_EVENT0("gpu", | |
411 "ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded"); | |
412 | |
413 if (pending_swaps_.empty()) { | |
414 display_pending_swap_timer_.Stop(); | |
415 } else { | |
416 display_pending_swap_timer_.Start( | |
417 FROM_HERE, | |
418 pending_swaps_.front()->target_display_time - now, | |
419 base::Bind(&ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback, | |
420 weak_factory_.GetWeakPtr())); | |
421 } | |
422 } | |
423 | |
424 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { | |
425 return SwapBuffersInternal( | |
426 gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height())); | |
427 } | |
428 | |
429 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, | |
430 int y, | |
431 int width, | |
432 int height) { | |
433 return SwapBuffersInternal(gfx::Rect(x, y, width, height)); | |
434 } | |
435 | |
436 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { | |
437 return true; | |
438 } | |
439 | |
440 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { | |
441 return gfx::Size(); | |
442 } | |
443 | |
444 void* ImageTransportSurfaceOverlayMac::GetHandle() { | |
445 return nullptr; | |
446 } | |
447 | |
448 bool ImageTransportSurfaceOverlayMac::OnMakeCurrent(gfx::GLContext* context) { | |
449 // Ensure that the context is on the appropriate GL renderer. The GL renderer | |
450 // will generally only change when the GPU changes. | |
451 if (gl_renderer_id_ && context) | |
452 context->share_group()->SetRendererID(gl_renderer_id_); | |
453 return true; | |
454 } | |
455 | |
456 bool ImageTransportSurfaceOverlayMac::SetBackbufferAllocation(bool allocated) { | |
457 if (!allocated) { | |
458 DisplayAndClearAllPendingSwaps(); | |
459 last_swap_time_ = base::TimeTicks(); | |
460 } | |
461 return true; | |
462 } | |
463 | |
464 bool ImageTransportSurfaceOverlayMac::ScheduleOverlayPlane( | |
465 int z_order, | |
466 gfx::OverlayTransform transform, | |
467 gl::GLImage* image, | |
468 const gfx::Rect& pixel_frame_rect, | |
469 const gfx::RectF& crop_rect) { | |
470 if (transform != gfx::OVERLAY_TRANSFORM_NONE) { | |
471 DLOG(ERROR) << "Invalid overlay plane transform."; | |
472 return false; | |
473 } | |
474 if (z_order) { | |
475 DLOG(ERROR) << "Invalid non-zero Z order."; | |
476 return false; | |
477 } | |
478 if (pending_partial_damage_tree_) { | |
479 DLOG(ERROR) << "Only one overlay per swap is allowed."; | |
480 return false; | |
481 } | |
482 pending_partial_damage_tree_.reset(new CALayerPartialDamageTree( | |
483 use_remote_layer_api_, | |
484 static_cast<gl::GLImageIOSurface*>(image)->io_surface(), | |
485 pixel_frame_rect)); | |
486 return true; | |
487 } | |
488 | |
489 bool ImageTransportSurfaceOverlayMac::ScheduleCALayer( | |
490 gl::GLImage* contents_image, | |
491 const gfx::RectF& contents_rect, | |
492 float opacity, | |
493 unsigned background_color, | |
494 unsigned edge_aa_mask, | |
495 const gfx::RectF& rect, | |
496 bool is_clipped, | |
497 const gfx::RectF& clip_rect, | |
498 const gfx::Transform& transform, | |
499 int sorting_context_id) { | |
500 base::ScopedCFTypeRef<IOSurfaceRef> io_surface; | |
501 if (contents_image) { | |
502 io_surface = | |
503 static_cast<gl::GLImageIOSurface*>(contents_image)->io_surface(); | |
504 } | |
505 if (!pending_ca_layer_tree_) | |
506 pending_ca_layer_tree_.reset(new CALayerTree); | |
507 return pending_ca_layer_tree_->ScheduleCALayer( | |
508 is_clipped, gfx::ToEnclosingRect(clip_rect), sorting_context_id, | |
509 transform, io_surface, contents_rect, gfx::ToEnclosingRect(rect), | |
510 background_color, edge_aa_mask, opacity); | |
511 } | |
512 | |
513 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { | |
514 return true; | |
515 } | |
516 | |
517 bool ImageTransportSurfaceOverlayMac::Resize(const gfx::Size& pixel_size, | |
518 float scale_factor, | |
519 bool has_alpha) { | |
520 // Flush through any pending frames. | |
521 DisplayAndClearAllPendingSwaps(); | |
522 pixel_size_ = pixel_size; | |
523 scale_factor_ = scale_factor; | |
524 return true; | |
525 } | |
526 | |
527 void ImageTransportSurfaceOverlayMac::OnGpuSwitched() { | |
528 // Create a new context, and use the GL renderer ID that the new context gets. | |
529 scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu = | |
530 ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext); | |
531 if (!context_on_new_gpu) | |
532 return; | |
533 GLint context_renderer_id = -1; | |
534 if (CGLGetParameter(context_on_new_gpu->cgl_context(), | |
535 kCGLCPCurrentRendererID, | |
536 &context_renderer_id) != kCGLNoError) { | |
537 LOG(ERROR) << "Failed to create test context after GPU switch"; | |
538 return; | |
539 } | |
540 gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask; | |
541 | |
542 // Post a task holding a reference to the new GL context. The reason for | |
543 // this is to avoid creating-then-destroying the context for every image | |
544 // transport surface that is observing the GPU switch. | |
545 base::MessageLoop::current()->PostTask( | |
546 FROM_HERE, base::Bind(&IOSurfaceContextNoOp, context_on_new_gpu)); | |
547 } | |
548 | |
549 base::TimeTicks ImageTransportSurfaceOverlayMac::GetNextVSyncTimeAfter( | |
550 const base::TimeTicks& from, double interval_fraction) { | |
551 if (!vsync_parameters_valid_) | |
552 return from; | |
553 | |
554 // Compute the previous vsync time. | |
555 base::TimeTicks previous_vsync = | |
556 vsync_interval_ * ((from - vsync_timebase_) / vsync_interval_) + | |
557 vsync_timebase_; | |
558 | |
559 // Return |interval_fraction| through the next vsync. | |
560 return previous_vsync + (1 + interval_fraction) * vsync_interval_; | |
561 } | |
562 | |
563 } // namespace content | |
OLD | NEW |