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

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

Issue 490393002: Simplify IOSurface CoreAnimation code: Part 2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Lower similarity Created 6 years, 4 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <OpenGL/gl.h>
9
10 #include "base/mac/mac_util.h"
11 #include "base/mac/sdk_forward_declarations.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
14 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
15 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
16 #include "ui/base/cocoa/animation_utils.h"
17 #include "ui/gfx/size_conversions.h"
18 #include "ui/gl/gpu_switching_manager.h"
19
20 ////////////////////////////////////////////////////////////////////////////////
21 // CompositingIOSurfaceLayerHelper
22
23 namespace content {
24
25 CompositingIOSurfaceLayerHelper::CompositingIOSurfaceLayerHelper(
26 CompositingIOSurfaceLayerClient* client,
27 CompositingIOSurfaceLayer* layer)
28 : client_(client),
29 layer_(layer),
30 needs_display_(false),
31 has_pending_frame_(false),
32 did_not_draw_counter_(0),
33 is_pumping_frames_(false),
34 timer_(
35 FROM_HERE,
36 base::TimeDelta::FromSeconds(1) / 6,
37 this,
38 &CompositingIOSurfaceLayerHelper::TimerFired) {}
39
40 CompositingIOSurfaceLayerHelper::~CompositingIOSurfaceLayerHelper() {
41 // Any acks that were waiting on this layer to draw will not occur, so ack
42 // them now to prevent blocking the renderer.
43 AckPendingFrame(true);
44 }
45
46 void CompositingIOSurfaceLayerHelper::GotNewFrame() {
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 has_pending_frame_ = true;
52 needs_display_ = true;
53 timer_.Reset();
54
55 // If reqested, draw immediately and don't bother trying to use the
56 // isAsynchronous property to ensure smooth animation. If this is while
57 // frames are being pumped then ack and display immediately to get a
58 // correct-sized frame displayed as soon as possible.
59 if (is_pumping_frames_ || client_->AcceleratedLayerShouldAckImmediately()) {
60 SetNeedsDisplayAndDisplayAndAck();
61 } else {
62 if (![layer_ isAsynchronous])
63 [layer_ setAsynchronous:YES];
64 }
65 }
66
67 void CompositingIOSurfaceLayerHelper::SetNeedsDisplay() {
68 needs_display_ = true;
69 }
70
71 bool CompositingIOSurfaceLayerHelper::CanDraw() {
72 // If we return NO 30 times in a row, switch to being synchronous to avoid
73 // burning CPU cycles on this callback.
74 if (needs_display_) {
75 did_not_draw_counter_ = 0;
76 } else {
77 did_not_draw_counter_ += 1;
78 if (did_not_draw_counter_ == 30)
79 [layer_ setAsynchronous:NO];
80 }
81
82 // Add an instantaneous blip to the PendingSwapAck state to indicate
83 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually
84 // from 2, indicating that a swap ack is pending) indicates that we
85 // requested a draw. A blip up to 1 (usually from 0, indicating there is no
86 // pending swap ack) indicates that we did not request a draw. This would
87 // be more natural to do with a tracing pseudo-thread
88 // http://crbug.com/366300
89 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display_ ? 3 : 1);
90 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this,
91 has_pending_frame_ ? 2 : 0);
92
93 return needs_display_;
94 }
95
96 void CompositingIOSurfaceLayerHelper::DidDraw(bool success) {
97 needs_display_ = false;
98 AckPendingFrame(success);
99 }
100
101 void CompositingIOSurfaceLayerHelper::AckPendingFrame(bool success) {
102 if (!has_pending_frame_)
103 return;
104 has_pending_frame_ = false;
105 if (success)
106 client_->AcceleratedLayerDidDrawFrame();
107 else
108 client_->AcceleratedLayerHitError();
109 // A trace value of 0 indicates that there is no longer a pending swap ack.
110 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
111 }
112
113 void CompositingIOSurfaceLayerHelper::SetNeedsDisplayAndDisplayAndAck() {
114 // Drawing using setNeedsDisplay and displayIfNeeded will result in
115 // subsequent canDrawInCGLContext callbacks getting dropped, and jerky
116 // animation. Disable asynchronous drawing before issuing these calls as a
117 // workaround.
118 // http://crbug.com/395827
119 if ([layer_ isAsynchronous])
120 [layer_ setAsynchronous:NO];
121
122 [layer_ setNeedsDisplay];
123 DisplayIfNeededAndAck();
124 }
125
126 void CompositingIOSurfaceLayerHelper::DisplayIfNeededAndAck() {
127 if (!needs_display_)
128 return;
129
130 // As in SetNeedsDisplayAndDisplayAndAck, disable asynchronous drawing before
131 // issuing displayIfNeeded.
132 // http://crbug.com/395827
133 if ([layer_ isAsynchronous])
134 [layer_ setAsynchronous:NO];
135
136 // Do not bother drawing while pumping new frames -- wait until the waiting
137 // block ends to draw any of the new frames.
138 if (!is_pumping_frames_)
139 [layer_ displayIfNeeded];
140
141 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
142 // rapidly (e.g, with vsync off). This is unacceptable because the failure
143 // to ack a single frame will hang the renderer. Ensure that the renderer
144 // not be blocked by lying and claiming that we drew the frame.
145 AckPendingFrame(true);
146 }
147
148 void CompositingIOSurfaceLayerHelper::TimerFired() {
149 SetNeedsDisplayAndDisplayAndAck();
150 }
151
152 void CompositingIOSurfaceLayerHelper::BeginPumpingFrames() {
153 is_pumping_frames_ = true;
154 }
155
156 void CompositingIOSurfaceLayerHelper::EndPumpingFrames() {
157 is_pumping_frames_ = false;
158 DisplayIfNeededAndAck();
159 }
160
161 } // namespace content
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // CompositingIOSurfaceLayer
165
166 @implementation CompositingIOSurfaceLayer
167
168 - (content::CompositingIOSurfaceMac*)iosurface {
169 return iosurface_.get();
170 }
171
172 - (content::CompositingIOSurfaceContext*)context {
173 return context_.get();
174 }
175
176 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>)
177 iosurface
178 withScaleFactor:(float)scale_factor
179 withClient:(content::CompositingIOSurfaceLayerClient*)client {
180 DCHECK(iosurface);
181 if (self = [super init]) {
182 helper_.reset(new content::CompositingIOSurfaceLayerHelper(client, self));
183
184 iosurface_ = iosurface;
185 context_ = content::CompositingIOSurfaceContext::Get(
186 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber);
187 if (!context_) {
188 LOG(ERROR) << "Failed create CompositingIOSurfaceContext";
189 [self resetClient];
190 [self release];
191 return nil;
192 }
193
194 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
195 [self setAnchorPoint:CGPointMake(0, 0)];
196 // Setting contents gravity is necessary to prevent the layer from being
197 // scaled during dyanmic resizes (especially with devtools open).
198 [self setContentsGravity:kCAGravityTopLeft];
199 if ([self respondsToSelector:(@selector(setContentsScale:))]) {
200 [self setContentsScale:scale_factor];
201 }
202 }
203 return self;
204 }
205
206 - (void)dealloc {
207 DCHECK(!helper_);
208 [super dealloc];
209 }
210
211 - (void)resetClient {
212 helper_.reset();
213 }
214
215 - (void)gotNewFrame {
216 helper_->GotNewFrame();
217 }
218
219 - (void)setNeedsDisplayAndDisplayAndAck {
220 helper_->SetNeedsDisplayAndDisplayAndAck();
221 }
222
223 - (void)displayIfNeededAndAck {
224 helper_->DisplayIfNeededAndAck();
225 }
226
227 - (void)beginPumpingFrames {
228 helper_->BeginPumpingFrames();
229 }
230
231 - (void)endPumpingFrames {
232 helper_->EndPumpingFrames();
233 }
234
235 // The remaining methods implement the CAOpenGLLayer interface.
236
237 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
238 if (!context_)
239 return [super copyCGLPixelFormatForDisplayMask:mask];
240 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
241 }
242
243 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
244 if (!context_)
245 return [super copyCGLContextForPixelFormat:pixelFormat];
246 return CGLRetainContext(context_->cgl_context());
247 }
248
249 - (void)setNeedsDisplay {
250 if (helper_)
251 helper_->SetNeedsDisplay();
252 [super setNeedsDisplay];
253 }
254
255 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
256 pixelFormat:(CGLPixelFormatObj)pixelFormat
257 forLayerTime:(CFTimeInterval)timeInterval
258 displayTime:(const CVTimeStamp*)timeStamp {
259 if (helper_)
260 return helper_->CanDraw();
261 return NO;
262 }
263
264 - (void)drawInCGLContext:(CGLContextObj)glContext
265 pixelFormat:(CGLPixelFormatObj)pixelFormat
266 forLayerTime:(CFTimeInterval)timeInterval
267 displayTime:(const CVTimeStamp*)timeStamp {
268 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext");
269
270 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) {
271 glClearColor(1, 1, 1, 1);
272 glClear(GL_COLOR_BUFFER_BIT);
273 return;
274 }
275
276 // The correct viewport to cover the layer will be set up by the caller.
277 // Transform this into a window size for DrawIOSurface, where it will be
278 // transformed back into this viewport.
279 GLint viewport[4];
280 glGetIntegerv(GL_VIEWPORT, viewport);
281 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
282 float window_scale_factor = 1.f;
283 if ([self respondsToSelector:(@selector(contentsScale))])
284 window_scale_factor = [self contentsScale];
285 window_rect = ToNearestRect(
286 gfx::ScaleRect(window_rect, 1.f/window_scale_factor));
287
288 bool draw_succeeded = iosurface_->DrawIOSurface(
289 context_, window_rect, window_scale_factor);
290
291 if (helper_)
292 helper_->DidDraw(draw_succeeded);
293
294 [super drawInCGLContext:glContext
295 pixelFormat:pixelFormat
296 forLayerTime:timeInterval
297 displayTime:timeStamp];
298 }
299
300 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698