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

Side by Side Diff: chrome/browser/renderer_host/accelerated_plugin_view_mac.mm

Issue 6993043: Fix the mac hangup when force-compositing-mode is enabled (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 9 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #import "chrome/browser/renderer_host/accelerated_plugin_view_mac.h" 5 #import "chrome/browser/renderer_host/accelerated_plugin_view_mac.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #import "base/mac/scoped_nsautorelease_pool.h" 9 #import "base/mac/scoped_nsautorelease_pool.h"
10 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" 10 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
11 #include "chrome/common/chrome_switches.h" 11 #include "chrome/common/chrome_switches.h"
12 #include "ui/gfx/gl/gl_switches.h" 12 #include "ui/gfx/gl/gl_switches.h"
13 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 13 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
14 14
15 @implementation AcceleratedPluginView 15 @implementation AcceleratedPluginView
16 @synthesize cachedSize = cachedSize_; 16 @synthesize cachedSize = cachedSize_;
17 17
18 - (void)drawView {
19 TRACE_EVENT1("browser", "AcceleratedPluginViewMac::drawView",
20 "frameNum", swapBuffersCount_);
21
22 if (renderWidgetHostView_) {
23 // TODO(thakis): Pixel or view coordinates for size?
24 renderWidgetHostView_->DrawAcceleratedSurfaceInstance(
25 cglContext_, pluginHandle_, [self cachedSize]);
26 }
27
28 CGLFlushDrawable(cglContext_);
29 CGLSetCurrentContext(0);
30 }
31
32 // Note: cglContext_ lock must be held during this call.
Ken Russell (switch to Gerrit) 2011/06/13 21:45:12 This comment applies to drawView too.
33 - (void)ackSwapBuffers:(uint64)swapBuffersCount {
34 if (swapBuffersCount > acknowledgedSwapBuffersCount_) {
35 acknowledgedSwapBuffersCount_ = swapBuffersCount;
36 bool sendAck = (rendererId_ != 0 || routeId_ != 0);
37 if (sendAck && renderWidgetHostView_) {
38 renderWidgetHostView_->AcknowledgeSwapBuffers(
39 rendererId_,
40 routeId_,
41 gpuHostId_,
42 acknowledgedSwapBuffersCount_);
43 }
44 }
45 }
46
18 - (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime { 47 - (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime {
48 TRACE_EVENT0("browser", "AcceleratedPluginView::getFrameForTime");
19 // There is no autorelease pool when this method is called because it will be 49 // There is no autorelease pool when this method is called because it will be
20 // called from a background thread. 50 // called from a background thread.
21 base::mac::ScopedNSAutoreleasePool pool; 51 base::mac::ScopedNSAutoreleasePool pool;
22 52
23 bool sendAck = (rendererId_ != 0 || routeId_ != 0);
24 uint64 currentSwapBuffersCount = swapBuffersCount_; 53 uint64 currentSwapBuffersCount = swapBuffersCount_;
25 if (currentSwapBuffersCount == acknowledgedSwapBuffersCount_) { 54 if (currentSwapBuffersCount == acknowledgedSwapBuffersCount_) {
26 return kCVReturnSuccess; 55 return kCVReturnSuccess;
27 } 56 }
28 57
58 // Called on a background thread. Synchronized via the CGL context lock.
59 CGLLockContext(cglContext_);
60
29 [self drawView]; 61 [self drawView];
62 [self ackSwapBuffers:currentSwapBuffersCount];
30 63
31 acknowledgedSwapBuffersCount_ = currentSwapBuffersCount; 64 CGLUnlockContext(cglContext_);
32 if (sendAck && renderWidgetHostView_) {
33 renderWidgetHostView_->AcknowledgeSwapBuffers(
34 rendererId_,
35 routeId_,
36 gpuHostId_,
37 acknowledgedSwapBuffersCount_);
38 }
39 65
40 return kCVReturnSuccess; 66 return kCVReturnSuccess;
41 } 67 }
42 68
43 // This is the renderer output callback function 69 // This is the renderer output callback function
44 static CVReturn DrawOneAcceleratedPluginCallback( 70 static CVReturn DrawOneAcceleratedPluginCallback(
45 CVDisplayLinkRef displayLink, 71 CVDisplayLinkRef displayLink,
46 const CVTimeStamp* now, 72 const CVTimeStamp* now,
47 const CVTimeStamp* outputTime, 73 const CVTimeStamp* outputTime,
48 CVOptionFlags flagsIn, 74 CVOptionFlags flagsIn,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // Draw at beam vsync. 112 // Draw at beam vsync.
87 GLint swapInterval; 113 GLint swapInterval;
88 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) 114 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
89 swapInterval = 0; 115 swapInterval = 0;
90 else 116 else
91 swapInterval = 1; 117 swapInterval = 1;
92 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 118 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
93 119
94 // Set up a display link to do OpenGL rendering on a background thread. 120 // Set up a display link to do OpenGL rendering on a background thread.
95 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_); 121 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_);
122 CVDisplayLinkSetOutputCallback(
123 displayLink_, &DrawOneAcceleratedPluginCallback, self);
124 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
125 displayLink_, cglContext_, cglPixelFormat_);
126
127 [[NSNotificationCenter defaultCenter]
128 addObserver:self
129 selector:@selector(globalFrameDidChange:)
130 name:NSViewGlobalFrameDidChangeNotification
131 object:self];
96 } 132 }
97 return self; 133 return self;
98 } 134 }
99 135
100 - (void)dealloc { 136 - (void)dealloc {
101 CVDisplayLinkRelease(displayLink_); 137 CVDisplayLinkRelease(displayLink_);
138
139 // Ack pending swaps (if any):
140 CGLLockContext(cglContext_);
141 [self ackSwapBuffers:swapBuffersCount_];
142 CGLUnlockContext(cglContext_);
143
102 if (renderWidgetHostView_) 144 if (renderWidgetHostView_)
103 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); 145 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_);
104 [[NSNotificationCenter defaultCenter] removeObserver:self]; 146 [[NSNotificationCenter defaultCenter] removeObserver:self];
105 [super dealloc]; 147 [super dealloc];
106 } 148 }
107 149
108 - (void)drawView {
109 TRACE_EVENT1("browser", "AcceleratedPluginViewMac::drawView",
110 "frameNum", swapBuffersCount_);
111 // Called on a background thread. Synchronized via the CGL context lock.
112 CGLLockContext(cglContext_);
113
114 if (renderWidgetHostView_) {
115 // TODO(thakis): Pixel or view coordinates for size?
116 renderWidgetHostView_->DrawAcceleratedSurfaceInstance(
117 cglContext_, pluginHandle_, [self cachedSize]);
118 }
119
120 CGLFlushDrawable(cglContext_);
121 CGLSetCurrentContext(0);
122 CGLUnlockContext(cglContext_);
123 }
124
125 - (void)setCutoutRects:(NSArray*)cutout_rects { 150 - (void)setCutoutRects:(NSArray*)cutout_rects {
126 cutoutRects_.reset([cutout_rects copy]); 151 cutoutRects_.reset([cutout_rects copy]);
127 } 152 }
128 153
129 - (void)updateSwapBuffersCount:(uint64)count 154 - (void)updateSwapBuffersCount:(uint64)count
130 fromRenderer:(int)rendererId 155 fromRenderer:(int)rendererId
131 routeId:(int32)routeId 156 routeId:(int32)routeId
132 gpuHostId:(int)gpuHostId { 157 gpuHostId:(int)gpuHostId {
133 if (rendererId == 0 && routeId == 0) { 158 if (rendererId == 0 && routeId == 0) {
134 // This notification is coming from a plugin process, for which we 159 // This notification is coming from a plugin process, for which we
135 // don't have flow control implemented right now. Fake up a swap 160 // don't have flow control implemented right now. Fake up a swap
136 // buffers count so that we can at least skip useless renders. 161 // buffers count so that we can at least skip useless renders.
137 ++swapBuffersCount_; 162 ++swapBuffersCount_;
138 } else { 163 } else {
139 rendererId_ = rendererId; 164 rendererId_ = rendererId;
140 routeId_ = routeId; 165 routeId_ = routeId;
141 gpuHostId_ = gpuHostId; 166 gpuHostId_ = gpuHostId;
142 swapBuffersCount_ = count; 167 swapBuffersCount_ = count;
143 } 168 }
169 // If this view is not visible, we have to ack now. Otherwise,
170 // the ack will not be sent until the tab is made visible, which means it will
171 // look like the tab is loading (busy cursor) until it is clicked.
172 if (![self window]) {
173 // Ack pending swaps (if any):
174 CGLLockContext(cglContext_);
175 [self ackSwapBuffers:swapBuffersCount_];
176 CGLUnlockContext(cglContext_);
177 }
144 } 178 }
145 179
146 - (void)onRenderWidgetHostViewGone { 180 - (void)onRenderWidgetHostViewGone {
147 if (!renderWidgetHostView_) 181 if (!renderWidgetHostView_)
148 return; 182 return;
149 183
150 CGLLockContext(cglContext_); 184 CGLLockContext(cglContext_);
185 // Ack pending swaps (if any):
186 [self ackSwapBuffers:swapBuffersCount_];
151 // Deallocate the plugin handle while we still can. 187 // Deallocate the plugin handle while we still can.
152 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); 188 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_);
153 renderWidgetHostView_ = NULL; 189 renderWidgetHostView_ = NULL;
154 CGLUnlockContext(cglContext_); 190 CGLUnlockContext(cglContext_);
155 } 191 }
156 192
157 - (void)drawRect:(NSRect)rect { 193 - (void)drawRect:(NSRect)rect {
194 TRACE_EVENT0("browser", "AcceleratedPluginView::drawRect");
158 const NSRect* dirtyRects; 195 const NSRect* dirtyRects;
159 int dirtyRectCount; 196 int dirtyRectCount;
160 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; 197 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
161 198
162 { 199 {
163 gfx::ScopedNSGraphicsContextSaveGState scopedGState; 200 gfx::ScopedNSGraphicsContextSaveGState scopedGState;
164 201
165 // Mask out any cutout rects--somewhat counterintuitively cutout rects are 202 // Mask out any cutout rects--somewhat counterintuitively cutout rects are
166 // places where clearColor is *not* drawn. The trick is that drawing nothing 203 // places where clearColor is *not* drawn. The trick is that drawing nothing
167 // lets the parent view (i.e., the web page) show through, whereas drawing 204 // lets the parent view (i.e., the web page) show through, whereas drawing
(...skipping 15 matching lines...) Expand all
183 } 220 }
184 221
185 [path addClip]; 222 [path addClip];
186 } 223 }
187 224
188 // Punch a hole so that the OpenGL view shows through. 225 // Punch a hole so that the OpenGL view shows through.
189 [[NSColor clearColor] set]; 226 [[NSColor clearColor] set];
190 NSRectFillList(dirtyRects, dirtyRectCount); 227 NSRectFillList(dirtyRects, dirtyRectCount);
191 } 228 }
192 229
230 CGLLockContext(cglContext_);
193 [self drawView]; 231 [self drawView];
232 CGLUnlockContext(cglContext_);
194 } 233 }
195 234
196 - (void)rightMouseDown:(NSEvent*)event { 235 - (void)rightMouseDown:(NSEvent*)event {
197 // The NSResponder documentation: "Note: The NSView implementation of this 236 // The NSResponder documentation: "Note: The NSView implementation of this
198 // method does not pass the message up the responder chain, it handles it 237 // method does not pass the message up the responder chain, it handles it
199 // directly." 238 // directly."
200 // That's bad, we want the next responder (RWHVMac) to handle this event to 239 // That's bad, we want the next responder (RWHVMac) to handle this event to
201 // dispatch it to the renderer. 240 // dispatch it to the renderer.
202 [[self nextResponder] rightMouseDown:event]; 241 [[self nextResponder] rightMouseDown:event];
203 } 242 }
(...skipping 14 matching lines...) Expand all
218 CGLUnlockContext(cglContext_); 257 CGLUnlockContext(cglContext_);
219 globalFrameDidChangeCGLLockCount_--; 258 globalFrameDidChangeCGLLockCount_--;
220 259
221 if (globalFrameDidChangeCGLLockCount_ == 0) { 260 if (globalFrameDidChangeCGLLockCount_ == 0) {
222 // Make sure the view is synchronized with the correct display. 261 // Make sure the view is synchronized with the correct display.
223 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext( 262 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
224 displayLink_, cglContext_, cglPixelFormat_); 263 displayLink_, cglContext_, cglPixelFormat_);
225 } 264 }
226 } 265 }
227 266
267 - (void)prepareForGLRendering {
268 TRACE_EVENT0("browser", "AcceleratedPluginView::prepareForGLRendering");
269
270 // If we're using OpenGL, make sure it is connected.
271 if ([glContext_ view] != self) {
272 [glContext_ setView:self];
273 }
274 }
275
228 - (void)renewGState { 276 - (void)renewGState {
277 TRACE_EVENT0("browser", "AcceleratedPluginView::renewGState");
229 // Synchronize with window server to avoid flashes or corrupt drawing. 278 // Synchronize with window server to avoid flashes or corrupt drawing.
230 [[self window] disableScreenUpdatesUntilFlush]; 279 [[self window] disableScreenUpdatesUntilFlush];
231 [self globalFrameDidChange:nil]; 280 [self globalFrameDidChange:nil];
232 [super renewGState]; 281 [super renewGState];
233 } 282 }
234 283
284 - (void)setUpGState {
285 TRACE_EVENT0("browser", "AcceleratedPluginView::setUpGState");
286 [self prepareForGLRendering];
287 }
288
289 // TODO(jbates): is lockFocus needed anymore? it seems redundant with
290 // setUpGState in traces.
235 - (void)lockFocus { 291 - (void)lockFocus {
292 TRACE_EVENT0("browser", "AcceleratedPluginView::lockFocus");
236 [super lockFocus]; 293 [super lockFocus];
237 294 [self prepareForGLRendering];
238 // If we're using OpenGL, make sure it is connected and that the display link
239 // is running.
240 if ([glContext_ view] != self) {
241 [glContext_ setView:self];
242
243 [[NSNotificationCenter defaultCenter]
244 addObserver:self
245 selector:@selector(globalFrameDidChange:)
246 name:NSViewGlobalFrameDidChangeNotification
247 object:self];
248 CVDisplayLinkSetOutputCallback(
249 displayLink_, &DrawOneAcceleratedPluginCallback, self);
250 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
251 displayLink_, cglContext_, cglPixelFormat_);
252 CVDisplayLinkStart(displayLink_);
253 }
254 [glContext_ makeCurrentContext]; 295 [glContext_ makeCurrentContext];
255 } 296 }
256 297
257 - (void)viewWillMoveToWindow:(NSWindow*)newWindow { 298 - (void)viewWillMoveToWindow:(NSWindow*)newWindow {
299 TRACE_EVENT1("browser", "AcceleratedPluginView::viewWillMoveToWindow",
300 "newWindow", newWindow);
258 // Stop the display link thread while the view is not visible. 301 // Stop the display link thread while the view is not visible.
259 if (newWindow) { 302 if (newWindow) {
260 if (displayLink_ && !CVDisplayLinkIsRunning(displayLink_)) 303 if (!CVDisplayLinkIsRunning(displayLink_))
261 CVDisplayLinkStart(displayLink_); 304 CVDisplayLinkStart(displayLink_);
262 } else { 305 } else {
263 if (displayLink_ && CVDisplayLinkIsRunning(displayLink_)) 306 if (CVDisplayLinkIsRunning(displayLink_))
264 CVDisplayLinkStop(displayLink_); 307 CVDisplayLinkStop(displayLink_);
308
309 // Ack pending swaps (if any):
310 CGLLockContext(cglContext_);
311 [self ackSwapBuffers:swapBuffersCount_];
312 CGLUnlockContext(cglContext_);
265 } 313 }
266 314
267 // Inform the window hosting this accelerated view that it needs to be 315 // Inform the window hosting this accelerated view that it needs to be
268 // transparent. 316 // transparent.
269 if (![self isHiddenOrHasHiddenAncestor]) { 317 if (![self isHiddenOrHasHiddenAncestor]) {
270 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) 318 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)])
271 [static_cast<id>([self window]) underlaySurfaceRemoved]; 319 [static_cast<id>([self window]) underlaySurfaceRemoved];
272 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) 320 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)])
273 [static_cast<id>(newWindow) underlaySurfaceAdded]; 321 [static_cast<id>(newWindow) underlaySurfaceAdded];
274 } 322 }
275 } 323 }
276 324
277 - (void)viewDidHide { 325 - (void)viewDidHide {
326 TRACE_EVENT0("browser", "AcceleratedPluginView::viewDidHide");
278 [super viewDidHide]; 327 [super viewDidHide];
279 328
280 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { 329 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) {
281 [static_cast<id>([self window]) underlaySurfaceRemoved]; 330 [static_cast<id>([self window]) underlaySurfaceRemoved];
282 } 331 }
283 } 332 }
284 333
285 - (void)viewDidUnhide { 334 - (void)viewDidUnhide {
335 TRACE_EVENT0("browser", "AcceleratedPluginView::viewDidUnhide");
286 [super viewDidUnhide]; 336 [super viewDidUnhide];
287 337
288 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { 338 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) {
289 [static_cast<id>([self window]) underlaySurfaceAdded]; 339 [static_cast<id>([self window]) underlaySurfaceAdded];
290 } 340 }
291 } 341 }
292 342
293 - (void)setFrame:(NSRect)frameRect { 343 - (void)setFrame:(NSRect)frameRect {
294 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame"); 344 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame");
295 [self setCachedSize:frameRect.size]; 345 [self setCachedSize:frameRect.size];
296 [super setFrame:frameRect]; 346 [super setFrame:frameRect];
297 } 347 }
298 348
299 - (void)setFrameSize:(NSSize)newSize { 349 - (void)setFrameSize:(NSSize)newSize {
350 TRACE_EVENT0("browser", "AcceleratedPluginView::newSize");
300 [self setCachedSize:newSize]; 351 [self setCachedSize:newSize];
301 [super setFrameSize:newSize]; 352 [super setFrameSize:newSize];
302 } 353 }
303 354
304 - (BOOL)acceptsFirstResponder { 355 - (BOOL)acceptsFirstResponder {
305 // Accept first responder if the first responder isn't the RWHVMac, and if the 356 // Accept first responder if the first responder isn't the RWHVMac, and if the
306 // RWHVMac accepts first responder. If the RWHVMac does not accept first 357 // RWHVMac accepts first responder. If the RWHVMac does not accept first
307 // responder, do not accept on its behalf. 358 // responder, do not accept on its behalf.
308 return ([[self window] firstResponder] != [self superview] && 359 return ([[self window] firstResponder] != [self superview] &&
309 [[self superview] acceptsFirstResponder]); 360 [[self superview] acceptsFirstResponder]);
310 } 361 }
311 362
312 - (BOOL)becomeFirstResponder { 363 - (BOOL)becomeFirstResponder {
313 // Delegate first responder to the RWHVMac. 364 // Delegate first responder to the RWHVMac.
314 [[self window] makeFirstResponder:[self superview]]; 365 [[self window] makeFirstResponder:[self superview]];
315 return YES; 366 return YES;
316 } 367 }
317 368
318 - (void)viewDidMoveToSuperview { 369 - (void)viewDidMoveToSuperview {
370 TRACE_EVENT0("browser", "AcceleratedPluginView::viewDidMoveToSuperview");
319 if (![self superview]) 371 if (![self superview])
320 [self onRenderWidgetHostViewGone]; 372 [self onRenderWidgetHostViewGone];
321 } 373 }
322 @end 374 @end
323 375
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/accelerated_plugin_view_mac.h ('k') | content/common/gpu/gpu_channel.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698