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