OLD | NEW |
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/sdk_forward_declarations.h" | 10 #include "base/mac/sdk_forward_declarations.h" |
11 #include "content/browser/renderer_host/render_widget_host_impl.h" | 11 #include "content/browser/renderer_host/render_widget_host_impl.h" |
12 #include "content/browser/renderer_host/render_widget_host_view_mac.h" | 12 #include "content/browser/renderer_host/render_widget_host_view_mac.h" |
13 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" | 13 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" |
14 #include "content/browser/renderer_host/compositing_iosurface_mac.h" | 14 #include "content/browser/renderer_host/compositing_iosurface_mac.h" |
15 #include "ui/base/cocoa/animation_utils.h" | 15 #include "ui/base/cocoa/animation_utils.h" |
16 #include "ui/gfx/size_conversions.h" | 16 #include "ui/gfx/size_conversions.h" |
17 #include "ui/gl/gpu_switching_manager.h" | 17 #include "ui/gl/gpu_switching_manager.h" |
18 | 18 |
| 19 @interface CompositingIOSurfaceLayer() |
| 20 |
| 21 // Private method to wait for a frame of the right size if we're in an active |
| 22 // resize. This may potentially dispatch select messages from the run loop. |
| 23 - (void)waitForResizedFrameInContext:(CGLContextObj)glContext; |
| 24 |
| 25 @end |
| 26 |
19 @implementation CompositingIOSurfaceLayer | 27 @implementation CompositingIOSurfaceLayer |
20 | 28 |
21 @synthesize context = context_; | 29 @synthesize context = context_; |
22 | 30 |
23 - (id)initWithRenderWidgetHostViewMac:(content::RenderWidgetHostViewMac*)r { | 31 - (id)initWithRenderWidgetHostViewMac:(content::RenderWidgetHostViewMac*)r { |
24 if (self = [super init]) { | 32 if (self = [super init]) { |
25 renderWidgetHostView_ = r; | 33 renderWidgetHostView_ = r; |
26 context_ = content::CompositingIOSurfaceContext::Get( | 34 context_ = content::CompositingIOSurfaceContext::Get( |
27 content::CompositingIOSurfaceContext::kOffscreenContextWindowNumber); | 35 content::CompositingIOSurfaceContext::kOffscreenContextWindowNumber); |
28 DCHECK(context_); | 36 DCHECK(context_); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 | 84 |
77 - (void)timerSinceGotNewFrameFired { | 85 - (void)timerSinceGotNewFrameFired { |
78 if (![self isAsynchronous]) | 86 if (![self isAsynchronous]) |
79 return; | 87 return; |
80 | 88 |
81 [self setAsynchronous:NO]; | 89 [self setAsynchronous:NO]; |
82 if (needsDisplay_) | 90 if (needsDisplay_) |
83 [self setNeedsDisplay]; | 91 [self setNeedsDisplay]; |
84 } | 92 } |
85 | 93 |
| 94 - (void)waitForResizedFrameInContext:(CGLContextObj)glContext { |
| 95 // Cache a copy of renderWidgetHostView_ because it may be reset if |
| 96 // a software frame is received in GetBackingStore. |
| 97 content::RenderWidgetHostViewMac* cached_view = renderWidgetHostView_; |
| 98 if (!cached_view->render_widget_host_ || |
| 99 cached_view->render_widget_host_->is_hidden()) { |
| 100 return; |
| 101 } |
| 102 |
| 103 // Note that GetBackingStore can potentially spawn a nested run loop, which |
| 104 // may change the current GL context, or, because the GL contexts are |
| 105 // shared, may change the currently-bound FBO. Ensure that, when the run |
| 106 // loop returns, the original GL context remain current, and the original |
| 107 // FBO remain bound. |
| 108 // TODO(ccameron): This is far too fragile a mechanism to rely on. Find |
| 109 // a way to avoid doing this. |
| 110 GLuint previous_framebuffer = 0; |
| 111 glGetIntegerv(GL_FRAMEBUFFER_BINDING, |
| 112 reinterpret_cast<GLint*>(&previous_framebuffer)); |
| 113 { |
| 114 // If a resize is in progress then GetBackingStore request a frame of the |
| 115 // current window size and block until a frame of the right size comes in. |
| 116 // This makes the window content not lag behind the resize (at the cost of |
| 117 // blocking on the browser's main thread). |
| 118 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(NULL); |
| 119 cached_view->about_to_validate_and_paint_ = true; |
| 120 (void)cached_view->render_widget_host_->GetBackingStore(true); |
| 121 cached_view->about_to_validate_and_paint_ = false; |
| 122 } |
| 123 CHECK_EQ(CGLGetCurrentContext(), glContext) |
| 124 << "original GL context failed to re-bind after nested run loop, " |
| 125 << "browser crash is imminent."; |
| 126 glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer); |
| 127 } |
| 128 |
86 // The remaining methods implement the CAOpenGLLayer interface. | 129 // The remaining methods implement the CAOpenGLLayer interface. |
87 | 130 |
88 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { | 131 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { |
89 if (!context_) | 132 if (!context_) |
90 return [super copyCGLPixelFormatForDisplayMask:mask]; | 133 return [super copyCGLPixelFormatForDisplayMask:mask]; |
91 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); | 134 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); |
92 } | 135 } |
93 | 136 |
94 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { | 137 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { |
95 if (!context_) | 138 if (!context_) |
(...skipping 21 matching lines...) Expand all Loading... |
117 | 160 |
118 if (!context_ || | 161 if (!context_ || |
119 (context_ && context_->cgl_context() != glContext) || | 162 (context_ && context_->cgl_context() != glContext) || |
120 !renderWidgetHostView_ || | 163 !renderWidgetHostView_ || |
121 !renderWidgetHostView_->compositing_iosurface_) { | 164 !renderWidgetHostView_->compositing_iosurface_) { |
122 glClearColor(1, 1, 1, 1); | 165 glClearColor(1, 1, 1, 1); |
123 glClear(GL_COLOR_BUFFER_BIT); | 166 glClear(GL_COLOR_BUFFER_BIT); |
124 return; | 167 return; |
125 } | 168 } |
126 | 169 |
127 // Cache a copy of renderWidgetHostView_ because it may be reset if | 170 // Acknowledge the frame before we potentially wait for a frame of the right |
128 // a software frame is received in GetBackingStore. | 171 // size. |
129 content::RenderWidgetHostViewMac* cached_view = renderWidgetHostView_; | 172 renderWidgetHostView_->SendPendingSwapAck(); |
130 | 173 |
131 // If a resize is in progress then GetBackingStore request a frame of the | 174 // Wait for a frame of the right size to come in, if needed. |
132 // current window size and block until a frame of the right size comes in. | 175 [self waitForResizedFrameInContext:glContext]; |
133 // This makes the window content not lag behind the resize (at the cost of | |
134 // blocking on the browser's main thread). | |
135 if (cached_view->render_widget_host_) { | |
136 // Note that GetBackingStore can potentially spawn a nested run loop, which | |
137 // may change the current GL context, or, because the GL contexts are | |
138 // shared, may change the currently-bound FBO. Ensure that, when the run | |
139 // loop returns, the original GL context remain current, and the original | |
140 // FBO remain bound. | |
141 // TODO(ccameron): This is far too fragile a mechanism to rely on. Find | |
142 // a way to avoid doing this. | |
143 GLuint previous_framebuffer = 0; | |
144 glGetIntegerv(GL_FRAMEBUFFER_BINDING, | |
145 reinterpret_cast<GLint*>(&previous_framebuffer)); | |
146 { | |
147 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(NULL); | |
148 cached_view->about_to_validate_and_paint_ = true; | |
149 (void)cached_view->render_widget_host_->GetBackingStore(true); | |
150 cached_view->about_to_validate_and_paint_ = false; | |
151 } | |
152 CHECK_EQ(CGLGetCurrentContext(), glContext) | |
153 << "original GL context failed to re-bind after nested run loop, " | |
154 << "browser crash is imminent."; | |
155 glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer); | |
156 } | |
157 | 176 |
158 // If a transition to software mode has occurred, this layer should be | 177 // If a transition to software mode has occurred, this layer should be |
159 // removed from the heirarchy now, so don't draw anything. | 178 // removed from the heirarchy now, so don't draw anything. |
160 if (!renderWidgetHostView_) | 179 if (!renderWidgetHostView_) |
161 return; | 180 return; |
162 | 181 |
163 gfx::Rect window_rect([self frame]); | 182 gfx::Rect window_rect([self frame]); |
164 float window_scale_factor = 1.f; | 183 float window_scale_factor = 1.f; |
165 if ([self respondsToSelector:(@selector(contentsScale))]) | 184 if ([self respondsToSelector:(@selector(contentsScale))]) |
166 window_scale_factor = [self contentsScale]; | 185 window_scale_factor = [self contentsScale]; |
167 | 186 |
168 if (!renderWidgetHostView_->compositing_iosurface_->DrawIOSurface( | 187 if (!renderWidgetHostView_->compositing_iosurface_->DrawIOSurface( |
169 context_, | 188 context_, |
170 window_rect, | 189 window_rect, |
171 window_scale_factor, | 190 window_scale_factor, |
172 false)) { | 191 false)) { |
173 renderWidgetHostView_->GotAcceleratedCompositingError(); | 192 renderWidgetHostView_->GotAcceleratedCompositingError(); |
174 return; | 193 return; |
175 } | 194 } |
176 | 195 |
177 needsDisplay_ = NO; | 196 needsDisplay_ = NO; |
178 renderWidgetHostView_->SendPendingLatencyInfoToHost(); | 197 renderWidgetHostView_->SendPendingLatencyInfoToHost(); |
179 } | 198 } |
180 | 199 |
181 @end | 200 @end |
OLD | NEW |