| 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 "gpu/ipc/service/image_transport_surface_overlay_mac.h" | 5 #include "gpu/ipc/service/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> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 #include "ui/gfx/transform.h" | 35 #include "ui/gfx/transform.h" |
| 36 #include "ui/gl/gl_context.h" | 36 #include "ui/gl/gl_context.h" |
| 37 #include "ui/gl/gl_fence.h" | 37 #include "ui/gl/gl_fence.h" |
| 38 #include "ui/gl/gl_image_io_surface.h" | 38 #include "ui/gl/gl_image_io_surface.h" |
| 39 #include "ui/gl/gpu_switching_manager.h" | 39 #include "ui/gl/gpu_switching_manager.h" |
| 40 #include "ui/gl/scoped_api.h" | 40 #include "ui/gl/scoped_api.h" |
| 41 #include "ui/gl/scoped_cgl.h" | 41 #include "ui/gl/scoped_cgl.h" |
| 42 | 42 |
| 43 namespace { | 43 namespace { |
| 44 | 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) { | 45 void CheckGLErrors(const char* msg) { |
| 65 GLenum gl_error; | 46 GLenum gl_error; |
| 66 while ((gl_error = glGetError()) != GL_NO_ERROR) { | 47 while ((gl_error = glGetError()) != GL_NO_ERROR) { |
| 67 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; | 48 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; |
| 68 } | 49 } |
| 69 } | 50 } |
| 70 | 51 |
| 71 void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { | 52 void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { |
| 72 } | 53 } |
| 73 | 54 |
| 74 } // namespace | 55 } // namespace |
| 75 | 56 |
| 76 @interface CALayer(Private) | |
| 77 -(void)setContentsChanged; | |
| 78 @end | |
| 79 | |
| 80 namespace gpu { | 57 namespace gpu { |
| 81 | 58 |
| 82 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( | 59 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( |
| 83 GpuChannelManager* manager, | 60 GpuChannelManager* manager, |
| 84 GpuCommandBufferStub* stub, | 61 GpuCommandBufferStub* stub, |
| 85 SurfaceHandle handle) { | 62 SurfaceHandle handle) { |
| 86 return new ImageTransportSurfaceOverlayMac(manager, stub, handle); | 63 return new ImageTransportSurfaceOverlayMac(manager, stub, handle); |
| 87 } | 64 } |
| 88 | 65 |
| 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( | 66 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( |
| 117 GpuChannelManager* manager, | 67 GpuChannelManager* manager, |
| 118 GpuCommandBufferStub* stub, | 68 GpuCommandBufferStub* stub, |
| 119 SurfaceHandle handle) | 69 SurfaceHandle handle) |
| 120 : manager_(manager), | 70 : manager_(manager), |
| 121 stub_(stub->AsWeakPtr()), | 71 stub_(stub->AsWeakPtr()), |
| 122 handle_(handle), | 72 handle_(handle), |
| 123 use_remote_layer_api_(ui::RemoteLayerAPISupported()), | 73 use_remote_layer_api_(ui::RemoteLayerAPISupported()), |
| 124 scale_factor_(1), | 74 scale_factor_(1), |
| 125 gl_renderer_id_(0), | 75 gl_renderer_id_(0), |
| 126 vsync_parameters_valid_(false), | 76 vsync_parameters_valid_(false) { |
| 127 display_pending_swap_timer_(true, false), | |
| 128 weak_factory_(this) { | |
| 129 manager_->AddBufferPresentedCallback( | 77 manager_->AddBufferPresentedCallback( |
| 130 handle_, base::Bind(&ImageTransportSurfaceOverlayMac::BufferPresented, | 78 handle_, base::Bind(&ImageTransportSurfaceOverlayMac::BufferPresented, |
| 131 base::Unretained(this))); | 79 base::Unretained(this))); |
| 132 ui::GpuSwitchingManager::GetInstance()->AddObserver(this); | 80 ui::GpuSwitchingManager::GetInstance()->AddObserver(this); |
| 133 } | 81 } |
| 134 | 82 |
| 135 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { | 83 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { |
| 136 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); | 84 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); |
| 137 if (stub_.get()) { | 85 if (stub_.get()) { |
| 138 stub_->SetLatencyInfoCallback( | 86 stub_->SetLatencyInfoCallback( |
| (...skipping 20 matching lines...) Expand all Loading... |
| 159 [CAContext contextWithCGSConnection:connection_id options:@{}] retain]); | 107 [CAContext contextWithCGSConnection:connection_id options:@{}] retain]); |
| 160 ca_root_layer_.reset([[CALayer alloc] init]); | 108 ca_root_layer_.reset([[CALayer alloc] init]); |
| 161 [ca_root_layer_ setGeometryFlipped:YES]; | 109 [ca_root_layer_ setGeometryFlipped:YES]; |
| 162 [ca_root_layer_ setOpaque:YES]; | 110 [ca_root_layer_ setOpaque:YES]; |
| 163 [ca_context_ setLayer:ca_root_layer_]; | 111 [ca_context_ setLayer:ca_root_layer_]; |
| 164 } | 112 } |
| 165 return true; | 113 return true; |
| 166 } | 114 } |
| 167 | 115 |
| 168 void ImageTransportSurfaceOverlayMac::Destroy() { | 116 void ImageTransportSurfaceOverlayMac::Destroy() { |
| 169 DisplayAndClearAllPendingSwaps(); | |
| 170 | |
| 171 current_partial_damage_tree_.reset(); | 117 current_partial_damage_tree_.reset(); |
| 172 current_ca_layer_tree_.reset(); | 118 current_ca_layer_tree_.reset(); |
| 173 } | 119 } |
| 174 | 120 |
| 175 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { | 121 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { |
| 176 return false; | 122 return false; |
| 177 } | 123 } |
| 178 | 124 |
| 179 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( | 125 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( |
| 180 const std::vector<ui::LatencyInfo>& latency_info) { | 126 const std::vector<ui::LatencyInfo>& latency_info) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 // GpuProcessTransportFactory::CreatePerCompositorData | 159 // GpuProcessTransportFactory::CreatePerCompositorData |
| 214 manager_->delegate()->SendAcceleratedSurfaceBuffersSwapped( | 160 manager_->delegate()->SendAcceleratedSurfaceBuffersSwapped( |
| 215 surface_id, ca_context_id, io_surface, size, scale_factor, | 161 surface_id, ca_context_id, io_surface, size, scale_factor, |
| 216 std::move(latency_info)); | 162 std::move(latency_info)); |
| 217 } | 163 } |
| 218 | 164 |
| 219 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( | 165 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( |
| 220 const gfx::Rect& pixel_damage_rect) { | 166 const gfx::Rect& pixel_damage_rect) { |
| 221 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); | 167 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); |
| 222 | 168 |
| 223 // Use the same concept of 'now' for the entire function. The duration of | 169 // A glFlush is necessary to ensure correct content appears. A glFinish |
| 224 // this function only affect the result if this function lasts across a vsync | 170 // appears empirically to be the best way to get maximum performance when |
| 225 // boundary, in which case smooth animation is out the window anyway. | 171 // GPU bound. |
| 226 const base::TimeTicks now = base::TimeTicks::Now(); | 172 { |
| 227 | 173 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
| 228 // Decide if the frame should be drawn immediately, or if we should wait until | 174 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFinish"); |
| 229 // its work finishes before drawing immediately. | 175 CheckGLErrors("Before finish"); |
| 230 bool display_immediately = false; | 176 glFinish(); |
| 231 if (vsync_parameters_valid_ && | 177 CheckGLErrors("After finish"); |
| 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 } | 178 } |
| 245 | 179 |
| 246 // The remainder of the function will populate the PendingSwap structure and | 180 base::TimeTicks finish_time = base::TimeTicks::Now(); |
| 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 | 181 |
| 332 // Update the CALayer hierarchy. | 182 // Update the CALayer hierarchy. |
| 333 { | 183 { |
| 334 gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect); | |
| 335 ScopedCAActionDisabler disabler; | 184 ScopedCAActionDisabler disabler; |
| 336 if (swap->ca_layer_tree) { | 185 if (pending_ca_layer_tree_) { |
| 337 swap->ca_layer_tree->CommitScheduledCALayers( | 186 pending_ca_layer_tree_->CommitScheduledCALayers( |
| 338 ca_root_layer_.get(), std::move(current_ca_layer_tree_), | 187 ca_root_layer_.get(), std::move(current_ca_layer_tree_), |
| 339 swap->scale_factor); | 188 scale_factor_); |
| 340 current_ca_layer_tree_.swap(swap->ca_layer_tree); | 189 current_ca_layer_tree_.swap(pending_ca_layer_tree_); |
| 341 current_partial_damage_tree_.reset(); | 190 current_partial_damage_tree_.reset(); |
| 342 } else if (swap->partial_damage_tree) { | 191 } else if (pending_partial_damage_tree_) { |
| 343 swap->partial_damage_tree->CommitCALayers( | 192 pending_partial_damage_tree_->CommitCALayers( |
| 344 ca_root_layer_.get(), std::move(current_partial_damage_tree_), | 193 ca_root_layer_.get(), std::move(current_partial_damage_tree_), |
| 345 swap->scale_factor, swap->pixel_damage_rect); | 194 scale_factor_, pixel_damage_rect); |
| 346 current_partial_damage_tree_.swap(swap->partial_damage_tree); | 195 current_partial_damage_tree_.swap(pending_partial_damage_tree_); |
| 347 current_ca_layer_tree_.reset(); | 196 current_ca_layer_tree_.reset(); |
| 348 } else { | 197 } else { |
| 349 TRACE_EVENT0("gpu", "Blank frame: No overlays or CALayers"); | 198 TRACE_EVENT0("gpu", "Blank frame: No overlays or CALayers"); |
| 350 [ca_root_layer_ setSublayers:nil]; | 199 [ca_root_layer_ setSublayers:nil]; |
| 351 current_partial_damage_tree_.reset(); | 200 current_partial_damage_tree_.reset(); |
| 352 current_ca_layer_tree_.reset(); | 201 current_ca_layer_tree_.reset(); |
| 353 } | 202 } |
| 354 swap->ca_layer_tree.reset(); | |
| 355 swap->partial_damage_tree.reset(); | |
| 356 } | 203 } |
| 357 | 204 |
| 358 // Update the latency info to reflect the swap time. | 205 // Update the latency info to reflect the swap time. |
| 359 base::TimeTicks swap_time = base::TimeTicks::Now(); | 206 for (auto latency_info : latency_info_) { |
| 360 for (auto latency_info : swap->latency_info) { | |
| 361 latency_info.AddLatencyNumberWithTimestamp( | 207 latency_info.AddLatencyNumberWithTimestamp( |
| 362 ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); | 208 ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, finish_time, 1); |
| 363 latency_info.AddLatencyNumberWithTimestamp( | 209 latency_info.AddLatencyNumberWithTimestamp( |
| 364 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, | 210 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, |
| 365 swap_time, 1); | 211 finish_time, 1); |
| 366 } | 212 } |
| 367 | 213 |
| 368 // Send acknowledgement to the browser. | 214 // Send acknowledgement to the browser. |
| 369 CAContextID ca_context_id = 0; | 215 CAContextID ca_context_id = 0; |
| 370 gfx::ScopedRefCountedIOSurfaceMachPort io_surface; | 216 gfx::ScopedRefCountedIOSurfaceMachPort io_surface; |
| 371 if (use_remote_layer_api_) { | 217 if (use_remote_layer_api_) { |
| 372 ca_context_id = [ca_context_ contextId]; | 218 ca_context_id = [ca_context_ contextId]; |
| 373 } else if (current_partial_damage_tree_) { | 219 } else if (current_partial_damage_tree_) { |
| 374 io_surface.reset(IOSurfaceCreateMachPort( | 220 io_surface.reset(IOSurfaceCreateMachPort( |
| 375 current_partial_damage_tree_->RootLayerIOSurface())); | 221 current_partial_damage_tree_->RootLayerIOSurface())); |
| 376 } | 222 } |
| 377 gfx::Size size = swap->pixel_size; | 223 SendAcceleratedSurfaceBuffersSwapped(handle_, ca_context_id, io_surface, |
| 378 float scale_factor = swap->scale_factor; | 224 pixel_size_, scale_factor_, |
| 379 std::vector<ui::LatencyInfo> latency_info; | 225 std::move(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 | 226 |
| 384 // Remove this from the queue, and reset any callback timers. | 227 // Reset all state for the next frame. |
| 385 pending_swaps_.pop_front(); | 228 latency_info_.clear(); |
| 386 } | 229 pending_ca_layer_tree_.reset(); |
| 387 | 230 pending_partial_damage_tree_.reset(); |
| 388 void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() { | 231 return gfx::SwapResult::SWAP_ACK; |
| 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 } | 232 } |
| 423 | 233 |
| 424 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { | 234 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { |
| 425 return SwapBuffersInternal( | 235 return SwapBuffersInternal( |
| 426 gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height())); | 236 gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height())); |
| 427 } | 237 } |
| 428 | 238 |
| 429 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, | 239 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, |
| 430 int y, | 240 int y, |
| 431 int width, | 241 int width, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 446 } | 256 } |
| 447 | 257 |
| 448 bool ImageTransportSurfaceOverlayMac::OnMakeCurrent(gfx::GLContext* context) { | 258 bool ImageTransportSurfaceOverlayMac::OnMakeCurrent(gfx::GLContext* context) { |
| 449 // Ensure that the context is on the appropriate GL renderer. The GL renderer | 259 // Ensure that the context is on the appropriate GL renderer. The GL renderer |
| 450 // will generally only change when the GPU changes. | 260 // will generally only change when the GPU changes. |
| 451 if (gl_renderer_id_ && context) | 261 if (gl_renderer_id_ && context) |
| 452 context->share_group()->SetRendererID(gl_renderer_id_); | 262 context->share_group()->SetRendererID(gl_renderer_id_); |
| 453 return true; | 263 return true; |
| 454 } | 264 } |
| 455 | 265 |
| 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( | 266 bool ImageTransportSurfaceOverlayMac::ScheduleOverlayPlane( |
| 465 int z_order, | 267 int z_order, |
| 466 gfx::OverlayTransform transform, | 268 gfx::OverlayTransform transform, |
| 467 gl::GLImage* image, | 269 gl::GLImage* image, |
| 468 const gfx::Rect& pixel_frame_rect, | 270 const gfx::Rect& pixel_frame_rect, |
| 469 const gfx::RectF& crop_rect) { | 271 const gfx::RectF& crop_rect) { |
| 470 if (transform != gfx::OVERLAY_TRANSFORM_NONE) { | 272 if (transform != gfx::OVERLAY_TRANSFORM_NONE) { |
| 471 DLOG(ERROR) << "Invalid overlay plane transform."; | 273 DLOG(ERROR) << "Invalid overlay plane transform."; |
| 472 return false; | 274 return false; |
| 473 } | 275 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 } | 313 } |
| 512 | 314 |
| 513 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { | 315 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { |
| 514 return true; | 316 return true; |
| 515 } | 317 } |
| 516 | 318 |
| 517 bool ImageTransportSurfaceOverlayMac::Resize(const gfx::Size& pixel_size, | 319 bool ImageTransportSurfaceOverlayMac::Resize(const gfx::Size& pixel_size, |
| 518 float scale_factor, | 320 float scale_factor, |
| 519 bool has_alpha) { | 321 bool has_alpha) { |
| 520 // Flush through any pending frames. | 322 // Flush through any pending frames. |
| 521 DisplayAndClearAllPendingSwaps(); | |
| 522 pixel_size_ = pixel_size; | 323 pixel_size_ = pixel_size; |
| 523 scale_factor_ = scale_factor; | 324 scale_factor_ = scale_factor; |
| 524 return true; | 325 return true; |
| 525 } | 326 } |
| 526 | 327 |
| 527 void ImageTransportSurfaceOverlayMac::OnGpuSwitched() { | 328 void ImageTransportSurfaceOverlayMac::OnGpuSwitched() { |
| 528 // Create a new context, and use the GL renderer ID that the new context gets. | 329 // Create a new context, and use the GL renderer ID that the new context gets. |
| 529 scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu = | 330 scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu = |
| 530 ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext); | 331 ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext); |
| 531 if (!context_on_new_gpu) | 332 if (!context_on_new_gpu) |
| 532 return; | 333 return; |
| 533 GLint context_renderer_id = -1; | 334 GLint context_renderer_id = -1; |
| 534 if (CGLGetParameter(context_on_new_gpu->cgl_context(), | 335 if (CGLGetParameter(context_on_new_gpu->cgl_context(), |
| 535 kCGLCPCurrentRendererID, | 336 kCGLCPCurrentRendererID, |
| 536 &context_renderer_id) != kCGLNoError) { | 337 &context_renderer_id) != kCGLNoError) { |
| 537 LOG(ERROR) << "Failed to create test context after GPU switch"; | 338 LOG(ERROR) << "Failed to create test context after GPU switch"; |
| 538 return; | 339 return; |
| 539 } | 340 } |
| 540 gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask; | 341 gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask; |
| 541 | 342 |
| 542 // Post a task holding a reference to the new GL context. The reason for | 343 // 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 | 344 // this is to avoid creating-then-destroying the context for every image |
| 544 // transport surface that is observing the GPU switch. | 345 // transport surface that is observing the GPU switch. |
| 545 base::MessageLoop::current()->PostTask( | 346 base::MessageLoop::current()->PostTask( |
| 546 FROM_HERE, base::Bind(&IOSurfaceContextNoOp, context_on_new_gpu)); | 347 FROM_HERE, base::Bind(&IOSurfaceContextNoOp, context_on_new_gpu)); |
| 547 } | 348 } |
| 548 | 349 |
| 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 gpu | 350 } // namespace gpu |
| OLD | NEW |