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..724e56c9ff7dc292c433b46c3e3a0e763e84784d 100644 |
--- a/content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
+++ b/content/browser/renderer_host/compositing_iosurface_layer_mac.mm |
@@ -17,29 +17,90 @@ |
#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), |
+ 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; |
+ 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", this, 2); |
+} |
+ |
+void CompositingIOSurfaceLayerHelper::CanDrawCalled(bool needs_display) { |
+ // 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; |
miu
2014/07/16 22:31:56
Seems like this should only be set to zero when se
ccameron
2014/07/17 02:30:02
This is a bit easier to reason about correctness,
|
+ } else { |
+ did_not_draw_counter_ += 1; |
+ if (did_not_draw_counter_ > 30) |
miu
2014/07/16 22:31:55
Consider making this:
if (did_not_draw_counter_
ccameron
2014/07/17 02:30:02
Good idea -- done.
|
+ [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); |
+} |
+ |
+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 +116,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; |
miu
2014/07/16 22:31:56
I think you meant to keep this statement. But, if
ccameron
2014/07/17 02:30:02
Moved it to the C++ class.
|
- has_pending_frame_ = NO; |
- did_not_draw_counter_ = 0; |
[self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; |
[self setAnchorPoint:CGPointMake(0, 0)]; |
@@ -83,25 +135,22 @@ class CompositingIOSurfaceLayerHelper { |
return self; |
} |
+- (void)dealloc { |
+ DCHECK(!helper_); |
+ [super dealloc]; |
+} |
+ |
- (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; |
+ helper_.reset(); |
} |
- (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); |
+ helper_->GotNewFrame(); |
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]; |
+ helper_->ImmediatelyForceDisplayAndAck(); |
} else { |
needs_display_ = YES; |
if (![self isAsynchronous]) |
miu
2014/07/16 22:31:55
This should be moved into the helper. That way, a
ccameron
2014/07/17 02:30:02
You're right -- moved it to the helper.
|
@@ -109,34 +158,6 @@ class CompositingIOSurfaceLayerHelper { |
} |
} |
-// 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)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)timerFired { |
- if (has_pending_frame_) |
- [self immediatelyForceDisplayAndAck]; |
-} |
- |
// The remaining methods implement the CAOpenGLLayer interface. |
- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { |
@@ -160,27 +181,8 @@ 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]; |
- } |
- |
+ if (helper_) |
+ helper_->CanDrawCalled(needs_display_); |
return needs_display_; |
} |
@@ -211,7 +213,8 @@ class CompositingIOSurfaceLayerHelper { |
bool draw_succeeded = iosurface_->DrawIOSurface( |
context_, window_rect, window_scale_factor); |
- [self ackPendingFrame:draw_succeeded]; |
+ if (helper_) |
+ helper_->AckPendingFrame(draw_succeeded); |
needs_display_ = NO; |
[super drawInCGLContext:glContext |