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

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: Rebase 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
« no previous file with comments | « content/browser/renderer_host/compositing_iosurface_layer_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 needs_display_(false),
34 void TimerFired() { 31 has_pending_frame_(false),
35 [layer_ timerFired]; 32 did_not_draw_counter_(0),
33 timer_(
34 FROM_HERE,
35 base::TimeDelta::FromSeconds(1) / 6,
36 this,
37 &CompositingIOSurfaceLayerHelper::TimerFired) {}
38
39 CompositingIOSurfaceLayerHelper::~CompositingIOSurfaceLayerHelper() {
40 // Any acks that were waiting on this layer to draw will not occur, so ack
41 // them now to prevent blocking the renderer.
42 AckPendingFrame(true);
43 }
44
45 void CompositingIOSurfaceLayerHelper::GotNewFrame() {
46 has_pending_frame_ = true;
47 needs_display_ = true;
48 timer_.Reset();
49
50 if ([layer_ context] && [layer_ context]->is_vsync_disabled()) {
51 // If vsync is disabled, draw immediately and don't bother trying to use
52 // the isAsynchronous property to ensure smooth animation.
53 ImmediatelyForceDisplayAndAck();
54 } else {
55 needs_display_ = YES;
56 if (![layer_ isAsynchronous])
57 [layer_ setAsynchronous:YES];
36 } 58 }
37 private: 59
38 CompositingIOSurfaceLayer* layer_; 60 // A trace value of 2 indicates that there is a pending swap ack. See
39 }; 61 // canDrawInCGLContext for other value meanings.
62 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2);
63 }
64
65 void CompositingIOSurfaceLayerHelper::SetNeedsDisplay() {
66 needs_display_ = true;
67 }
68
69 bool CompositingIOSurfaceLayerHelper::CanDraw() {
70 // If we return NO 30 times in a row, switch to being synchronous to avoid
71 // burning CPU cycles on this callback.
72 if (needs_display_) {
73 did_not_draw_counter_ = 0;
74 } else {
75 did_not_draw_counter_ += 1;
76 if (did_not_draw_counter_ == 30)
77 [layer_ setAsynchronous:NO];
78 }
79
80 // Add an instantaneous blip to the PendingSwapAck state to indicate
81 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually
82 // from 2, indicating that a swap ack is pending) indicates that we
83 // requested a draw. A blip up to 1 (usually from 0, indicating there is no
84 // pending swap ack) indicates that we did not request a draw. This would
85 // be more natural to do with a tracing pseudo-thread
86 // http://crbug.com/366300
87 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display_ ? 3 : 1);
88 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this,
89 has_pending_frame_ ? 2 : 0);
90
91 return needs_display_;
92 }
93
94 void CompositingIOSurfaceLayerHelper::DidDraw(bool success) {
95 needs_display_ = false;
96 AckPendingFrame(success);
97 }
98
99 void CompositingIOSurfaceLayerHelper::AckPendingFrame(bool success) {
100 if (!has_pending_frame_)
101 return;
102 has_pending_frame_ = false;
103 client_->AcceleratedLayerDidDrawFrame(success);
104 // A trace value of 0 indicates that there is no longer a pending swap ack.
105 TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
106 }
107
108 void CompositingIOSurfaceLayerHelper::ImmediatelyForceDisplayAndAck() {
109 [layer_ setNeedsDisplay];
110 [layer_ displayIfNeeded];
111
112 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
113 // rapidly (e.g, with vsync off). This is unacceptable because the failure
114 // to ack a single frame will hang the renderer. Ensure that the renderer
115 // not be blocked by lying and claiming that we drew the frame.
116 AckPendingFrame(true);
117 }
118
119 void CompositingIOSurfaceLayerHelper::TimerFired() {
120 ImmediatelyForceDisplayAndAck();
121 }
40 122
41 } // namespace content 123 } // namespace content
42 124
125 ////////////////////////////////////////////////////////////////////////////////
126 // CompositingIOSurfaceLayer
127
43 @implementation CompositingIOSurfaceLayer 128 @implementation CompositingIOSurfaceLayer
44 129
45 - (content::CompositingIOSurfaceMac*)iosurface { 130 - (content::CompositingIOSurfaceMac*)iosurface {
46 return iosurface_.get(); 131 return iosurface_.get();
47 } 132 }
48 133
49 - (content::CompositingIOSurfaceContext*)context { 134 - (content::CompositingIOSurfaceContext*)context {
50 return context_.get(); 135 return context_.get();
51 } 136 }
52 137
53 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>) 138 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>)
54 iosurface 139 iosurface
55 withScaleFactor:(float)scale_factor 140 withScaleFactor:(float)scale_factor
56 withClient:(content::CompositingIOSurfaceLayerClient*)client { 141 withClient:(content::CompositingIOSurfaceLayerClient*)client {
57 if (self = [super init]) { 142 if (self = [super init]) {
143 helper_.reset(new content::CompositingIOSurfaceLayerHelper(client, self));
144
58 iosurface_ = iosurface; 145 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( 146 context_ = content::CompositingIOSurfaceContext::Get(
68 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber); 147 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber);
69 DCHECK(context_); 148 DCHECK(context_);
70 needs_display_ = NO;
71 has_pending_frame_ = NO;
72 did_not_draw_counter_ = 0;
73 149
74 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; 150 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
75 [self setAnchorPoint:CGPointMake(0, 0)]; 151 [self setAnchorPoint:CGPointMake(0, 0)];
76 // Setting contents gravity is necessary to prevent the layer from being 152 // Setting contents gravity is necessary to prevent the layer from being
77 // scaled during dyanmic resizes (especially with devtools open). 153 // scaled during dyanmic resizes (especially with devtools open).
78 [self setContentsGravity:kCAGravityTopLeft]; 154 [self setContentsGravity:kCAGravityTopLeft];
79 if ([self respondsToSelector:(@selector(setContentsScale:))]) { 155 if ([self respondsToSelector:(@selector(setContentsScale:))]) {
80 [self setContentsScale:scale_factor]; 156 [self setContentsScale:scale_factor];
81 } 157 }
82 } 158 }
83 return self; 159 return self;
84 } 160 }
85 161
162 - (void)dealloc {
163 DCHECK(!helper_);
164 [super dealloc];
165 }
166
86 - (void)resetClient { 167 - (void)resetClient {
87 // Any acks that were waiting on this layer to draw will not occur, so ack 168 helper_.reset();
88 // them now to prevent blocking the renderer.
89 [self ackPendingFrame:true];
90 client_ = NULL;
91 } 169 }
92 170
93 - (void)gotNewFrame { 171 - (void)gotNewFrame {
94 has_pending_frame_ = YES; 172 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
101 if (context_ && context_->is_vsync_disabled()) {
102 // If vsync is disabled, draw immediately and don't bother trying to use
103 // the isAsynchronous property to ensure smooth animation.
104 [self immediatelyForceDisplayAndAck];
105 } else {
106 needs_display_ = YES;
107 if (![self isAsynchronous])
108 [self setAsynchronous:YES];
109 }
110 }
111
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 } 173 }
139 174
140 // The remaining methods implement the CAOpenGLLayer interface. 175 // The remaining methods implement the CAOpenGLLayer interface.
141 176
142 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { 177 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
143 if (!context_) 178 if (!context_)
144 return [super copyCGLPixelFormatForDisplayMask:mask]; 179 return [super copyCGLPixelFormatForDisplayMask:mask];
145 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); 180 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
146 } 181 }
147 182
148 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { 183 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
149 if (!context_) 184 if (!context_)
150 return [super copyCGLContextForPixelFormat:pixelFormat]; 185 return [super copyCGLContextForPixelFormat:pixelFormat];
151 return CGLRetainContext(context_->cgl_context()); 186 return CGLRetainContext(context_->cgl_context());
152 } 187 }
153 188
154 - (void)setNeedsDisplay { 189 - (void)setNeedsDisplay {
155 needs_display_ = YES; 190 if (helper_)
191 helper_->SetNeedsDisplay();
156 [super setNeedsDisplay]; 192 [super setNeedsDisplay];
157 } 193 }
158 194
159 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext 195 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
160 pixelFormat:(CGLPixelFormatObj)pixelFormat 196 pixelFormat:(CGLPixelFormatObj)pixelFormat
161 forLayerTime:(CFTimeInterval)timeInterval 197 forLayerTime:(CFTimeInterval)timeInterval
162 displayTime:(const CVTimeStamp*)timeStamp { 198 displayTime:(const CVTimeStamp*)timeStamp {
163 // Add an instantaneous blip to the PendingSwapAck state to indicate 199 if (helper_)
164 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually 200 return helper_->CanDraw();
165 // from 2, indicating that a swap ack is pending) indicates that we requested 201 return NO;
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_;
185 } 202 }
186 203
187 - (void)drawInCGLContext:(CGLContextObj)glContext 204 - (void)drawInCGLContext:(CGLContextObj)glContext
188 pixelFormat:(CGLPixelFormatObj)pixelFormat 205 pixelFormat:(CGLPixelFormatObj)pixelFormat
189 forLayerTime:(CFTimeInterval)timeInterval 206 forLayerTime:(CFTimeInterval)timeInterval
190 displayTime:(const CVTimeStamp*)timeStamp { 207 displayTime:(const CVTimeStamp*)timeStamp {
191 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext"); 208 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext");
192 209
193 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) { 210 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) {
194 glClearColor(1, 1, 1, 1); 211 glClearColor(1, 1, 1, 1);
195 glClear(GL_COLOR_BUFFER_BIT); 212 glClear(GL_COLOR_BUFFER_BIT);
196 return; 213 return;
197 } 214 }
198 215
199 // The correct viewport to cover the layer will be set up by the caller. 216 // The correct viewport to cover the layer will be set up by the caller.
200 // Transform this into a window size for DrawIOSurface, where it will be 217 // Transform this into a window size for DrawIOSurface, where it will be
201 // transformed back into this viewport. 218 // transformed back into this viewport.
202 GLint viewport[4]; 219 GLint viewport[4];
203 glGetIntegerv(GL_VIEWPORT, viewport); 220 glGetIntegerv(GL_VIEWPORT, viewport);
204 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]); 221 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
205 float window_scale_factor = 1.f; 222 float window_scale_factor = 1.f;
206 if ([self respondsToSelector:(@selector(contentsScale))]) 223 if ([self respondsToSelector:(@selector(contentsScale))])
207 window_scale_factor = [self contentsScale]; 224 window_scale_factor = [self contentsScale];
208 window_rect = ToNearestRect( 225 window_rect = ToNearestRect(
209 gfx::ScaleRect(window_rect, 1.f/window_scale_factor)); 226 gfx::ScaleRect(window_rect, 1.f/window_scale_factor));
210 227
211 bool draw_succeeded = iosurface_->DrawIOSurface( 228 bool draw_succeeded = iosurface_->DrawIOSurface(
212 context_, window_rect, window_scale_factor); 229 context_, window_rect, window_scale_factor);
213 230
214 [self ackPendingFrame:draw_succeeded]; 231 if (helper_)
215 needs_display_ = NO; 232 helper_->DidDraw(draw_succeeded);
216 233
217 [super drawInCGLContext:glContext 234 [super drawInCGLContext:glContext
218 pixelFormat:pixelFormat 235 pixelFormat:pixelFormat
219 forLayerTime:timeInterval 236 forLayerTime:timeInterval
220 displayTime:timeStamp]; 237 displayTime:timeStamp];
221 } 238 }
222 239
223 @end 240 @end
OLDNEW
« no previous file with comments | « content/browser/renderer_host/compositing_iosurface_layer_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698