Chromium Code Reviews| 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 extern "C" { | 5 extern "C" { |
| 6 #include <X11/Xlib.h> | 6 #include <X11/Xlib.h> |
| 7 } | 7 } |
| 8 | 8 |
| 9 #include "ui/gl/gl_surface_glx.h" | 9 #include "ui/gl/gl_surface_glx.h" |
| 10 | 10 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML | 50 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML |
| 51 // always fails even though GLX_OML_sync_control is reported as being supported. | 51 // always fails even though GLX_OML_sync_control is reported as being supported. |
| 52 bool g_glx_get_msc_rate_oml_supported = false; | 52 bool g_glx_get_msc_rate_oml_supported = false; |
| 53 | 53 |
| 54 bool g_glx_sgi_video_sync_supported = false; | 54 bool g_glx_sgi_video_sync_supported = false; |
| 55 | 55 |
| 56 class OMLSyncControlVSyncProvider | 56 class OMLSyncControlVSyncProvider |
| 57 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider { | 57 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider { |
| 58 public: | 58 public: |
| 59 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window) | 59 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window) |
| 60 : window_(window) { | 60 : window_(window), |
| 61 last_timebase_(), | |
|
apatrick_chromium
2013/01/04 21:21:09
nit: this line is redundant.
jonathan.backer
2013/01/04 21:29:22
Done.
| |
| 62 last_media_stream_counter_(0), | |
| 63 last_good_interval_() { | |
|
apatrick_chromium
2013/01/04 21:21:09
and here
jonathan.backer
2013/01/04 21:29:22
Done.
| |
| 64 // On platforms where we can't get an accurate reading on the refresh | |
| 65 // rate we fall back to the assumption that we're displaying 60 frames | |
| 66 // per second. | |
| 67 last_good_interval_ = base::TimeDelta::FromSeconds(1) / 60; | |
| 61 } | 68 } |
| 62 | 69 |
| 63 virtual ~OMLSyncControlVSyncProvider() { } | 70 virtual ~OMLSyncControlVSyncProvider() { } |
| 64 | 71 |
| 65 virtual void GetVSyncParameters( | 72 virtual void GetVSyncParameters( |
| 66 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { | 73 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { |
| 67 base::TimeTicks timebase; | 74 base::TimeTicks timebase; |
| 68 base::TimeDelta interval; | |
| 69 | 75 |
| 70 // The actual clock used for the system time returned by glXGetSyncValuesOML | 76 // The actual clock used for the system time returned by glXGetSyncValuesOML |
| 71 // is unspecified. In practice, the clock used is likely to be either | 77 // is unspecified. In practice, the clock used is likely to be either |
| 72 // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the | 78 // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the |
| 73 // current time according to both clocks, and assume that the returned time | 79 // current time according to both clocks, and assume that the returned time |
| 74 // was produced by the clock whose current time is closest to it, subject | 80 // was produced by the clock whose current time is closest to it, subject |
| 75 // to the restriction that the returned time must not be in the future | 81 // to the restriction that the returned time must not be in the future |
| 76 // (since it is the time of a vblank that has already occurred). | 82 // (since it is the time of a vblank that has already occurred). |
| 77 int64 system_time; | 83 int64 system_time; |
| 78 int64 media_stream_counter; | 84 int64 media_stream_counter; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 106 | 112 |
| 107 if (time_conversion_needed) { | 113 if (time_conversion_needed) { |
| 108 int64 time_difference = | 114 int64 time_difference = |
| 109 real_time_in_microseconds - monotonic_time_in_microseconds; | 115 real_time_in_microseconds - monotonic_time_in_microseconds; |
| 110 timebase = base::TimeTicks::FromInternalValue( | 116 timebase = base::TimeTicks::FromInternalValue( |
| 111 system_time - time_difference); | 117 system_time - time_difference); |
| 112 } else { | 118 } else { |
| 113 timebase = base::TimeTicks::FromInternalValue(system_time); | 119 timebase = base::TimeTicks::FromInternalValue(system_time); |
| 114 } | 120 } |
| 115 | 121 |
| 116 // On platforms where glXGetMscRateOML doesn't work, we fall back to the | |
| 117 // assumption that we're displaying 60 frames per second. | |
| 118 const int64 kDefaultIntervalTime = | |
| 119 base::Time::kMicrosecondsPerSecond / 60; | |
| 120 int64 interval_time = kDefaultIntervalTime; | |
| 121 int32 numerator; | |
| 122 int32 denominator; | |
| 123 if (g_glx_get_msc_rate_oml_supported) { | 122 if (g_glx_get_msc_rate_oml_supported) { |
| 123 int32 numerator, denominator; | |
| 124 if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { | 124 if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { |
| 125 interval_time = | 125 last_good_interval_ = |
| 126 (base::Time::kMicrosecondsPerSecond * denominator) / numerator; | 126 base::TimeDelta::FromSeconds(denominator) / numerator; |
| 127 } else { | 127 } else { |
| 128 // Once glXGetMscRateOML has been found to fail, don't try again, | 128 // Once glXGetMscRateOML has been found to fail, don't try again, |
| 129 // since each failing call may spew an error message. | 129 // since each failing call may spew an error message. |
| 130 g_glx_get_msc_rate_oml_supported = false; | 130 g_glx_get_msc_rate_oml_supported = false; |
| 131 } | 131 } |
| 132 } else { | |
| 133 if (!last_timebase_.is_null()) { | |
|
apatrick_chromium
2013/01/04 21:21:09
indentation is out
jonathan.backer
2013/01/04 21:29:22
Done.
| |
| 134 base::TimeDelta timebase_diff = timebase - last_timebase_; | |
| 135 uint64 counter_diff = media_stream_counter - | |
| 136 last_media_stream_counter_; | |
| 137 if (counter_diff > 0 && timebase > last_timebase_) | |
| 138 last_good_interval_ = timebase_diff / counter_diff; | |
| 139 } | |
| 132 } | 140 } |
| 133 interval = base::TimeDelta::FromMicroseconds(interval_time); | 141 last_timebase_ = timebase; |
| 134 callback.Run(timebase, interval); | 142 last_media_stream_counter_ = media_stream_counter; |
| 143 callback.Run(timebase, last_good_interval_); | |
| 135 } | 144 } |
| 136 | 145 |
| 137 private: | 146 private: |
| 138 XID window_; | 147 XID window_; |
| 139 | 148 |
| 149 base::TimeTicks last_timebase_; | |
| 150 uint64 last_media_stream_counter_; | |
| 151 base::TimeDelta last_good_interval_; | |
| 152 | |
| 140 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); | 153 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); |
| 141 }; | 154 }; |
| 142 | 155 |
| 143 class SGIVideoSyncThread | 156 class SGIVideoSyncThread |
| 144 : public base::Thread, | 157 : public base::Thread, |
| 145 public base::NonThreadSafe, | 158 public base::NonThreadSafe, |
| 146 public base::RefCounted<SGIVideoSyncThread> { | 159 public base::RefCounted<SGIVideoSyncThread> { |
| 147 public: | 160 public: |
| 148 static scoped_refptr<SGIVideoSyncThread> Create() { | 161 static scoped_refptr<SGIVideoSyncThread> Create() { |
| 149 if (!g_video_sync_thread) { | 162 if (!g_video_sync_thread) { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 175 : public base::SupportsWeakPtr<SGIVideoSyncProviderThreadShim> { | 188 : public base::SupportsWeakPtr<SGIVideoSyncProviderThreadShim> { |
| 176 public: | 189 public: |
| 177 explicit SGIVideoSyncProviderThreadShim(XID window) | 190 explicit SGIVideoSyncProviderThreadShim(XID window) |
| 178 : window_(window), | 191 : window_(window), |
| 179 context_(NULL), | 192 context_(NULL), |
| 180 message_loop_(base::MessageLoopProxy::current()), | 193 message_loop_(base::MessageLoopProxy::current()), |
| 181 cancel_vsync_flag_(), | 194 cancel_vsync_flag_(), |
| 182 vsync_lock_() { | 195 vsync_lock_() { |
| 183 // This ensures that creation of |window_| has occured when this shim | 196 // This ensures that creation of |window_| has occured when this shim |
| 184 // is executing in the same process as the call to create |window_|. | 197 // is executing in the same process as the call to create |window_|. |
| 185 XSync(::gfx::g_display, False); | 198 XSync(g_display, False); |
| 186 } | 199 } |
| 187 | 200 |
| 188 base::CancellationFlag* cancel_vsync_flag() { | 201 base::CancellationFlag* cancel_vsync_flag() { |
| 189 return &cancel_vsync_flag_; | 202 return &cancel_vsync_flag_; |
| 190 } | 203 } |
| 191 | 204 |
| 192 base::Lock* vsync_lock() { | 205 base::Lock* vsync_lock() { |
| 193 return &vsync_lock_; | 206 return &vsync_lock_; |
| 194 } | 207 } |
| 195 | 208 |
| 196 void Initialize() { | 209 void Initialize() { |
| 197 DCHECK(SGIVideoSyncProviderThreadShim::g_display); | 210 DCHECK(display_); |
| 198 | 211 |
| 199 XWindowAttributes attributes; | 212 XWindowAttributes attributes; |
| 200 if (!XGetWindowAttributes(SGIVideoSyncProviderThreadShim::g_display, | 213 if (!XGetWindowAttributes(display_, window_, &attributes)) { |
| 201 window_, &attributes)) { | |
| 202 LOG(ERROR) << "XGetWindowAttributes failed for window " << | 214 LOG(ERROR) << "XGetWindowAttributes failed for window " << |
| 203 window_ << "."; | 215 window_ << "."; |
| 204 return; | 216 return; |
| 205 } | 217 } |
| 206 | 218 |
| 207 XVisualInfo visual_info_template; | 219 XVisualInfo visual_info_template; |
| 208 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); | 220 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); |
| 209 | 221 |
| 210 int visual_info_count = 0; | 222 int visual_info_count = 0; |
| 211 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( | 223 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( |
| 212 XGetVisualInfo(SGIVideoSyncProviderThreadShim::g_display, VisualIDMask, | 224 XGetVisualInfo(display_, VisualIDMask, |
| 213 &visual_info_template, &visual_info_count)); | 225 &visual_info_template, &visual_info_count)); |
| 214 | 226 |
| 215 DCHECK(visual_info_list.get()); | 227 DCHECK(visual_info_list.get()); |
| 216 if (visual_info_count == 0) { | 228 if (visual_info_count == 0) { |
| 217 LOG(ERROR) << "No visual info for visual ID."; | 229 LOG(ERROR) << "No visual info for visual ID."; |
| 218 return; | 230 return; |
| 219 } | 231 } |
| 220 | 232 |
| 221 context_ = glXCreateContext(SGIVideoSyncProviderThreadShim::g_display, | 233 context_ = glXCreateContext(display_, visual_info_list.get(), NULL, True); |
| 222 visual_info_list.get(), | |
| 223 NULL, | |
| 224 True); | |
| 225 | 234 |
| 226 DCHECK(NULL != context_); | 235 DCHECK(NULL != context_); |
| 227 } | 236 } |
| 228 | 237 |
| 229 void Destroy() { | 238 void Destroy() { |
| 230 if (context_) { | 239 if (context_) { |
| 231 glXDestroyContext(SGIVideoSyncProviderThreadShim::g_display, context_); | 240 glXDestroyContext(display_, context_); |
| 232 context_ = NULL; | 241 context_ = NULL; |
| 233 } | 242 } |
| 234 delete this; | 243 delete this; |
| 235 } | 244 } |
| 236 | 245 |
| 237 void GetVSyncParameters(const GLSurface::UpdateVSyncCallback& callback) { | 246 void GetVSyncParameters(const GLSurface::UpdateVSyncCallback& callback) { |
| 238 base::TimeTicks now; | 247 base::TimeTicks now; |
| 239 { | 248 { |
| 240 // Don't allow |window_| destruction while we're probing vsync. | 249 // Don't allow |window_| destruction while we're probing vsync. |
| 241 base::AutoLock locked(vsync_lock_); | 250 base::AutoLock locked(vsync_lock_); |
| 242 | 251 |
| 243 if (!context_ || cancel_vsync_flag_.IsSet()) | 252 if (!context_ || cancel_vsync_flag_.IsSet()) |
| 244 return; | 253 return; |
| 245 | 254 |
| 246 glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, | 255 glXMakeCurrent(display_, window_, context_); |
| 247 window_, context_); | |
| 248 | 256 |
| 249 unsigned int retrace_count = 0; | 257 unsigned int retrace_count = 0; |
| 250 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) | 258 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) |
| 251 return; | 259 return; |
| 252 | 260 |
| 253 TRACE_EVENT_INSTANT0("gpu", "vblank"); | 261 TRACE_EVENT_INSTANT0("gpu", "vblank"); |
| 254 now = base::TimeTicks::HighResNow(); | 262 now = base::TimeTicks::HighResNow(); |
| 255 | 263 |
| 256 glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, 0, 0); | 264 glXMakeCurrent(display_, 0, 0); |
| 257 } | 265 } |
| 258 | 266 |
| 259 const int64 kDefaultIntervalTime = | 267 const base::TimeDelta kDefaultInterval = |
| 260 base::Time::kMicrosecondsPerSecond / 60; | 268 base::TimeDelta::FromSeconds(1) / 60; |
| 261 base::TimeDelta interval = | |
| 262 base::TimeDelta::FromMicroseconds(kDefaultIntervalTime); | |
| 263 | 269 |
| 264 message_loop_->PostTask(FROM_HERE, base::Bind(callback, now, interval)); | 270 message_loop_->PostTask( |
| 271 FROM_HERE, base::Bind(callback, now, kDefaultInterval)); | |
| 265 } | 272 } |
| 266 | 273 |
| 267 private: | 274 private: |
| 268 // For initialization of g_display in GLSurface::InitializeOneOff before | 275 // For initialization of display_ in GLSurface::InitializeOneOff before |
| 269 // the sandbox goes up. | 276 // the sandbox goes up. |
| 270 friend class gfx::GLSurfaceGLX; | 277 friend class gfx::GLSurfaceGLX; |
| 271 | 278 |
| 272 virtual ~SGIVideoSyncProviderThreadShim() { | 279 virtual ~SGIVideoSyncProviderThreadShim() { |
| 273 } | 280 } |
| 274 | 281 |
| 275 static Display* g_display; | 282 static Display* display_; |
| 276 | 283 |
| 277 XID window_; | 284 XID window_; |
| 278 GLXContext context_; | 285 GLXContext context_; |
| 279 | 286 |
| 280 scoped_refptr<base::MessageLoopProxy> message_loop_; | 287 scoped_refptr<base::MessageLoopProxy> message_loop_; |
| 281 | 288 |
| 282 base::CancellationFlag cancel_vsync_flag_; | 289 base::CancellationFlag cancel_vsync_flag_; |
| 283 base::Lock vsync_lock_; | 290 base::Lock vsync_lock_; |
| 284 | 291 |
| 285 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); | 292 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 base::Lock* vsync_lock_; | 353 base::Lock* vsync_lock_; |
| 347 | 354 |
| 348 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); | 355 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); |
| 349 }; | 356 }; |
| 350 | 357 |
| 351 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; | 358 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; |
| 352 | 359 |
| 353 // In order to take advantage of GLX_SGI_video_sync, we need a display | 360 // In order to take advantage of GLX_SGI_video_sync, we need a display |
| 354 // for use on a separate thread. We must allocate this before the sandbox | 361 // for use on a separate thread. We must allocate this before the sandbox |
| 355 // goes up (rather than on-demand when we start the thread). | 362 // goes up (rather than on-demand when we start the thread). |
| 356 Display* SGIVideoSyncProviderThreadShim::g_display = NULL; | 363 Display* SGIVideoSyncProviderThreadShim::display_ = NULL; |
| 357 | 364 |
| 358 } // namespace | 365 } // namespace |
| 359 | 366 |
| 360 GLSurfaceGLX::GLSurfaceGLX() {} | 367 GLSurfaceGLX::GLSurfaceGLX() {} |
| 361 | 368 |
| 362 bool GLSurfaceGLX::InitializeOneOff() { | 369 bool GLSurfaceGLX::InitializeOneOff() { |
| 363 static bool initialized = false; | 370 static bool initialized = false; |
| 364 if (initialized) | 371 if (initialized) |
| 365 return true; | 372 return true; |
| 366 | 373 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 392 HasGLXExtension("GLX_ARB_create_context_robustness"); | 399 HasGLXExtension("GLX_ARB_create_context_robustness"); |
| 393 g_glx_texture_from_pixmap_supported = | 400 g_glx_texture_from_pixmap_supported = |
| 394 HasGLXExtension("GLX_EXT_texture_from_pixmap"); | 401 HasGLXExtension("GLX_EXT_texture_from_pixmap"); |
| 395 g_glx_oml_sync_control_supported = | 402 g_glx_oml_sync_control_supported = |
| 396 HasGLXExtension("GLX_OML_sync_control"); | 403 HasGLXExtension("GLX_OML_sync_control"); |
| 397 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; | 404 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; |
| 398 g_glx_sgi_video_sync_supported = | 405 g_glx_sgi_video_sync_supported = |
| 399 HasGLXExtension("GLX_SGI_video_sync"); | 406 HasGLXExtension("GLX_SGI_video_sync"); |
| 400 | 407 |
| 401 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) | 408 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) |
| 402 SGIVideoSyncProviderThreadShim::g_display = XOpenDisplay(NULL); | 409 SGIVideoSyncProviderThreadShim::display_ = XOpenDisplay(NULL); |
| 403 | 410 |
| 404 initialized = true; | 411 initialized = true; |
| 405 return true; | 412 return true; |
| 406 } | 413 } |
| 407 | 414 |
| 408 // static | 415 // static |
| 409 const char* GLSurfaceGLX::GetGLXExtensions() { | 416 const char* GLSurfaceGLX::GetGLXExtensions() { |
| 410 return g_glx_extensions; | 417 return g_glx_extensions; |
| 411 } | 418 } |
| 412 | 419 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 669 | 676 |
| 670 void* PbufferGLSurfaceGLX::GetConfig() { | 677 void* PbufferGLSurfaceGLX::GetConfig() { |
| 671 return config_; | 678 return config_; |
| 672 } | 679 } |
| 673 | 680 |
| 674 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { | 681 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { |
| 675 Destroy(); | 682 Destroy(); |
| 676 } | 683 } |
| 677 | 684 |
| 678 } // namespace gfx | 685 } // namespace gfx |
| OLD | NEW |