OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |