OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_mac.h" | 5 #include "content/browser/renderer_host/compositing_iosurface_mac.h" |
6 | 6 |
7 #include <OpenGL/OpenGL.h> | 7 #include <OpenGL/OpenGL.h> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
12 #include "base/threading/platform_thread.h" | |
12 #include "content/browser/renderer_host/render_widget_host_view_mac.h" | 13 #include "content/browser/renderer_host/render_widget_host_view_mac.h" |
13 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
14 #include "gpu/command_buffer/service/gpu_switches.h" | 15 #include "gpu/command_buffer/service/gpu_switches.h" |
15 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | 16 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" |
16 #include "ui/gl/gl_context.h" | 17 #include "ui/gl/gl_context.h" |
17 #include "ui/gl/gl_switches.h" | 18 #include "ui/gl/gl_switches.h" |
18 #include "ui/surface/io_surface_support_mac.h" | 19 #include "ui/surface/io_surface_support_mac.h" |
19 | 20 |
20 #ifdef NDEBUG | 21 #ifdef NDEBUG |
21 #define CHECK_GL_ERROR() | 22 #define CHECK_GL_ERROR() |
22 #else | 23 #else |
23 #define CHECK_GL_ERROR() do { \ | 24 #define CHECK_GL_ERROR() do { \ |
24 GLenum gl_error = glGetError(); \ | 25 GLenum gl_error = glGetError(); \ |
25 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \ | 26 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \ |
26 } while (0) | 27 } while (0) |
27 #endif | 28 #endif |
28 | 29 |
29 #define SHADER_STRING_GLSL(shader) #shader | 30 #define SHADER_STRING_GLSL(shader) #shader |
30 | 31 |
31 namespace content { | 32 namespace content { |
32 namespace { | 33 namespace { |
33 | 34 |
34 static const char* g_vertex_shader_blit_rgb = SHADER_STRING_GLSL( | 35 const char* g_vertex_shader_blit_rgb = SHADER_STRING_GLSL( |
35 varying vec2 texture_coordinate; | 36 varying vec2 texture_coordinate; |
36 void main() { | 37 void main() { |
37 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | 38 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; |
38 texture_coordinate = vec2(gl_MultiTexCoord0); | 39 texture_coordinate = vec2(gl_MultiTexCoord0); |
39 }); | 40 }); |
40 | 41 |
41 static const char* g_fragment_shader_blit_rgb = SHADER_STRING_GLSL( | 42 const char* g_fragment_shader_blit_rgb = SHADER_STRING_GLSL( |
42 varying vec2 texture_coordinate; | 43 varying vec2 texture_coordinate; |
43 uniform sampler2DRect texture; | 44 uniform sampler2DRect texture; |
44 void main() { | 45 void main() { |
45 gl_FragColor = vec4(texture2DRect(texture, texture_coordinate).rgb, 1.0); | 46 gl_FragColor = vec4(texture2DRect(texture, texture_coordinate).rgb, 1.0); |
46 }); | 47 }); |
47 | 48 |
48 static const char* g_vertex_shader_white = SHADER_STRING_GLSL( | 49 const char* g_vertex_shader_white = SHADER_STRING_GLSL( |
49 void main() { | 50 void main() { |
50 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | 51 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; |
51 }); | 52 }); |
52 | 53 |
53 static const char* g_fragment_shader_white = SHADER_STRING_GLSL( | 54 const char* g_fragment_shader_white = SHADER_STRING_GLSL( |
54 void main() { | 55 void main() { |
55 gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); | 56 gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); |
56 }); | 57 }); |
57 | 58 |
58 // Create and compile shader, return its ID or 0 on error. | 59 // Create and compile shader, return its ID or 0 on error. |
59 GLuint CompileShaderGLSL(GLenum type, const char* shader_str) { | 60 GLuint CompileShaderGLSL(GLenum type, const char* shader_str) { |
60 GLuint shader = glCreateShader(type); | 61 GLuint shader = glCreateShader(type); |
61 glShaderSource(shader, 1, &shader_str, NULL); | 62 glShaderSource(shader, 1, &shader_str, NULL); |
62 glCompileShader(shader); CHECK_GL_ERROR(); | 63 glCompileShader(shader); CHECK_GL_ERROR(); |
63 GLint error; | 64 GLint error; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
98 glGetProgramiv(program, GL_LINK_STATUS, &error); | 99 glGetProgramiv(program, GL_LINK_STATUS, &error); |
99 if (error != GL_TRUE) { | 100 if (error != GL_TRUE) { |
100 glDeleteProgram(program); | 101 glDeleteProgram(program); |
101 return 0; | 102 return 0; |
102 } | 103 } |
103 return program; | 104 return program; |
104 } | 105 } |
105 | 106 |
106 } // namespace | 107 } // namespace |
107 | 108 |
109 CVReturn DisplayLinkCallback(CVDisplayLinkRef display_link, | |
110 const CVTimeStamp* now, | |
111 const CVTimeStamp* output_time, | |
112 CVOptionFlags flags_in, | |
113 CVOptionFlags* flags_out, | |
114 void* context) { | |
115 CompositingIOSurfaceMac* surface = | |
116 static_cast<CompositingIOSurfaceMac*>(context); | |
117 surface->DisplayLinkTick(display_link, output_time); | |
118 return kCVReturnSuccess; | |
119 } | |
120 | |
108 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() { | 121 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() { |
109 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::Create"); | 122 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::Create"); |
110 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); | 123 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); |
111 if (!io_surface_support) { | 124 if (!io_surface_support) { |
112 LOG(WARNING) << "No IOSurface support"; | 125 LOG(WARNING) << "No IOSurface support"; |
113 return NULL; | 126 return NULL; |
114 } | 127 } |
115 | 128 |
116 std::vector<NSOpenGLPixelFormatAttribute> attributes; | 129 std::vector<NSOpenGLPixelFormatAttribute> attributes; |
117 attributes.push_back(NSOpenGLPFADoubleBuffer); | 130 attributes.push_back(NSOpenGLPFADoubleBuffer); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 GLint blit_rgb_sampler_location = | 175 GLint blit_rgb_sampler_location = |
163 glGetUniformLocation(shader_program_blit_rgb, "texture"); | 176 glGetUniformLocation(shader_program_blit_rgb, "texture"); |
164 CGLSetCurrentContext(0); | 177 CGLSetCurrentContext(0); |
165 | 178 |
166 if (!shader_program_blit_rgb || !shader_program_white || | 179 if (!shader_program_blit_rgb || !shader_program_white || |
167 blit_rgb_sampler_location == -1) { | 180 blit_rgb_sampler_location == -1) { |
168 LOG(ERROR) << "IOSurface shader build error"; | 181 LOG(ERROR) << "IOSurface shader build error"; |
169 return NULL; | 182 return NULL; |
170 } | 183 } |
171 | 184 |
185 CVDisplayLinkRef display_link; | |
186 CVReturn ret = CVDisplayLinkCreateWithActiveCGDisplays(&display_link); | |
187 if (ret != kCVReturnSuccess) { | |
188 LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret; | |
189 return NULL; | |
190 } | |
191 | |
192 // Set the display link for the current renderer | |
193 CGLPixelFormatObj cglPixelFormat = | |
194 (CGLPixelFormatObj)[glPixelFormat CGLPixelFormatObj]; | |
195 ret = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(display_link, | |
196 cglContext, | |
197 cglPixelFormat); | |
198 if (ret != kCVReturnSuccess) { | |
199 CVDisplayLinkRelease(display_link); | |
200 LOG(ERROR) << "CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: " | |
201 << ret; | |
202 return NULL; | |
203 } | |
204 | |
172 return new CompositingIOSurfaceMac(io_surface_support, glContext.release(), | 205 return new CompositingIOSurfaceMac(io_surface_support, glContext.release(), |
173 cglContext, | 206 cglContext, |
174 shader_program_blit_rgb, | 207 shader_program_blit_rgb, |
175 blit_rgb_sampler_location, | 208 blit_rgb_sampler_location, |
176 shader_program_white, | 209 shader_program_white, |
177 is_vsync_disabled); | 210 is_vsync_disabled, |
211 display_link); | |
178 } | 212 } |
179 | 213 |
180 CompositingIOSurfaceMac::CompositingIOSurfaceMac( | 214 CompositingIOSurfaceMac::CompositingIOSurfaceMac( |
181 IOSurfaceSupport* io_surface_support, | 215 IOSurfaceSupport* io_surface_support, |
182 NSOpenGLContext* glContext, | 216 NSOpenGLContext* glContext, |
183 CGLContextObj cglContext, | 217 CGLContextObj cglContext, |
184 GLuint shader_program_blit_rgb, | 218 GLuint shader_program_blit_rgb, |
185 GLint blit_rgb_sampler_location, | 219 GLint blit_rgb_sampler_location, |
186 GLuint shader_program_white, | 220 GLuint shader_program_white, |
187 bool is_vsync_disabled) | 221 bool is_vsync_disabled, |
222 CVDisplayLinkRef display_link) | |
188 : io_surface_support_(io_surface_support), | 223 : io_surface_support_(io_surface_support), |
189 glContext_(glContext), | 224 glContext_(glContext), |
190 cglContext_(cglContext), | 225 cglContext_(cglContext), |
191 io_surface_handle_(0), | 226 io_surface_handle_(0), |
192 texture_(0), | 227 texture_(0), |
193 shader_program_blit_rgb_(shader_program_blit_rgb), | 228 shader_program_blit_rgb_(shader_program_blit_rgb), |
194 blit_rgb_sampler_location_(blit_rgb_sampler_location), | 229 blit_rgb_sampler_location_(blit_rgb_sampler_location), |
195 shader_program_white_(shader_program_white), | 230 shader_program_white_(shader_program_white), |
196 is_vsync_disabled_(is_vsync_disabled) { | 231 is_vsync_disabled_(is_vsync_disabled), |
232 display_link_(display_link), | |
233 display_link_stop_timer_(FROM_HERE, base::TimeDelta::FromSeconds(1), | |
234 this, &CompositingIOSurfaceMac::StopDisplayLink), | |
235 vsync_count_(0), | |
236 swap_count_(0), | |
237 vsync_interval_numerator_(0), | |
238 vsync_interval_denominator_(0) { | |
239 CVReturn ret = CVDisplayLinkSetOutputCallback(display_link_, | |
240 &DisplayLinkCallback, this); | |
241 DCHECK(ret == kCVReturnSuccess) | |
242 << "CVDisplayLinkSetOutputCallback failed: " << ret; | |
243 | |
244 StartOrContinueDisplayLink(); | |
245 | |
246 CVTimeStamp cv_time; | |
247 ret = CVDisplayLinkGetCurrentTime(display_link_, &cv_time); | |
248 DCHECK(ret == kCVReturnSuccess) | |
249 << "CVDisplayLinkGetCurrentTime failed: " << ret; | |
250 | |
251 { | |
252 base::AutoLock lock(lock_); | |
253 CalculateVsyncParametersLockHeld(&cv_time); | |
254 } | |
255 | |
256 // Stop display link for now, it will be started when needed during Draw. | |
257 StopDisplayLink(); | |
258 } | |
259 | |
260 void CompositingIOSurfaceMac::GetVSyncParameters(base::TimeTicks* timebase, | |
261 uint32* interval_numerator, | |
262 uint32* interval_denominator) { | |
263 *timebase = vsync_timebase_; | |
264 *interval_numerator = vsync_interval_numerator_; | |
265 *interval_denominator = vsync_interval_denominator_; | |
197 } | 266 } |
198 | 267 |
199 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { | 268 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { |
269 CVDisplayLinkRelease(display_link_); | |
200 UnrefIOSurface(); | 270 UnrefIOSurface(); |
201 } | 271 } |
202 | 272 |
203 void CompositingIOSurfaceMac::SetIOSurface(uint64 io_surface_handle) { | 273 void CompositingIOSurfaceMac::SetIOSurface(uint64 io_surface_handle) { |
204 CGLSetCurrentContext(cglContext_); | 274 CGLSetCurrentContext(cglContext_); |
205 MapIOSurfaceToTexture(io_surface_handle); | 275 MapIOSurfaceToTexture(io_surface_handle); |
206 CGLSetCurrentContext(0); | 276 CGLSetCurrentContext(0); |
207 } | 277 } |
208 | 278 |
209 void CompositingIOSurfaceMac::DrawIOSurface(NSView* view, float scale_factor) { | 279 void CompositingIOSurfaceMac::DrawIOSurface(NSView* view, float scale_factor) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 if (use_glfinish_workaround) { | 363 if (use_glfinish_workaround) { |
294 // http://crbug.com/123409 : work around bugs in graphics driver on | 364 // http://crbug.com/123409 : work around bugs in graphics driver on |
295 // MacBook Air with Intel HD graphics, and possibly on other models, | 365 // MacBook Air with Intel HD graphics, and possibly on other models, |
296 // by forcing the graphics pipeline to be completely drained at this | 366 // by forcing the graphics pipeline to be completely drained at this |
297 // point. | 367 // point. |
298 glFinish(); | 368 glFinish(); |
299 } | 369 } |
300 | 370 |
301 CGLFlushDrawable(cglContext_); | 371 CGLFlushDrawable(cglContext_); |
302 | 372 |
373 // For latency_tests.cc: | |
374 UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete"); | |
375 | |
303 CGLSetCurrentContext(0); | 376 CGLSetCurrentContext(0); |
377 | |
378 StartOrContinueDisplayLink(); | |
379 | |
380 if (!is_vsync_disabled_) | |
381 RateLimitDraws(); | |
304 } | 382 } |
305 | 383 |
306 bool CompositingIOSurfaceMac::CopyTo(const gfx::Size& dst_size, void* out) { | 384 bool CompositingIOSurfaceMac::CopyTo(const gfx::Size& dst_size, void* out) { |
307 if (!MapIOSurfaceToTexture(io_surface_handle_)) | 385 if (!MapIOSurfaceToTexture(io_surface_handle_)) |
308 return false; | 386 return false; |
309 | 387 |
310 CGLSetCurrentContext(cglContext_); | 388 CGLSetCurrentContext(cglContext_); |
311 GLuint target = GL_TEXTURE_RECTANGLE_ARB; | 389 GLuint target = GL_TEXTURE_RECTANGLE_ARB; |
312 | 390 |
313 GLuint dst_texture = 0; | 391 GLuint dst_texture = 0; |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
460 | 538 |
461 void CompositingIOSurfaceMac::GlobalFrameDidChange() { | 539 void CompositingIOSurfaceMac::GlobalFrameDidChange() { |
462 [glContext_ update]; | 540 [glContext_ update]; |
463 } | 541 } |
464 | 542 |
465 void CompositingIOSurfaceMac::ClearDrawable() { | 543 void CompositingIOSurfaceMac::ClearDrawable() { |
466 [glContext_ clearDrawable]; | 544 [glContext_ clearDrawable]; |
467 UnrefIOSurface(); | 545 UnrefIOSurface(); |
468 } | 546 } |
469 | 547 |
548 void CompositingIOSurfaceMac::DisplayLinkTick(CVDisplayLinkRef display_link, | |
549 const CVTimeStamp* output_time) { | |
550 base::AutoLock lock(lock_); | |
551 // Increment vsync_count but don't let it get ahead of swap_count. | |
552 vsync_count_ = std::min(vsync_count_ + 1, swap_count_); | |
553 | |
554 CalculateVsyncParametersLockHeld(output_time); | |
555 } | |
556 | |
557 void CompositingIOSurfaceMac::CalculateVsyncParametersLockHeld( | |
558 const CVTimeStamp* time) { | |
559 vsync_interval_numerator_ = static_cast<uint32>(time->videoRefreshPeriod); | |
560 vsync_interval_denominator_ = time->videoTimeScale; | |
561 // Verify that videoRefreshPeriod is 32 bits. | |
562 DCHECK((time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull); | |
563 | |
564 vsync_timebase_ = | |
565 base::TimeTicks::FromInternalValue(time->hostTime / 1000); | |
566 } | |
567 | |
568 void CompositingIOSurfaceMac::RateLimitDraws() { | |
569 int64 vsync_count; | |
570 int64 swap_count; | |
571 | |
572 { | |
573 base::AutoLock lock(lock_); | |
574 vsync_count = vsync_count_; | |
575 swap_count = ++swap_count_; | |
vangelis
2012/08/01 00:53:12
Should these two values be reset somewhere on a su
jbates
2012/08/01 01:00:47
They get reset when the 1 second idle timer fires.
vangelis
2012/08/01 01:33:01
Oh, I see. That makes sense.
| |
576 } | |
577 | |
578 // It's OK for swap_count to get 2 ahead of vsync_count, but any more | |
579 // indicates that it has become unthrottled. This happens when, for example, | |
580 // the window is obscured by another opaque window. | |
581 if (swap_count > vsync_count + 2) { | |
582 TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::RateLimitDraws"); | |
583 // Sleep for one vsync interval. This will prevent spinning while the window | |
584 // is not visible, but will also allow quick recovery when the window | |
585 // becomes visible again. | |
586 int64 sleep_us = 16666; // default to 60hz if display link API fails. | |
587 if (vsync_interval_denominator_ > 0) { | |
588 sleep_us = (static_cast<int64>(vsync_interval_numerator_) * 1000000) / | |
589 vsync_interval_denominator_; | |
590 } | |
591 base::PlatformThread::Sleep(base::TimeDelta::FromMicroseconds(sleep_us)); | |
592 } | |
593 } | |
594 | |
595 void CompositingIOSurfaceMac::StartOrContinueDisplayLink() { | |
596 if (!CVDisplayLinkIsRunning(display_link_)) { | |
597 vsync_count_ = swap_count_ = 0; | |
598 CVDisplayLinkStart(display_link_); | |
599 } | |
600 display_link_stop_timer_.Reset(); | |
601 } | |
602 | |
603 void CompositingIOSurfaceMac::StopDisplayLink() { | |
604 if (CVDisplayLinkIsRunning(display_link_)) | |
605 CVDisplayLinkStop(display_link_); | |
606 } | |
607 | |
470 } // namespace content | 608 } // namespace content |
OLD | NEW |