Chromium Code Reviews| Index: content/common/gpu/image_transport_surface_overlay_mac.mm |
| diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm |
| index c9fbe56e67e952a2bbe859d677470fcb4f024d04..b9ac795cc772bd9d51c0ef334567edeba8acbaea 100644 |
| --- a/content/common/gpu/image_transport_surface_overlay_mac.mm |
| +++ b/content/common/gpu/image_transport_surface_overlay_mac.mm |
| @@ -24,6 +24,10 @@ |
| } \ |
| } while (0) |
| +@interface CALayer(Private) |
| +-(void) setContentsChanged; |
|
Andre
2015/08/05 17:59:30
- (void)set...
ccameron
2015/08/06 18:55:18
Done.
|
| +@end |
| + |
| namespace content { |
| ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( |
| @@ -48,6 +52,7 @@ bool ImageTransportSurfaceOverlayMac::Initialize() { |
| [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); |
| layer_.reset([[CALayer alloc] init]); |
| [layer_ setGeometryFlipped:YES]; |
| + partial_damage_layer_.reset([[CALayer alloc] init]); |
| [ca_context_ setLayer:layer_]; |
| return true; |
| @@ -93,9 +98,39 @@ gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( |
| LOG_GL_ERRORS("while flushing frame"); |
| } |
| - this_swap.dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_); |
| - pending_swaps_.push_back(this_swap); |
| + // Determine if this will be a full or partial damage, and compute the rects |
| + // for the damage. |
| + { |
| + this_swap.dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_); |
| + |
| + // Grow the partial damage rect to include the new damage. |
| + accumulated_partial_damage_pixel_rect_.Union(pixel_damage_rect); |
| + // Compute the fraction of the full layer that has been damaged. If this |
| + // fraction is very large (>85%), just damage the full layer, and don't |
| + // bother with the partial layer. |
| + double kMaximumFractionOfFullDamage = 0.85; |
|
Andre
2015/08/05 17:59:30
nit: const
ccameron
2015/08/06 18:55:18
Done.
|
| + double fraction_of_full_damage = |
|
Andre
2015/08/05 17:59:30
nit: const
ccameron
2015/08/06 18:55:18
Done.
|
| + accumulated_partial_damage_pixel_rect_.size().GetArea() / |
| + static_cast<double>(pixel_size_.GetArea()); |
| + // Compute the fraction of the accumulated partial damage rect that has been |
| + // damaged. If this gets too small (<75%), just re-damage the full window, |
| + // so we can re-create a smaller partial damage layer next frame. |
| + double kMinimumFractionOfPartialDamage = 0.75; |
| + double fraction_of_partial_damage = |
| + pixel_damage_rect.size().GetArea() / static_cast<double>( |
| + accumulated_partial_damage_pixel_rect_.size().GetArea()); |
| + if (fraction_of_full_damage < kMaximumFractionOfFullDamage && |
| + fraction_of_partial_damage > kMinimumFractionOfPartialDamage) { |
| + this_swap.use_partial_damage = true; |
| + this_swap.dip_partial_damage_rect = gfx::ConvertRectToDIP( |
| + scale_factor_, accumulated_partial_damage_pixel_rect_); |
| + } else { |
| + this_swap.use_partial_damage = false; |
| + accumulated_partial_damage_pixel_rect_ = gfx::Rect(); |
| + } |
| + } |
| + pending_swaps_.push_back(this_swap); |
| PostCheckAndDisplayPendingSwaps(); |
| return gfx::SwapResult::SWAP_ACK; |
| } |
| @@ -131,9 +166,39 @@ void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps( |
| TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents", |
| "surface", this_swap.io_surface.get()); |
| ScopedCAActionDisabler disabler; |
| - id new_contents = static_cast<id>(this_swap.io_surface.get()); |
| - [layer_ setContents:new_contents]; |
| - [layer_ setFrame:gfx::Rect(this_swap.dip_size).ToCGRect()]; |
| + if (this_swap.use_partial_damage) { |
| + if (![partial_damage_layer_ superlayer]) |
| + [layer_ addSublayer:partial_damage_layer_]; |
| + |
| + [partial_damage_layer_ |
| + setContents:static_cast<id>(this_swap.io_surface.get())]; |
| + [partial_damage_layer_ |
| + setFrame:this_swap.dip_partial_damage_rect.ToCGRect()]; |
| + gfx::RectF content_bounds_rect = |
| + gfx::RectF(this_swap.dip_partial_damage_rect); |
| + content_bounds_rect.Scale( |
| + 1. / this_swap.dip_size.width(), 1. / this_swap.dip_size.height()); |
| + [partial_damage_layer_ setContentsRect:CGRectMake( |
| + content_bounds_rect.x(), |
| + content_bounds_rect.y(), |
| + content_bounds_rect.width(), |
| + content_bounds_rect.height())]; |
|
Andre
2015/08/05 17:59:30
How about something like:
CGRect damage_rect = thi
ccameron
2015/08/06 18:55:18
Actually, gfx::RectF should have a ToCGRect functi
|
| + } else { |
| + if ([partial_damage_layer_ superlayer]) { |
| + [partial_damage_layer_ removeFromSuperlayer]; |
| + [partial_damage_layer_ setContents:nil]; |
| + } |
| + |
| + // Note that calling setContents with the same IOSurface twice will result |
| + // in the screen not being updated, even if the IOSurface's content has |
| + // changed. Avoid this by calling setContentsChanged. |
| + id new_contents = static_cast<id>(this_swap.io_surface.get()); |
| + if ([layer_ contents] == new_contents) |
| + [layer_ setContentsChanged]; |
| + else |
| + [layer_ setContents:static_cast<id>(this_swap.io_surface.get())]; |
|
Andre
2015/08/05 17:59:30
setContents:new_contents
ccameron
2015/08/06 18:55:18
Done.
|
| + [layer_ setFrame:gfx::Rect(this_swap.dip_size).ToCGRect()]; |
| + } |
| } |
| // Remove this swap from the queue. |
| @@ -252,7 +317,7 @@ void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} |
| ImageTransportSurfaceOverlayMac::PendingSwap::PendingSwap() |
| - : fence(0) { |
| + : fence(0), use_partial_damage(false) { |
| } |
| ImageTransportSurfaceOverlayMac::PendingSwap::~PendingSwap() { |