Index: content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
diff --git a/content/browser/renderer_host/compositing_iosurface_layer_mac.mm b/content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
index 040d8f9fb8e1de21351a3ddcd044286c1bc633a4..3ee962d0788da402ae5be25173e998a8da9a4093 100644 |
--- a/content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
+++ b/content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
@@ -17,29 +17,114 @@ |
#include "ui/gfx/size_conversions.h" |
#include "ui/gl/gpu_switching_manager.h" |
-@interface CompositingIOSurfaceLayer(Private) |
-- (void)immediatelyForceDisplayAndAck; |
-- (void)ackPendingFrame:(bool)success; |
-- (void)timerFired; |
-@end |
+//////////////////////////////////////////////////////////////////////////////// |
+// CompositingIOSurfaceLayerHelper |
namespace content { |
-// The base::DelayTimer needs a C++ class to operate on, rather than Objective C |
-// class. This helper class provides a bridge between the two. |
-class CompositingIOSurfaceLayerHelper { |
- public: |
- CompositingIOSurfaceLayerHelper(CompositingIOSurfaceLayer* layer) |
- : layer_(layer) {} |
- void TimerFired() { |
- [layer_ timerFired]; |
+CompositingIOSurfaceLayerHelper::CompositingIOSurfaceLayerHelper( |
+ CompositingIOSurfaceLayerClient* client, |
+ CompositingIOSurfaceLayer* layer) |
+ : client_(client), |
+ layer_(layer), |
+ needs_display_(false), |
+ has_pending_frame_(false), |
+ did_not_draw_counter_(0), |
+ timer_( |
+ FROM_HERE, |
+ base::TimeDelta::FromSeconds(1) / 6, |
+ this, |
+ &CompositingIOSurfaceLayerHelper::TimerFired) {} |
+ |
+CompositingIOSurfaceLayerHelper::~CompositingIOSurfaceLayerHelper() { |
+ // Any acks that were waiting on this layer to draw will not occur, so ack |
+ // them now to prevent blocking the renderer. |
+ AckPendingFrame(true); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::GotNewFrame() { |
+ has_pending_frame_ = true; |
+ needs_display_ = true; |
+ timer_.Reset(); |
+ |
+ if ([layer_ context] && [layer_ context]->is_vsync_disabled()) { |
+ // If vsync is disabled, draw immediately and don't bother trying to use |
+ // the isAsynchronous property to ensure smooth animation. |
+ ImmediatelyForceDisplayAndAck(); |
+ } else { |
+ needs_display_ = YES; |
+ if (![layer_ isAsynchronous]) |
+ [layer_ setAsynchronous:YES]; |
+ } |
+ |
+ // A trace value of 2 indicates that there is a pending swap ack. See |
+ // canDrawInCGLContext for other value meanings. |
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::SetNeedsDisplay() { |
+ needs_display_ = true; |
+} |
+ |
+bool CompositingIOSurfaceLayerHelper::CanDraw() { |
+ // If we return NO 30 times in a row, switch to being synchronous to avoid |
+ // burning CPU cycles on this callback. |
+ if (needs_display_) { |
+ did_not_draw_counter_ = 0; |
+ } else { |
+ did_not_draw_counter_ += 1; |
+ if (did_not_draw_counter_ == 30) |
+ [layer_ setAsynchronous:NO]; |
} |
- private: |
- CompositingIOSurfaceLayer* layer_; |
-}; |
+ |
+ // Add an instantaneous blip to the PendingSwapAck state to indicate |
+ // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually |
+ // from 2, indicating that a swap ack is pending) indicates that we |
+ // requested a draw. A blip up to 1 (usually from 0, indicating there is no |
+ // pending swap ack) indicates that we did not request a draw. This would |
+ // be more natural to do with a tracing pseudo-thread |
+ // http://crbug.com/366300 |
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display_ ? 3 : 1); |
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, |
+ has_pending_frame_ ? 2 : 0); |
+ |
+ return needs_display_; |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::DidDraw(bool success) { |
+ needs_display_ = false; |
+ AckPendingFrame(success); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::AckPendingFrame(bool success) { |
+ if (!has_pending_frame_) |
+ return; |
+ has_pending_frame_ = false; |
+ client_->AcceleratedLayerDidDrawFrame(success); |
+ // A trace value of 0 indicates that there is no longer a pending swap ack. |
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::ImmediatelyForceDisplayAndAck() { |
+ [layer_ setNeedsDisplay]; |
+ [layer_ displayIfNeeded]; |
+ |
+ // Calls to setNeedsDisplay can sometimes be ignored, especially if issued |
+ // rapidly (e.g, with vsync off). This is unacceptable because the failure |
+ // to ack a single frame will hang the renderer. Ensure that the renderer |
+ // not be blocked by lying and claiming that we drew the frame. |
+ AckPendingFrame(true); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::TimerFired() { |
+ ImmediatelyForceDisplayAndAck(); |
+} |
} // namespace content |
+//////////////////////////////////////////////////////////////////////////////// |
+// CompositingIOSurfaceLayer |
+ |
@implementation CompositingIOSurfaceLayer |
- (content::CompositingIOSurfaceMac*)iosurface { |
@@ -55,21 +140,12 @@ class CompositingIOSurfaceLayerHelper { |
withScaleFactor:(float)scale_factor |
withClient:(content::CompositingIOSurfaceLayerClient*)client { |
if (self = [super init]) { |
- iosurface_ = iosurface; |
- client_ = client; |
- helper_.reset(new content::CompositingIOSurfaceLayerHelper(self)); |
- timer_.reset(new base::DelayTimer<content::CompositingIOSurfaceLayerHelper>( |
- FROM_HERE, |
- base::TimeDelta::FromSeconds(1) / 6, |
- helper_.get(), |
- &content::CompositingIOSurfaceLayerHelper::TimerFired)); |
+ helper_.reset(new content::CompositingIOSurfaceLayerHelper(client, self)); |
+ iosurface_ = iosurface; |
context_ = content::CompositingIOSurfaceContext::Get( |
content::CompositingIOSurfaceContext::kCALayerContextWindowNumber); |
DCHECK(context_); |
- needs_display_ = NO; |
- has_pending_frame_ = NO; |
- did_not_draw_counter_ = 0; |
[self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; |
[self setAnchorPoint:CGPointMake(0, 0)]; |
@@ -83,58 +159,17 @@ class CompositingIOSurfaceLayerHelper { |
return self; |
} |
-- (void)resetClient { |
- // Any acks that were waiting on this layer to draw will not occur, so ack |
- // them now to prevent blocking the renderer. |
- [self ackPendingFrame:true]; |
- client_ = NULL; |
-} |
- |
-- (void)gotNewFrame { |
- has_pending_frame_ = YES; |
- timer_->Reset(); |
- |
- // A trace value of 2 indicates that there is a pending swap ack. See |
- // canDrawInCGLContext for other value meanings. |
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 2); |
- |
- if (context_ && context_->is_vsync_disabled()) { |
- // If vsync is disabled, draw immediately and don't bother trying to use |
- // the isAsynchronous property to ensure smooth animation. |
- [self immediatelyForceDisplayAndAck]; |
- } else { |
- needs_display_ = YES; |
- if (![self isAsynchronous]) |
- [self setAsynchronous:YES]; |
- } |
-} |
- |
-// Private methods: |
- |
-- (void)immediatelyForceDisplayAndAck { |
- [self setNeedsDisplay]; |
- [self displayIfNeeded]; |
- |
- // Calls to setNeedsDisplay can sometimes be ignored, especially if issued |
- // rapidly (e.g, with vsync off). This is unacceptable because the failure |
- // to ack a single frame will hang the renderer. Ensure that the renderer |
- // not be blocked by lying and claiming that we drew the frame. |
- [self ackPendingFrame:true]; |
+- (void)dealloc { |
+ DCHECK(!helper_); |
+ [super dealloc]; |
} |
-- (void)ackPendingFrame:(bool)success { |
- if (!has_pending_frame_) |
- return; |
- |
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 0); |
- has_pending_frame_ = NO; |
- if (client_) |
- client_->AcceleratedLayerDidDrawFrame(success); |
+- (void)resetClient { |
+ helper_.reset(); |
} |
-- (void)timerFired { |
- if (has_pending_frame_) |
- [self immediatelyForceDisplayAndAck]; |
+- (void)gotNewFrame { |
+ helper_->GotNewFrame(); |
} |
// The remaining methods implement the CAOpenGLLayer interface. |
@@ -152,7 +187,8 @@ class CompositingIOSurfaceLayerHelper { |
} |
- (void)setNeedsDisplay { |
- needs_display_ = YES; |
+ if (helper_) |
+ helper_->SetNeedsDisplay(); |
[super setNeedsDisplay]; |
} |
@@ -160,28 +196,9 @@ class CompositingIOSurfaceLayerHelper { |
pixelFormat:(CGLPixelFormatObj)pixelFormat |
forLayerTime:(CFTimeInterval)timeInterval |
displayTime:(const CVTimeStamp*)timeStamp { |
- // Add an instantaneous blip to the PendingSwapAck state to indicate |
- // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually |
- // from 2, indicating that a swap ack is pending) indicates that we requested |
- // a draw. A blip up to 1 (usually from 0, indicating there is no pending swap |
- // ack) indicates that we did not request a draw. This would be more natural |
- // to do with a tracing pseudo-thread |
- // http://crbug.com/366300 |
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, needs_display_ ? 3 : 1); |
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, |
- has_pending_frame_ ? 2 : 0); |
- |
- // If we return NO 30 times in a row, switch to being synchronous to avoid |
- // burning CPU cycles on this callback. |
- if (needs_display_) { |
- did_not_draw_counter_ = 0; |
- } else { |
- did_not_draw_counter_ += 1; |
- if (did_not_draw_counter_ > 30) |
- [self setAsynchronous:NO]; |
- } |
- |
- return needs_display_; |
+ if (helper_) |
+ return helper_->CanDraw(); |
+ return NO; |
} |
- (void)drawInCGLContext:(CGLContextObj)glContext |
@@ -211,8 +228,8 @@ class CompositingIOSurfaceLayerHelper { |
bool draw_succeeded = iosurface_->DrawIOSurface( |
context_, window_rect, window_scale_factor); |
- [self ackPendingFrame:draw_succeeded]; |
- needs_display_ = NO; |
+ if (helper_) |
+ helper_->DidDraw(draw_succeeded); |
[super drawInCGLContext:glContext |
pixelFormat:pixelFormat |