Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: content/browser/renderer_host/compositing_iosurface_layer_mac.mm

Issue 394883007: Mac: Shift more code into C++ classes from ObjC classes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@flip_fix
Patch Set: Touch-ups Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/compositing_iosurface_layer_mac.h" 5 #include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 #include <OpenGL/gl.h> 8 #include <OpenGL/gl.h>
9 9
10 #include "base/mac/mac_util.h" 10 #include "base/mac/mac_util.h"
11 #include "base/mac/sdk_forward_declarations.h" 11 #include "base/mac/sdk_forward_declarations.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h" 12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/browser/renderer_host/render_widget_host_view_mac.h" 13 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
14 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" 14 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
15 #include "content/browser/renderer_host/compositing_iosurface_mac.h" 15 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
16 #include "ui/base/cocoa/animation_utils.h" 16 #include "ui/base/cocoa/animation_utils.h"
17 #include "ui/gfx/size_conversions.h" 17 #include "ui/gfx/size_conversions.h"
18 #include "ui/gl/gpu_switching_manager.h" 18 #include "ui/gl/gpu_switching_manager.h"
19 19
20 @interface CompositingIOSurfaceLayer(Private) 20 ////////////////////////////////////////////////////////////////////////////////
21 - (void)immediatelyForceDisplayAndAck; 21 // CompositingIOSurfaceLayerHelper
22 - (void)ackPendingFrame:(bool)success;
23 - (void)timerFired;
24 @end
25 22
26 namespace content { 23 namespace content {
27 24
28 // The base::DelayTimer needs a C++ class to operate on, rather than Objective C 25 CompositingIOSurfaceLayerHelper::CompositingIOSurfaceLayerHelper(
29 // class. This helper class provides a bridge between the two. 26 CompositingIOSurfaceLayerClient* client,
30 class CompositingIOSurfaceLayerHelper { 27 CompositingIOSurfaceLayer* layer)
31 public: 28 : client_(client),
32 CompositingIOSurfaceLayerHelper(CompositingIOSurfaceLayer* layer) 29 layer_(layer),
33 : layer_(layer) {} 30 has_pending_frame_(false),
34 void TimerFired() { 31 did_not_draw_counter_(0),
35 [layer_ timerFired]; 32 timer_(
33 FROM_HERE,
34 base::TimeDelta::FromSeconds(1) / 6,
35 this,
36 &CompositingIOSurfaceLayerHelper::TimerFired) {}
37
38 CompositingIOSurfaceLayerHelper::~CompositingIOSurfaceLayerHelper() {
39 // Any acks that were waiting on this layer to draw will not occur, so ack
40 // them now to prevent blocking the renderer.
41 AckPendingFrame(true);
42 }
43
44 void CompositingIOSurfaceLayerHelper::GotNewFrame() {
45 has_pending_frame_ = true;
46 timer_.Reset();
47 // A trace value of 2 indicates that there is a pending swap ack. See
48 // canDrawInCGLContext for other value meanings.
49 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2);
50 }
51
52 void CompositingIOSurfaceLayerHelper::CanDrawCalled(bool needs_display) {
53 // If we return NO 30 times in a row, switch to being synchronous to avoid
54 // burning CPU cycles on this callback.
55 if (needs_display) {
56 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,
57 } else {
58 did_not_draw_counter_ += 1;
59 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.
60 [layer_ setAsynchronous:NO];
36 } 61 }
37 private: 62
38 CompositingIOSurfaceLayer* layer_; 63 // Add an instantaneous blip to the PendingSwapAck state to indicate
39 }; 64 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually
65 // from 2, indicating that a swap ack is pending) indicates that we
66 // requested a draw. A blip up to 1 (usually from 0, indicating there is no
67 // pending swap ack) indicates that we did not request a draw. This would
68 // be more natural to do with a tracing pseudo-thread
69 // http://crbug.com/366300
70 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display ? 3 : 1);
71 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this,
72 has_pending_frame_ ? 2 : 0);
73 }
74
75 void CompositingIOSurfaceLayerHelper::AckPendingFrame(bool success) {
76 if (!has_pending_frame_)
77 return;
78 has_pending_frame_ = false;
79 client_->AcceleratedLayerDidDrawFrame(success);
80 // A trace value of 0 indicates that there is no longer a pending swap ack.
81 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
82 }
83
84 void CompositingIOSurfaceLayerHelper::ImmediatelyForceDisplayAndAck() {
85 [layer_ setNeedsDisplay];
86 [layer_ displayIfNeeded];
87
88 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
89 // rapidly (e.g, with vsync off). This is unacceptable because the failure
90 // to ack a single frame will hang the renderer. Ensure that the renderer
91 // not be blocked by lying and claiming that we drew the frame.
92 AckPendingFrame(true);
93 }
94
95 void CompositingIOSurfaceLayerHelper::TimerFired() {
96 ImmediatelyForceDisplayAndAck();
97 }
40 98
41 } // namespace content 99 } // namespace content
42 100
101 ////////////////////////////////////////////////////////////////////////////////
102 // CompositingIOSurfaceLayer
103
43 @implementation CompositingIOSurfaceLayer 104 @implementation CompositingIOSurfaceLayer
44 105
45 - (content::CompositingIOSurfaceMac*)iosurface { 106 - (content::CompositingIOSurfaceMac*)iosurface {
46 return iosurface_.get(); 107 return iosurface_.get();
47 } 108 }
48 109
49 - (content::CompositingIOSurfaceContext*)context { 110 - (content::CompositingIOSurfaceContext*)context {
50 return context_.get(); 111 return context_.get();
51 } 112 }
52 113
53 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>) 114 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>)
54 iosurface 115 iosurface
55 withScaleFactor:(float)scale_factor 116 withScaleFactor:(float)scale_factor
56 withClient:(content::CompositingIOSurfaceLayerClient*)client { 117 withClient:(content::CompositingIOSurfaceLayerClient*)client {
57 if (self = [super init]) { 118 if (self = [super init]) {
119 helper_.reset(new content::CompositingIOSurfaceLayerHelper(client, self));
120
58 iosurface_ = iosurface; 121 iosurface_ = iosurface;
59 client_ = client;
60 helper_.reset(new content::CompositingIOSurfaceLayerHelper(self));
61 timer_.reset(new base::DelayTimer<content::CompositingIOSurfaceLayerHelper>(
62 FROM_HERE,
63 base::TimeDelta::FromSeconds(1) / 6,
64 helper_.get(),
65 &content::CompositingIOSurfaceLayerHelper::TimerFired));
66
67 context_ = content::CompositingIOSurfaceContext::Get( 122 context_ = content::CompositingIOSurfaceContext::Get(
68 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber); 123 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber);
69 DCHECK(context_); 124 DCHECK(context_);
70 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.
71 has_pending_frame_ = NO;
72 did_not_draw_counter_ = 0;
73 125
74 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; 126 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
75 [self setAnchorPoint:CGPointMake(0, 0)]; 127 [self setAnchorPoint:CGPointMake(0, 0)];
76 // Setting contents gravity is necessary to prevent the layer from being 128 // Setting contents gravity is necessary to prevent the layer from being
77 // scaled during dyanmic resizes (especially with devtools open). 129 // scaled during dyanmic resizes (especially with devtools open).
78 [self setContentsGravity:kCAGravityTopLeft]; 130 [self setContentsGravity:kCAGravityTopLeft];
79 if ([self respondsToSelector:(@selector(setContentsScale:))]) { 131 if ([self respondsToSelector:(@selector(setContentsScale:))]) {
80 [self setContentsScale:scale_factor]; 132 [self setContentsScale:scale_factor];
81 } 133 }
82 } 134 }
83 return self; 135 return self;
84 } 136 }
85 137
138 - (void)dealloc {
139 DCHECK(!helper_);
140 [super dealloc];
141 }
142
86 - (void)resetClient { 143 - (void)resetClient {
87 // Any acks that were waiting on this layer to draw will not occur, so ack 144 helper_.reset();
88 // them now to prevent blocking the renderer.
89 [self ackPendingFrame:true];
90 client_ = NULL;
91 } 145 }
92 146
93 - (void)gotNewFrame { 147 - (void)gotNewFrame {
94 has_pending_frame_ = YES; 148 helper_->GotNewFrame();
95 timer_->Reset();
96
97 // A trace value of 2 indicates that there is a pending swap ack. See
98 // canDrawInCGLContext for other value meanings.
99 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 2);
100 149
101 if (context_ && context_->is_vsync_disabled()) { 150 if (context_ && context_->is_vsync_disabled()) {
102 // If vsync is disabled, draw immediately and don't bother trying to use 151 // If vsync is disabled, draw immediately and don't bother trying to use
103 // the isAsynchronous property to ensure smooth animation. 152 // the isAsynchronous property to ensure smooth animation.
104 [self immediatelyForceDisplayAndAck]; 153 helper_->ImmediatelyForceDisplayAndAck();
105 } else { 154 } else {
106 needs_display_ = YES; 155 needs_display_ = YES;
107 if (![self isAsynchronous]) 156 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.
108 [self setAsynchronous:YES]; 157 [self setAsynchronous:YES];
109 } 158 }
110 } 159 }
111 160
112 // Private methods:
113
114 - (void)immediatelyForceDisplayAndAck {
115 [self setNeedsDisplay];
116 [self displayIfNeeded];
117
118 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
119 // rapidly (e.g, with vsync off). This is unacceptable because the failure
120 // to ack a single frame will hang the renderer. Ensure that the renderer
121 // not be blocked by lying and claiming that we drew the frame.
122 [self ackPendingFrame:true];
123 }
124
125 - (void)ackPendingFrame:(bool)success {
126 if (!has_pending_frame_)
127 return;
128
129 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 0);
130 has_pending_frame_ = NO;
131 if (client_)
132 client_->AcceleratedLayerDidDrawFrame(success);
133 }
134
135 - (void)timerFired {
136 if (has_pending_frame_)
137 [self immediatelyForceDisplayAndAck];
138 }
139
140 // The remaining methods implement the CAOpenGLLayer interface. 161 // The remaining methods implement the CAOpenGLLayer interface.
141 162
142 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { 163 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
143 if (!context_) 164 if (!context_)
144 return [super copyCGLPixelFormatForDisplayMask:mask]; 165 return [super copyCGLPixelFormatForDisplayMask:mask];
145 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); 166 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
146 } 167 }
147 168
148 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { 169 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
149 if (!context_) 170 if (!context_)
150 return [super copyCGLContextForPixelFormat:pixelFormat]; 171 return [super copyCGLContextForPixelFormat:pixelFormat];
151 return CGLRetainContext(context_->cgl_context()); 172 return CGLRetainContext(context_->cgl_context());
152 } 173 }
153 174
154 - (void)setNeedsDisplay { 175 - (void)setNeedsDisplay {
155 needs_display_ = YES; 176 needs_display_ = YES;
156 [super setNeedsDisplay]; 177 [super setNeedsDisplay];
157 } 178 }
158 179
159 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext 180 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
160 pixelFormat:(CGLPixelFormatObj)pixelFormat 181 pixelFormat:(CGLPixelFormatObj)pixelFormat
161 forLayerTime:(CFTimeInterval)timeInterval 182 forLayerTime:(CFTimeInterval)timeInterval
162 displayTime:(const CVTimeStamp*)timeStamp { 183 displayTime:(const CVTimeStamp*)timeStamp {
163 // Add an instantaneous blip to the PendingSwapAck state to indicate 184 if (helper_)
164 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually 185 helper_->CanDrawCalled(needs_display_);
165 // from 2, indicating that a swap ack is pending) indicates that we requested
166 // a draw. A blip up to 1 (usually from 0, indicating there is no pending swap
167 // ack) indicates that we did not request a draw. This would be more natural
168 // to do with a tracing pseudo-thread
169 // http://crbug.com/366300
170 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, needs_display_ ? 3 : 1);
171 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self,
172 has_pending_frame_ ? 2 : 0);
173
174 // If we return NO 30 times in a row, switch to being synchronous to avoid
175 // burning CPU cycles on this callback.
176 if (needs_display_) {
177 did_not_draw_counter_ = 0;
178 } else {
179 did_not_draw_counter_ += 1;
180 if (did_not_draw_counter_ > 30)
181 [self setAsynchronous:NO];
182 }
183
184 return needs_display_; 186 return needs_display_;
185 } 187 }
186 188
187 - (void)drawInCGLContext:(CGLContextObj)glContext 189 - (void)drawInCGLContext:(CGLContextObj)glContext
188 pixelFormat:(CGLPixelFormatObj)pixelFormat 190 pixelFormat:(CGLPixelFormatObj)pixelFormat
189 forLayerTime:(CFTimeInterval)timeInterval 191 forLayerTime:(CFTimeInterval)timeInterval
190 displayTime:(const CVTimeStamp*)timeStamp { 192 displayTime:(const CVTimeStamp*)timeStamp {
191 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext"); 193 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext");
192 194
193 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) { 195 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) {
(...skipping 10 matching lines...) Expand all
204 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]); 206 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
205 float window_scale_factor = 1.f; 207 float window_scale_factor = 1.f;
206 if ([self respondsToSelector:(@selector(contentsScale))]) 208 if ([self respondsToSelector:(@selector(contentsScale))])
207 window_scale_factor = [self contentsScale]; 209 window_scale_factor = [self contentsScale];
208 window_rect = ToNearestRect( 210 window_rect = ToNearestRect(
209 gfx::ScaleRect(window_rect, 1.f/window_scale_factor)); 211 gfx::ScaleRect(window_rect, 1.f/window_scale_factor));
210 212
211 bool draw_succeeded = iosurface_->DrawIOSurface( 213 bool draw_succeeded = iosurface_->DrawIOSurface(
212 context_, window_rect, window_scale_factor); 214 context_, window_rect, window_scale_factor);
213 215
214 [self ackPendingFrame:draw_succeeded]; 216 if (helper_)
217 helper_->AckPendingFrame(draw_succeeded);
215 needs_display_ = NO; 218 needs_display_ = NO;
216 219
217 [super drawInCGLContext:glContext 220 [super drawInCGLContext:glContext
218 pixelFormat:pixelFormat 221 pixelFormat:pixelFormat
219 forLayerTime:timeInterval 222 forLayerTime:timeInterval
220 displayTime:timeStamp]; 223 displayTime:timeStamp];
221 } 224 }
222 225
223 @end 226 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698