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

Side by Side Diff: content/browser/renderer_host/compositing_iosurface_mac.mm

Issue 10828104: fix mac frame-rate regression for non-threaded GPU compositing (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove DEPS change Created 8 years, 4 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) 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698