diff options
author | ccameron <ccameron@chromium.org> | 2015-08-10 18:41:45 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-11 01:42:49 +0000 |
commit | aae371ca10e047d9b192acf869f8ff9601d3cdf7 (patch) | |
tree | e769084bff1f212d7e076e0b0c6eba1dbe9c1122 | |
parent | c1b891418bbfafcc620ca50805c0b7d610ba4cff (diff) | |
download | chromium_src-aae371ca10e047d9b192acf869f8ff9601d3cdf7.zip chromium_src-aae371ca10e047d9b192acf869f8ff9601d3cdf7.tar.gz chromium_src-aae371ca10e047d9b192acf869f8ff9601d3cdf7.tar.bz2 |
Mac: Enable partial swap
This is pretty trivial when using the overlay path. Just create a
new layer for the damage. The partial damage layer can be created,
removed, or resized with basically no cost, because its backing is the
already-existing IOSurface.
As each partial swap comes in, union the existing overlay layer's
rect with the rect of the new partial swap. If this grows "too big",
then do a full swap (which clears the accumulated union). The
constants here are pretty arbitrary.
BUG=474299
Review URL: https://codereview.chromium.org/1271123002
Cr-Commit-Position: refs/heads/master@{#342771}
-rw-r--r-- | content/common/gpu/image_transport_surface_overlay_mac.h | 5 | ||||
-rw-r--r-- | content/common/gpu/image_transport_surface_overlay_mac.mm | 81 | ||||
-rw-r--r-- | ui/gfx/geometry/rect_f.cc | 16 | ||||
-rw-r--r-- | ui/gfx/geometry/rect_f.h | 10 |
4 files changed, 106 insertions, 6 deletions
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.h b/content/common/gpu/image_transport_surface_overlay_mac.h index 022fbb4..1265cc4 100644 --- a/content/common/gpu/image_transport_surface_overlay_mac.h +++ b/content/common/gpu/image_transport_surface_overlay_mac.h @@ -79,6 +79,7 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface, scoped_ptr<ImageTransportHelper> helper_; base::scoped_nsobject<CAContext> ca_context_; base::scoped_nsobject<CALayer> layer_; + base::scoped_nsobject<CALayer> partial_damage_layer_; gfx::Size pixel_size_; float scale_factor_; @@ -94,6 +95,10 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface, // every swap and also by a callback. std::deque<linked_ptr<PendingSwap>> pending_swaps_; + // The union of the damage rects of SwapBuffersInternal since the last + // non-partial swap. + gfx::Rect accumulated_partial_damage_pixel_rect_; + // The display link used to compute the time for callbacks. scoped_refptr<ui::DisplayLinkMac> display_link_mac_; diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm index 2e6911c..8f222c5 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. diff --git a/ui/gfx/geometry/rect_f.cc b/ui/gfx/geometry/rect_f.cc index c87ea3d..a15bdf3 100644 --- a/ui/gfx/geometry/rect_f.cc +++ b/ui/gfx/geometry/rect_f.cc @@ -6,6 +6,12 @@ #include <algorithm> +#if defined(OS_IOS) +#include <CoreGraphics/CoreGraphics.h> +#elif defined(OS_MACOSX) +#include <ApplicationServices/ApplicationServices.h> +#endif + #include "base/logging.h" #include "base/strings/stringprintf.h" #include "ui/gfx/geometry/insets_f.h" @@ -24,6 +30,16 @@ static void AdjustAlongAxis(float dst_origin, *origin = std::min(dst_origin + dst_size, *origin + *size) - *size; } +#if defined(OS_MACOSX) +RectF::RectF(const CGRect& r) + : origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) { +} + +CGRect RectF::ToCGRect() const { + return CGRectMake(x(), y(), width(), height()); +} +#endif + void RectF::Inset(const InsetsF& insets) { Inset(insets.left(), insets.top(), insets.right(), insets.bottom()); } diff --git a/ui/gfx/geometry/rect_f.h b/ui/gfx/geometry/rect_f.h index dc233a7..3b132667e 100644 --- a/ui/gfx/geometry/rect_f.h +++ b/ui/gfx/geometry/rect_f.h @@ -12,6 +12,10 @@ #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/vector2d_f.h" +#if defined(OS_MACOSX) +typedef struct CGRect CGRect; +#endif + namespace gfx { class InsetsF; @@ -27,6 +31,12 @@ class GFX_EXPORT RectF { RectF(const PointF& origin, const SizeF& size) : origin_(origin), size_(size) {} +#if defined(OS_MACOSX) + explicit RectF(const CGRect& r); + // Construct an equivalent CoreGraphics object. + CGRect ToCGRect() const; +#endif + ~RectF() {} float x() const { return origin_.x(); } |