| 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 2e6911ce06aac51b1525d1522cc5f4edf936d62c..8f222c5062086ba1d1a60a68c263a58b151c61b9 100644
|
| --- a/content/common/gpu/image_transport_surface_overlay_mac.mm
|
| +++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
|
| @@ -64,6 +64,10 @@ class ImageTransportSurfaceOverlayMac::PendingSwap {
|
| float scale_factor;
|
| std::vector<ui::LatencyInfo> latency_info;
|
|
|
| + // If true, the partial damage rect for the frame.
|
| + bool use_partial_damage;
|
| + gfx::Rect pixel_partial_damage_rect;
|
| +
|
| // The IOSurface with new content for this swap.
|
| base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
|
|
|
| @@ -105,6 +109,9 @@ bool ImageTransportSurfaceOverlayMac::Initialize() {
|
| [layer_ setGeometryFlipped:YES];
|
| [layer_ setOpaque:YES];
|
| [ca_context_ setLayer:layer_];
|
| +
|
| + partial_damage_layer_.reset([[CALayer alloc] init]);
|
| + [partial_damage_layer_ setOpaque:YES];
|
| return true;
|
| }
|
|
|
| @@ -180,6 +187,36 @@ gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
|
| new_swap->latest_allowed_draw_time = now;
|
| }
|
|
|
| + // Determine if this will be a full or partial damage, and compute the rects
|
| + // for the damage.
|
| + {
|
| + // 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.
|
| + const double kMaximumFractionOfFullDamage = 0.85;
|
| + double fraction_of_full_damage =
|
| + 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.
|
| + const 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) {
|
| + new_swap->use_partial_damage = true;
|
| + new_swap->pixel_partial_damage_rect =
|
| + accumulated_partial_damage_pixel_rect_;
|
| + } else {
|
| + new_swap->use_partial_damage = false;
|
| + accumulated_partial_damage_pixel_rect_ = gfx::Rect();
|
| + }
|
| + }
|
| +
|
| pending_swaps_.push_back(new_swap);
|
| PostCheckPendingSwapsCallbackIfNeeded(now);
|
| return gfx::SwapResult::SWAP_ACK;
|
| @@ -246,12 +283,44 @@ void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() {
|
| ScopedCAActionDisabler disabler;
|
|
|
| id new_contents = static_cast<id>(swap->io_surface.get());
|
| - [layer_ setContents:new_contents];
|
| -
|
| - CGRect new_frame = gfx::ConvertRectToDIP(
|
| - swap->scale_factor, gfx::Rect(swap->pixel_size)).ToCGRect();
|
| - if (!CGRectEqualToRect([layer_ frame], new_frame))
|
| - [layer_ setFrame:new_frame];
|
| + if (swap->use_partial_damage) {
|
| + if (![partial_damage_layer_ superlayer])
|
| + [layer_ addSublayer:partial_damage_layer_];
|
| + [partial_damage_layer_ setContents:new_contents];
|
| +
|
| + CGRect new_frame = gfx::ConvertRectToDIP(
|
| + swap->scale_factor, swap->pixel_partial_damage_rect).ToCGRect();
|
| + if (!CGRectEqualToRect([partial_damage_layer_ frame], new_frame))
|
| + [partial_damage_layer_ setFrame:new_frame];
|
| +
|
| + gfx::RectF contents_rect =
|
| + gfx::RectF(swap->pixel_partial_damage_rect);
|
| + contents_rect.Scale(
|
| + 1. / swap->pixel_size.width(), 1. / swap->pixel_size.height());
|
| + CGRect cg_contents_rect = CGRectMake(
|
| + contents_rect.x(), contents_rect.y(),
|
| + contents_rect.width(), contents_rect.height());
|
| + [partial_damage_layer_ setContentsRect:cg_contents_rect];
|
| + } else {
|
| + // Remove the partial damage layer.
|
| + 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.
|
| + if ([layer_ contents] == new_contents)
|
| + [layer_ setContentsChanged];
|
| + else
|
| + [layer_ setContents:new_contents];
|
| +
|
| + CGRect new_frame = gfx::ConvertRectToDIP(
|
| + swap->scale_factor, gfx::Rect(swap->pixel_size)).ToCGRect();
|
| + if (!CGRectEqualToRect([layer_ frame], new_frame))
|
| + [layer_ setFrame:new_frame];
|
| + }
|
| }
|
|
|
| // Send acknowledgement to the browser.
|
|
|