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() { |