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/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 @implementation CompositingIOSurfaceLayer | 20 @implementation CompositingIOSurfaceLayer |
21 | 21 |
22 - (id)initWithRenderWidgetHostViewMac:(content::RenderWidgetHostViewMac*)r { | 22 - (content::CompositingIOSurfaceMac*)iosurface { |
| 23 return iosurface_.get(); |
| 24 } |
| 25 |
| 26 - (content::CompositingIOSurfaceContext*)context { |
| 27 return context_.get(); |
| 28 } |
| 29 |
| 30 - (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>) |
| 31 iosurface |
| 32 withClient:(content::CompositingIOSurfaceLayerClient*)client { |
23 if (self = [super init]) { | 33 if (self = [super init]) { |
24 renderWidgetHostView_ = r; | 34 iosurface_ = iosurface; |
| 35 client_ = client; |
| 36 |
25 context_ = content::CompositingIOSurfaceContext::Get( | 37 context_ = content::CompositingIOSurfaceContext::Get( |
26 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber); | 38 content::CompositingIOSurfaceContext::kCALayerContextWindowNumber); |
27 DCHECK(context_); | 39 DCHECK(context_); |
28 needsDisplay_ = NO; | 40 needs_display_ = NO; |
| 41 did_not_draw_counter_ = 0; |
29 | 42 |
30 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; | 43 [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; |
31 [self setAnchorPoint:CGPointMake(0, 0)]; | 44 [self setAnchorPoint:CGPointMake(0, 0)]; |
32 // Setting contents gravity is necessary to prevent the layer from being | 45 // Setting contents gravity is necessary to prevent the layer from being |
33 // scaled during dyanmic resizes (especially with devtools open). | 46 // scaled during dyanmic resizes (especially with devtools open). |
34 [self setContentsGravity:kCAGravityTopLeft]; | 47 [self setContentsGravity:kCAGravityTopLeft]; |
35 if (renderWidgetHostView_->compositing_iosurface_ && | 48 if ([self respondsToSelector:(@selector(setContentsScale:))]) { |
36 [self respondsToSelector:(@selector(setContentsScale:))]) { | 49 [self setContentsScale:iosurface_->scale_factor()]; |
37 [self setContentsScale: | |
38 renderWidgetHostView_->compositing_iosurface_->scale_factor()]; | |
39 } | 50 } |
40 } | 51 } |
41 return self; | 52 return self; |
42 } | 53 } |
43 | 54 |
44 - (void)disableCompositing{ | 55 - (void)resetClient { |
45 renderWidgetHostView_ = nil; | 56 client_ = NULL; |
46 } | 57 } |
47 | 58 |
48 - (void)gotNewFrame { | 59 - (void)gotNewFrame { |
49 if (context_ && context_->is_vsync_disabled()) { | 60 if (context_ && context_->is_vsync_disabled()) { |
50 // If vsync is disabled, draw immediately and don't bother trying to use | 61 // If vsync is disabled, draw immediately and don't bother trying to use |
51 // the isAsynchronous property to ensure smooth animation. | 62 // the isAsynchronous property to ensure smooth animation. |
52 [self setNeedsDisplay]; | 63 [self setNeedsDisplay]; |
53 [self displayIfNeeded]; | 64 [self displayIfNeeded]; |
54 | 65 |
55 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued | 66 // Calls to setNeedsDisplay can sometimes be ignored, especially if issued |
56 // rapidly (e.g, with vsync off). This is unacceptable because the failure | 67 // rapidly (e.g, with vsync off). This is unacceptable because the failure |
57 // to ack a single frame will hang the renderer. Ensure that the renderer | 68 // to ack a single frame will hang the renderer. Ensure that the renderer |
58 // not be blocked. | 69 // not be blocked by lying and claiming that we drew the frame. |
59 if (needsDisplay_) | 70 if (needs_display_ && client_) |
60 renderWidgetHostView_->SendPendingSwapAck(); | 71 client_->AcceleratedLayerDidDrawFrame(true); |
61 } else { | 72 } else { |
62 needsDisplay_ = YES; | 73 needs_display_ = YES; |
63 if (![self isAsynchronous]) | 74 if (![self isAsynchronous]) |
64 [self setAsynchronous:YES]; | 75 [self setAsynchronous:YES]; |
65 } | 76 } |
66 } | 77 } |
67 | 78 |
68 - (void)timerSinceGotNewFrameFired { | |
69 if (![self isAsynchronous]) | |
70 return; | |
71 | |
72 [self setAsynchronous:NO]; | |
73 | |
74 // If there was a pending frame, ensure that it goes through. | |
75 if (needsDisplay_) { | |
76 [self setNeedsDisplay]; | |
77 [self displayIfNeeded]; | |
78 } | |
79 // If that fails then ensure that, at a minimum, the renderer is not blocked. | |
80 if (needsDisplay_) | |
81 renderWidgetHostView_->SendPendingSwapAck(); | |
82 } | |
83 | |
84 // The remaining methods implement the CAOpenGLLayer interface. | 79 // The remaining methods implement the CAOpenGLLayer interface. |
85 | 80 |
86 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { | 81 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { |
87 if (!context_) | 82 if (!context_) |
88 return [super copyCGLPixelFormatForDisplayMask:mask]; | 83 return [super copyCGLPixelFormatForDisplayMask:mask]; |
89 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); | 84 return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context())); |
90 } | 85 } |
91 | 86 |
92 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { | 87 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { |
93 if (!context_) | 88 if (!context_) |
94 return [super copyCGLContextForPixelFormat:pixelFormat]; | 89 return [super copyCGLContextForPixelFormat:pixelFormat]; |
95 return CGLRetainContext(context_->cgl_context()); | 90 return CGLRetainContext(context_->cgl_context()); |
96 } | 91 } |
97 | 92 |
98 - (void)setNeedsDisplay { | 93 - (void)setNeedsDisplay { |
99 needsDisplay_ = YES; | 94 needs_display_ = YES; |
100 [super setNeedsDisplay]; | 95 [super setNeedsDisplay]; |
101 } | 96 } |
102 | 97 |
103 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext | 98 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext |
104 pixelFormat:(CGLPixelFormatObj)pixelFormat | 99 pixelFormat:(CGLPixelFormatObj)pixelFormat |
105 forLayerTime:(CFTimeInterval)timeInterval | 100 forLayerTime:(CFTimeInterval)timeInterval |
106 displayTime:(const CVTimeStamp*)timeStamp { | 101 displayTime:(const CVTimeStamp*)timeStamp { |
107 if (!renderWidgetHostView_) | |
108 return NO; | |
109 | |
110 // Add an instantaneous blip to the PendingSwapAck state to indicate | 102 // Add an instantaneous blip to the PendingSwapAck state to indicate |
111 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually | 103 // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually |
112 // from 2, indicating that a swap ack is pending) indicates that we requested | 104 // from 2, indicating that a swap ack is pending) indicates that we requested |
113 // a draw. A blip up to 1 (usually from 0, indicating there is no pending swap | 105 // a draw. A blip up to 1 (usually from 0, indicating there is no pending swap |
114 // ack) indicates that we did not request a draw. This would be more natural | 106 // ack) indicates that we did not request a draw. This would be more natural |
115 // to do with a tracing pseudo-thread | 107 // to do with a tracing pseudo-thread |
116 // http://crbug.com/366300 | 108 // http://crbug.com/366300 |
117 TRACE_COUNTER_ID1("browser", "PendingSwapAck", renderWidgetHostView_, | 109 if (client_) { |
118 needsDisplay_ ? 3 : 1); | 110 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, |
119 TRACE_COUNTER_ID1("browser", "PendingSwapAck", renderWidgetHostView_, | 111 needs_display_ ? 3 : 1); |
120 renderWidgetHostView_->HasPendingSwapAck() ? 2 : 0); | 112 TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, |
| 113 client_->AcceleratedLayerHasNotAckedPendingFrame() ? 2 : 0); |
| 114 } |
121 | 115 |
122 return needsDisplay_; | 116 // If we return NO 30 times in a row, switch to being synchronous to avoid |
| 117 // burning CPU cycles on this callback. |
| 118 if (needs_display_) { |
| 119 did_not_draw_counter_ = 0; |
| 120 } else { |
| 121 did_not_draw_counter_ += 1; |
| 122 if (did_not_draw_counter_ > 30) |
| 123 [self setAsynchronous:NO]; |
| 124 } |
| 125 |
| 126 return needs_display_; |
123 } | 127 } |
124 | 128 |
125 - (void)drawInCGLContext:(CGLContextObj)glContext | 129 - (void)drawInCGLContext:(CGLContextObj)glContext |
126 pixelFormat:(CGLPixelFormatObj)pixelFormat | 130 pixelFormat:(CGLPixelFormatObj)pixelFormat |
127 forLayerTime:(CFTimeInterval)timeInterval | 131 forLayerTime:(CFTimeInterval)timeInterval |
128 displayTime:(const CVTimeStamp*)timeStamp { | 132 displayTime:(const CVTimeStamp*)timeStamp { |
129 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext"); | 133 TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext"); |
130 | 134 |
131 if (!context_ || | 135 if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) { |
132 (context_ && context_->cgl_context() != glContext) || | |
133 !renderWidgetHostView_ || | |
134 !renderWidgetHostView_->compositing_iosurface_ || | |
135 !renderWidgetHostView_->compositing_iosurface_->HasIOSurface()) { | |
136 glClearColor(1, 1, 1, 1); | 136 glClearColor(1, 1, 1, 1); |
137 glClear(GL_COLOR_BUFFER_BIT); | 137 glClear(GL_COLOR_BUFFER_BIT); |
138 return; | 138 return; |
139 } | 139 } |
140 | 140 |
141 // The correct viewport to cover the layer will be set up by the caller. | 141 // The correct viewport to cover the layer will be set up by the caller. |
142 // Transform this into a window size for DrawIOSurface, where it will be | 142 // Transform this into a window size for DrawIOSurface, where it will be |
143 // transformed back into this viewport. | 143 // transformed back into this viewport. |
144 GLint viewport[4]; | 144 GLint viewport[4]; |
145 glGetIntegerv(GL_VIEWPORT, viewport); | 145 glGetIntegerv(GL_VIEWPORT, viewport); |
146 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]); | 146 gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]); |
147 float window_scale_factor = 1.f; | 147 float window_scale_factor = 1.f; |
148 if ([self respondsToSelector:(@selector(contentsScale))]) | 148 if ([self respondsToSelector:(@selector(contentsScale))]) |
149 window_scale_factor = [self contentsScale]; | 149 window_scale_factor = [self contentsScale]; |
150 window_rect = ToNearestRect( | 150 window_rect = ToNearestRect( |
151 gfx::ScaleRect(window_rect, 1.f/window_scale_factor)); | 151 gfx::ScaleRect(window_rect, 1.f/window_scale_factor)); |
152 | 152 |
153 if (!renderWidgetHostView_->compositing_iosurface_->DrawIOSurface( | 153 bool draw_succeeded = iosurface_->DrawIOSurface( |
154 context_, | 154 context_, window_rect, window_scale_factor, false); |
155 window_rect, | |
156 window_scale_factor, | |
157 false)) { | |
158 renderWidgetHostView_->GotAcceleratedCompositingError(); | |
159 return; | |
160 } | |
161 | 155 |
162 needsDisplay_ = NO; | 156 needs_display_ = NO; |
163 renderWidgetHostView_->SendPendingLatencyInfoToHost(); | 157 if (client_) |
164 renderWidgetHostView_->SendPendingSwapAck(); | 158 client_->AcceleratedLayerDidDrawFrame(draw_succeeded); |
165 | 159 |
166 [super drawInCGLContext:glContext | 160 [super drawInCGLContext:glContext |
167 pixelFormat:pixelFormat | 161 pixelFormat:pixelFormat |
168 forLayerTime:timeInterval | 162 forLayerTime:timeInterval |
169 displayTime:timeStamp]; | 163 displayTime:timeStamp]; |
170 } | 164 } |
171 | 165 |
172 @end | 166 @end |
OLD | NEW |