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

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: split raf-stall fix 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"
10 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" 9 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
11 #include "chrome/common/chrome_switches.h" 10 #include "chrome/common/chrome_switches.h"
11 #include "content/browser/browser_thread.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_;
17
18 - (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime {
19 // There is no autorelease pool when this method is called because it will be
20 // called from a background thread.
21 base::mac::ScopedNSAutoreleasePool pool;
22
23 bool sendAck = (rendererId_ != 0 || routeId_ != 0);
24 uint64 currentSwapBuffersCount = swapBuffersCount_;
25 if (currentSwapBuffersCount == acknowledgedSwapBuffersCount_) {
26 return kCVReturnSuccess;
27 }
28
29 [self drawView];
30
31 acknowledgedSwapBuffersCount_ = currentSwapBuffersCount;
32 if (sendAck && renderWidgetHostView_) {
33 renderWidgetHostView_->AcknowledgeSwapBuffers(
34 rendererId_,
35 routeId_,
36 gpuHostId_,
37 acknowledgedSwapBuffersCount_);
38 }
39
40 return kCVReturnSuccess;
41 }
42
43 // This is the renderer output callback function
44 static CVReturn DrawOneAcceleratedPluginCallback(
45 CVDisplayLinkRef displayLink,
46 const CVTimeStamp* now,
47 const CVTimeStamp* outputTime,
48 CVOptionFlags flagsIn,
49 CVOptionFlags* flagsOut,
50 void* displayLinkContext) {
51 CVReturn result =
52 [(AcceleratedPluginView*)displayLinkContext getFrameForTime:outputTime];
53 return result;
54 }
55 16
56 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r 17 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r
57 pluginHandle:(gfx::PluginWindowHandle)pluginHandle { 18 pluginHandle:(gfx::PluginWindowHandle)pluginHandle {
19 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58 if ((self = [super initWithFrame:NSZeroRect])) { 20 if ((self = [super initWithFrame:NSZeroRect])) {
21 TRACE_EVENT0("browser",
22 "AcceleratedPluginView::initWithRenderWidgetHostViewMac");
59 renderWidgetHostView_ = r; 23 renderWidgetHostView_ = r;
60 pluginHandle_ = pluginHandle; 24 pluginHandle_ = pluginHandle;
61 cachedSize_ = NSZeroSize;
62 swapBuffersCount_ = 0;
63 acknowledgedSwapBuffersCount_ = 0;
64 rendererId_ = 0;
65 routeId_ = 0;
66 gpuHostId_ = 0;
67 25
68 [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin]; 26 [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin];
69 27
70 NSOpenGLPixelFormatAttribute attributes[] = 28 NSOpenGLPixelFormatAttribute attributes[] =
71 { NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, 0}; 29 { NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, 0};
72 30
73 glPixelFormat_.reset([[NSOpenGLPixelFormat alloc] 31 glPixelFormat_.reset([[NSOpenGLPixelFormat alloc]
74 initWithAttributes:attributes]); 32 initWithAttributes:attributes]);
75 glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_ 33 glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_
76 shareContext:nil]); 34 shareContext:nil]);
77 35
78 // We "punch a hole" in the window, and have the WindowServer render the 36 // We "punch a hole" in the window, and have the WindowServer render the
79 // OpenGL surface underneath so we can draw over it. 37 // OpenGL surface underneath so we can draw over it.
80 GLint belowWindow = -1; 38 GLint belowWindow = -1;
81 [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder]; 39 [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder];
82 40
83 cglContext_ = (CGLContextObj)[glContext_ CGLContextObj]; 41 cglContext_ = (CGLContextObj)[glContext_ CGLContextObj];
84 cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj]; 42 cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj];
85 43
86 // Draw at beam vsync. 44 // Draw at beam vsync.
87 GLint swapInterval; 45 GLint swapInterval;
88 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) 46 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
89 swapInterval = 0; 47 swapInterval = 0;
90 else 48 else
91 swapInterval = 1; 49 swapInterval = 1;
92 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 50 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
93
94 // Set up a display link to do OpenGL rendering on a background thread.
95 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_);
96 } 51 }
97 return self; 52 return self;
98 } 53 }
99 54
100 - (void)dealloc { 55 - (void)dealloc {
101 CVDisplayLinkRelease(displayLink_);
102 if (renderWidgetHostView_) 56 if (renderWidgetHostView_)
103 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); 57 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_);
104 [[NSNotificationCenter defaultCenter] removeObserver:self]; 58 [[NSNotificationCenter defaultCenter] removeObserver:self];
105 [super dealloc]; 59 [super dealloc];
106 } 60 }
107 61
108 - (void)drawView { 62 - (void)drawView {
109 TRACE_EVENT1("browser", "AcceleratedPluginViewMac::drawView", 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110 "frameNum", swapBuffersCount_); 64 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::drawView");
111 // Called on a background thread. Synchronized via the CGL context lock. 65 // Called on the UI thread.
112 CGLLockContext(cglContext_);
113
114 if (renderWidgetHostView_) { 66 if (renderWidgetHostView_) {
115 // TODO(thakis): Pixel or view coordinates for size? 67 // TODO(thakis): Pixel or view coordinates for size?
68 NSRect frame = [self frame];
Nico 2011/06/08 16:52:46 no need for a variable
jbates 2011/06/08 17:54:42 Done.
116 renderWidgetHostView_->DrawAcceleratedSurfaceInstance( 69 renderWidgetHostView_->DrawAcceleratedSurfaceInstance(
117 cglContext_, pluginHandle_, [self cachedSize]); 70 cglContext_, pluginHandle_, frame.size);
118 } 71 }
119 72
120 CGLFlushDrawable(cglContext_); 73 CGLFlushDrawable(cglContext_);
121 CGLSetCurrentContext(0); 74 CGLSetCurrentContext(0);
122 CGLUnlockContext(cglContext_);
123 } 75 }
124 76
125 - (void)setCutoutRects:(NSArray*)cutout_rects { 77 - (void)setCutoutRects:(NSArray*)cutout_rects {
126 cutoutRects_.reset([cutout_rects copy]); 78 cutoutRects_.reset([cutout_rects copy]);
127 } 79 }
128 80
129 - (void)updateSwapBuffersCount:(uint64)count
130 fromRenderer:(int)rendererId
131 routeId:(int32)routeId
132 gpuHostId:(int)gpuHostId {
133 if (rendererId == 0 && routeId == 0) {
134 // This notification is coming from a plugin process, for which we
135 // don't have flow control implemented right now. Fake up a swap
136 // buffers count so that we can at least skip useless renders.
137 ++swapBuffersCount_;
138 } else {
139 rendererId_ = rendererId;
140 routeId_ = routeId;
141 gpuHostId_ = gpuHostId;
142 swapBuffersCount_ = count;
143 }
144 }
145
146 - (void)onRenderWidgetHostViewGone { 81 - (void)onRenderWidgetHostViewGone {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 if (!renderWidgetHostView_) 83 if (!renderWidgetHostView_)
148 return; 84 return;
149 85
150 CGLLockContext(cglContext_);
151 // Deallocate the plugin handle while we still can. 86 // Deallocate the plugin handle while we still can.
152 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); 87 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_);
153 renderWidgetHostView_ = NULL; 88 renderWidgetHostView_ = NULL;
154 CGLUnlockContext(cglContext_);
155 } 89 }
156 90
157 - (void)drawRect:(NSRect)rect { 91 - (void)drawRect:(NSRect)rect {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158 const NSRect* dirtyRects; 93 const NSRect* dirtyRects;
159 int dirtyRectCount; 94 int dirtyRectCount;
160 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; 95 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
161 96
162 { 97 {
163 gfx::ScopedNSGraphicsContextSaveGState scopedGState; 98 gfx::ScopedNSGraphicsContextSaveGState scopedGState;
164 99
165 // Mask out any cutout rects--somewhat counterintuitively cutout rects are 100 // Mask out any cutout rects--somewhat counterintuitively cutout rects are
166 // places where clearColor is *not* drawn. The trick is that drawing nothing 101 // 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 102 // lets the parent view (i.e., the web page) show through, whereas drawing
(...skipping 28 matching lines...) Expand all
196 - (void)rightMouseDown:(NSEvent*)event { 131 - (void)rightMouseDown:(NSEvent*)event {
197 // The NSResponder documentation: "Note: The NSView implementation of this 132 // The NSResponder documentation: "Note: The NSView implementation of this
198 // method does not pass the message up the responder chain, it handles it 133 // method does not pass the message up the responder chain, it handles it
199 // directly." 134 // directly."
200 // That's bad, we want the next responder (RWHVMac) to handle this event to 135 // That's bad, we want the next responder (RWHVMac) to handle this event to
201 // dispatch it to the renderer. 136 // dispatch it to the renderer.
202 [[self nextResponder] rightMouseDown:event]; 137 [[self nextResponder] rightMouseDown:event];
203 } 138 }
204 139
205 - (void)globalFrameDidChange:(NSNotification*)notification { 140 - (void)globalFrameDidChange:(NSNotification*)notification {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206 globalFrameDidChangeCGLLockCount_++; 142 globalFrameDidChangeCGLLockCount_++;
207 CGLLockContext(cglContext_);
208 // This call to -update can call -globalFrameDidChange: again, see 143 // This call to -update can call -globalFrameDidChange: again, see
209 // http://crbug.com/55754 comments 22 and 24. 144 // http://crbug.com/55754 comments 22 and 24.
210 [glContext_ update]; 145 [glContext_ update];
211 146
212 // You would think that -update updates the viewport. You would be wrong. 147 // You would think that -update updates the viewport. You would be wrong.
213 CGLSetCurrentContext(cglContext_); 148 CGLSetCurrentContext(cglContext_);
214 NSSize size = [self frame].size; 149 NSSize size = [self frame].size;
215 glViewport(0, 0, size.width, size.height); 150 glViewport(0, 0, size.width, size.height);
216 151
217 CGLSetCurrentContext(0); 152 CGLSetCurrentContext(0);
218 CGLUnlockContext(cglContext_);
219 globalFrameDidChangeCGLLockCount_--; 153 globalFrameDidChangeCGLLockCount_--;
220
221 if (globalFrameDidChangeCGLLockCount_ == 0) {
222 // Make sure the view is synchronized with the correct display.
223 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
224 displayLink_, cglContext_, cglPixelFormat_);
225 }
226 } 154 }
227 155
228 - (void)renewGState { 156 - (void)renewGState {
229 // Synchronize with window server to avoid flashes or corrupt drawing. 157 // Synchronize with window server to avoid flashes or corrupt drawing.
230 [[self window] disableScreenUpdatesUntilFlush]; 158 [[self window] disableScreenUpdatesUntilFlush];
231 [self globalFrameDidChange:nil]; 159 [self globalFrameDidChange:nil];
232 [super renewGState]; 160 [super renewGState];
233 } 161 }
234 162
235 - (void)lockFocus { 163 - (void)lockFocus {
236 [super lockFocus]; 164 [super lockFocus];
237 165
238 // If we're using OpenGL, make sure it is connected and that the display link 166 // If we're using OpenGL, make sure it is connected.
239 // is running.
240 if ([glContext_ view] != self) { 167 if ([glContext_ view] != self) {
241 [glContext_ setView:self]; 168 [glContext_ setView:self];
242 169
243 [[NSNotificationCenter defaultCenter] 170 [[NSNotificationCenter defaultCenter]
244 addObserver:self 171 addObserver:self
245 selector:@selector(globalFrameDidChange:) 172 selector:@selector(globalFrameDidChange:)
246 name:NSViewGlobalFrameDidChangeNotification 173 name:NSViewGlobalFrameDidChangeNotification
247 object:self]; 174 object:self];
248 CVDisplayLinkSetOutputCallback(
249 displayLink_, &DrawOneAcceleratedPluginCallback, self);
250 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
251 displayLink_, cglContext_, cglPixelFormat_);
252 CVDisplayLinkStart(displayLink_);
253 } 175 }
254 [glContext_ makeCurrentContext]; 176 [glContext_ makeCurrentContext];
255 } 177 }
256 178
257 - (void)viewWillMoveToWindow:(NSWindow*)newWindow { 179 - (void)viewWillMoveToWindow:(NSWindow*)newWindow {
258 // Stop the display link thread while the view is not visible. 180 TRACE_EVENT0("renderer", "viewWillMoveToWindow");
259 if (newWindow) {
260 if (displayLink_ && !CVDisplayLinkIsRunning(displayLink_))
261 CVDisplayLinkStart(displayLink_);
262 } else {
263 if (displayLink_ && CVDisplayLinkIsRunning(displayLink_))
264 CVDisplayLinkStop(displayLink_);
265 }
266
267 // Inform the window hosting this accelerated view that it needs to be 181 // Inform the window hosting this accelerated view that it needs to be
268 // transparent. 182 // transparent.
269 if (![self isHiddenOrHasHiddenAncestor]) { 183 if (![self isHiddenOrHasHiddenAncestor]) {
270 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) 184 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)])
271 [static_cast<id>([self window]) underlaySurfaceRemoved]; 185 [static_cast<id>([self window]) underlaySurfaceRemoved];
272 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) 186 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)])
273 [static_cast<id>(newWindow) underlaySurfaceAdded]; 187 [static_cast<id>(newWindow) underlaySurfaceAdded];
274 } 188 }
275 } 189 }
276 190
277 - (void)viewDidHide { 191 - (void)viewDidHide {
278 [super viewDidHide]; 192 [super viewDidHide];
279 193
280 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { 194 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) {
281 [static_cast<id>([self window]) underlaySurfaceRemoved]; 195 [static_cast<id>([self window]) underlaySurfaceRemoved];
282 } 196 }
283 } 197 }
284 198
285 - (void)viewDidUnhide { 199 - (void)viewDidUnhide {
286 [super viewDidUnhide]; 200 [super viewDidUnhide];
287 201
288 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { 202 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) {
289 [static_cast<id>([self window]) underlaySurfaceAdded]; 203 [static_cast<id>([self window]) underlaySurfaceAdded];
290 } 204 }
291 } 205 }
292 206
293 - (void)setFrame:(NSRect)frameRect { 207 - (void)setFrame:(NSRect)frameRect {
294 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame"); 208 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame");
295 [self setCachedSize:frameRect.size];
296 [super setFrame:frameRect]; 209 [super setFrame:frameRect];
297 } 210 }
Nico 2011/06/08 16:52:46 If you don't need the trace output, remove this me
jbates 2011/06/08 17:54:42 Done.
298 211
299 - (void)setFrameSize:(NSSize)newSize { 212 - (void)setFrameSize:(NSSize)newSize {
300 [self setCachedSize:newSize];
301 [super setFrameSize:newSize]; 213 [super setFrameSize:newSize];
302 } 214 }
Nico 2011/06/08 16:52:46 Remove this method?
jbates 2011/06/08 17:54:42 Done.
303 215
304 - (BOOL)acceptsFirstResponder { 216 - (BOOL)acceptsFirstResponder {
305 // Accept first responder if the first responder isn't the RWHVMac, and if the 217 // 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 218 // RWHVMac accepts first responder. If the RWHVMac does not accept first
307 // responder, do not accept on its behalf. 219 // responder, do not accept on its behalf.
308 return ([[self window] firstResponder] != [self superview] && 220 return ([[self window] firstResponder] != [self superview] &&
309 [[self superview] acceptsFirstResponder]); 221 [[self superview] acceptsFirstResponder]);
310 } 222 }
311 223
312 - (BOOL)becomeFirstResponder { 224 - (BOOL)becomeFirstResponder {
313 // Delegate first responder to the RWHVMac. 225 // Delegate first responder to the RWHVMac.
314 [[self window] makeFirstResponder:[self superview]]; 226 [[self window] makeFirstResponder:[self superview]];
315 return YES; 227 return YES;
316 } 228 }
317 229
318 - (void)viewDidMoveToSuperview { 230 - (void)viewDidMoveToSuperview {
319 if (![self superview]) 231 if (![self superview])
320 [self onRenderWidgetHostViewGone]; 232 [self onRenderWidgetHostViewGone];
321 } 233 }
322 @end 234 @end
323 235
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698