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 |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/memory/weak_ptr.h" |
15 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
16 #include "base/process_util.h" | 17 #include "base/process_util.h" |
| 18 #include "base/synchronization/cancellation_flag.h" |
| 19 #include "base/synchronization/lock.h" |
| 20 #include "base/threading/non_thread_safe.h" |
| 21 #include "base/threading/thread.h" |
17 #include "base/time.h" | 22 #include "base/time.h" |
18 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | 23 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" |
19 #include "ui/base/x/x11_util.h" | 24 #include "ui/base/x/x11_util.h" |
20 #include "ui/gl/gl_bindings.h" | 25 #include "ui/gl/gl_bindings.h" |
21 #include "ui/gl/gl_implementation.h" | 26 #include "ui/gl/gl_implementation.h" |
22 | 27 |
23 namespace gfx { | 28 namespace gfx { |
24 | 29 |
25 namespace { | 30 namespace { |
26 | 31 |
(...skipping 11 matching lines...) Expand all Loading... |
38 const char* g_glx_extensions = NULL; | 43 const char* g_glx_extensions = NULL; |
39 bool g_glx_create_context_robustness_supported = false; | 44 bool g_glx_create_context_robustness_supported = false; |
40 bool g_glx_texture_from_pixmap_supported = false; | 45 bool g_glx_texture_from_pixmap_supported = false; |
41 bool g_glx_oml_sync_control_supported = false; | 46 bool g_glx_oml_sync_control_supported = false; |
42 | 47 |
43 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a | 48 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a |
44 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML | 49 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML |
45 // always fails even though GLX_OML_sync_control is reported as being supported. | 50 // always fails even though GLX_OML_sync_control is reported as being supported. |
46 bool g_glx_get_msc_rate_oml_supported = false; | 51 bool g_glx_get_msc_rate_oml_supported = false; |
47 | 52 |
| 53 bool g_glx_sgi_video_sync_supported = false; |
| 54 |
| 55 class OMLSyncControlVSyncProvider |
| 56 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider { |
| 57 public: |
| 58 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window) |
| 59 : window_(window) { |
| 60 } |
| 61 |
| 62 virtual ~OMLSyncControlVSyncProvider() { } |
| 63 |
| 64 virtual void GetVSyncParameters( |
| 65 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { |
| 66 base::TimeTicks timebase; |
| 67 base::TimeDelta interval; |
| 68 |
| 69 // The actual clock used for the system time returned by glXGetSyncValuesOML |
| 70 // is unspecified. In practice, the clock used is likely to be either |
| 71 // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the |
| 72 // current time according to both clocks, and assume that the returned time |
| 73 // was produced by the clock whose current time is closest to it, subject |
| 74 // to the restriction that the returned time must not be in the future |
| 75 // (since it is the time of a vblank that has already occurred). |
| 76 int64 system_time; |
| 77 int64 media_stream_counter; |
| 78 int64 swap_buffer_counter; |
| 79 if (!glXGetSyncValuesOML(g_display, window_, &system_time, |
| 80 &media_stream_counter, &swap_buffer_counter)) |
| 81 return; |
| 82 |
| 83 struct timespec real_time; |
| 84 struct timespec monotonic_time; |
| 85 clock_gettime(CLOCK_REALTIME, &real_time); |
| 86 clock_gettime(CLOCK_MONOTONIC, &monotonic_time); |
| 87 |
| 88 int64 real_time_in_microseconds = |
| 89 real_time.tv_sec * base::Time::kMicrosecondsPerSecond + |
| 90 real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; |
| 91 int64 monotonic_time_in_microseconds = |
| 92 monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond + |
| 93 monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; |
| 94 |
| 95 if ((system_time > real_time_in_microseconds) && |
| 96 (system_time > monotonic_time_in_microseconds)) |
| 97 return; |
| 98 |
| 99 // We need the time according to CLOCK_MONOTONIC, so if we've been given |
| 100 // a time from CLOCK_REALTIME, we need to convert. |
| 101 bool time_conversion_needed = |
| 102 (system_time > monotonic_time_in_microseconds) || |
| 103 (real_time_in_microseconds - system_time < |
| 104 monotonic_time_in_microseconds - system_time); |
| 105 |
| 106 if (time_conversion_needed) { |
| 107 int64 time_difference = |
| 108 real_time_in_microseconds - monotonic_time_in_microseconds; |
| 109 timebase = base::TimeTicks::FromInternalValue( |
| 110 system_time - time_difference); |
| 111 } else { |
| 112 timebase = base::TimeTicks::FromInternalValue(system_time); |
| 113 } |
| 114 |
| 115 // On platforms where glXGetMscRateOML doesn't work, we fall back to the |
| 116 // assumption that we're displaying 60 frames per second. |
| 117 const int64 kDefaultIntervalTime = |
| 118 base::Time::kMicrosecondsPerSecond / 60; |
| 119 int64 interval_time = kDefaultIntervalTime; |
| 120 int32 numerator; |
| 121 int32 denominator; |
| 122 if (g_glx_get_msc_rate_oml_supported) { |
| 123 if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { |
| 124 interval_time = |
| 125 (base::Time::kMicrosecondsPerSecond * denominator) / numerator; |
| 126 } else { |
| 127 // Once glXGetMscRateOML has been found to fail, don't try again, |
| 128 // since each failing call may spew an error message. |
| 129 g_glx_get_msc_rate_oml_supported = false; |
| 130 } |
| 131 } |
| 132 interval = base::TimeDelta::FromMicroseconds(interval_time); |
| 133 callback.Run(timebase, interval); |
| 134 } |
| 135 |
| 136 private: |
| 137 XID window_; |
| 138 |
| 139 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); |
| 140 }; |
| 141 |
| 142 class SGIVideoSyncThread |
| 143 : public base::Thread, |
| 144 public base::NonThreadSafe, |
| 145 public base::RefCounted<SGIVideoSyncThread> { |
| 146 public: |
| 147 static scoped_refptr<SGIVideoSyncThread> Create() { |
| 148 if (!g_video_sync_thread) { |
| 149 g_video_sync_thread = new SGIVideoSyncThread(); |
| 150 g_video_sync_thread->Start(); |
| 151 } |
| 152 return g_video_sync_thread; |
| 153 } |
| 154 |
| 155 private: |
| 156 friend class base::RefCounted<SGIVideoSyncThread>; |
| 157 |
| 158 SGIVideoSyncThread() : base::Thread("SGI_video_sync") { |
| 159 DCHECK(CalledOnValidThread()); |
| 160 } |
| 161 |
| 162 ~SGIVideoSyncThread() { |
| 163 DCHECK(CalledOnValidThread()); |
| 164 g_video_sync_thread = NULL; |
| 165 Stop(); |
| 166 } |
| 167 |
| 168 static SGIVideoSyncThread* g_video_sync_thread; |
| 169 |
| 170 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread); |
| 171 }; |
| 172 |
| 173 class SGIVideoSyncProviderThreadShim |
| 174 : public base::SupportsWeakPtr<SGIVideoSyncProviderThreadShim> { |
| 175 public: |
| 176 explicit SGIVideoSyncProviderThreadShim(XID window) |
| 177 : window_(window), |
| 178 context_(NULL), |
| 179 message_loop_(base::MessageLoopProxy::current()), |
| 180 cancel_vsync_flag_(), |
| 181 vsync_lock_() { |
| 182 // This ensures that creation of |window_| has occured when this shim |
| 183 // is executing in the same process as the call to create |window_|. |
| 184 XSync(::gfx::g_display, False); |
| 185 } |
| 186 |
| 187 base::CancellationFlag* cancel_vsync_flag() { |
| 188 return &cancel_vsync_flag_; |
| 189 } |
| 190 |
| 191 base::Lock* vsync_lock() { |
| 192 return &vsync_lock_; |
| 193 } |
| 194 |
| 195 void Initialize() { |
| 196 DCHECK(SGIVideoSyncProviderThreadShim::g_display); |
| 197 |
| 198 XWindowAttributes attributes; |
| 199 if (!XGetWindowAttributes(SGIVideoSyncProviderThreadShim::g_display, |
| 200 window_, &attributes)) { |
| 201 LOG(ERROR) << "XGetWindowAttributes failed for window " << |
| 202 window_ << "."; |
| 203 return; |
| 204 } |
| 205 |
| 206 XVisualInfo visual_info_template; |
| 207 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); |
| 208 |
| 209 int visual_info_count = 0; |
| 210 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( |
| 211 XGetVisualInfo(SGIVideoSyncProviderThreadShim::g_display, VisualIDMask, |
| 212 &visual_info_template, &visual_info_count)); |
| 213 |
| 214 DCHECK(visual_info_list.get()); |
| 215 if (visual_info_count == 0) { |
| 216 LOG(ERROR) << "No visual info for visual ID."; |
| 217 return; |
| 218 } |
| 219 |
| 220 context_ = glXCreateContext(SGIVideoSyncProviderThreadShim::g_display, |
| 221 visual_info_list.get(), |
| 222 NULL, |
| 223 True); |
| 224 |
| 225 DCHECK(NULL != context_); |
| 226 } |
| 227 |
| 228 void Destroy() { |
| 229 if (context_) { |
| 230 glXDestroyContext(SGIVideoSyncProviderThreadShim::g_display, context_); |
| 231 context_ = NULL; |
| 232 } |
| 233 delete this; |
| 234 } |
| 235 |
| 236 void GetVSyncParameters(const GLSurface::UpdateVSyncCallback& callback) { |
| 237 base::TimeTicks now; |
| 238 { |
| 239 // Don't allow |window_| destruction while we're probing vsync. |
| 240 base::AutoLock locked(vsync_lock_); |
| 241 |
| 242 if (!context_ || cancel_vsync_flag_.IsSet()) |
| 243 return; |
| 244 |
| 245 glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, |
| 246 window_, context_); |
| 247 |
| 248 unsigned int retrace_count = 0; |
| 249 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) |
| 250 return; |
| 251 |
| 252 TRACE_EVENT_INSTANT0("gpu", "vblank"); |
| 253 now = base::TimeTicks::HighResNow(); |
| 254 |
| 255 glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, 0, 0); |
| 256 } |
| 257 |
| 258 const int64 kDefaultIntervalTime = |
| 259 base::Time::kMicrosecondsPerSecond / 60; |
| 260 base::TimeDelta interval = |
| 261 base::TimeDelta::FromMicroseconds(kDefaultIntervalTime); |
| 262 |
| 263 message_loop_->PostTask(FROM_HERE, base::Bind(callback, now, interval)); |
| 264 } |
| 265 |
| 266 private: |
| 267 // For initialization of g_display in GLSurface::InitializeOneOff before |
| 268 // the sandbox goes up. |
| 269 friend class gfx::GLSurfaceGLX; |
| 270 |
| 271 virtual ~SGIVideoSyncProviderThreadShim() { |
| 272 } |
| 273 |
| 274 static Display* g_display; |
| 275 |
| 276 XID window_; |
| 277 GLXContext context_; |
| 278 |
| 279 scoped_refptr<base::MessageLoopProxy> message_loop_; |
| 280 |
| 281 base::CancellationFlag cancel_vsync_flag_; |
| 282 base::Lock vsync_lock_; |
| 283 |
| 284 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); |
| 285 }; |
| 286 |
| 287 class SGIVideoSyncVSyncProvider |
| 288 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider, |
| 289 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { |
| 290 public: |
| 291 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window) |
| 292 : vsync_thread_(SGIVideoSyncThread::Create()), |
| 293 shim_((new SGIVideoSyncProviderThreadShim(window))->AsWeakPtr()), |
| 294 cancel_vsync_flag_(shim_->cancel_vsync_flag()), |
| 295 vsync_lock_(shim_->vsync_lock()) { |
| 296 // The WeakPtr is bound to the SGIVideoSyncThread. We only use it for |
| 297 // PostTask. |
| 298 shim_->DetachFromThread(); |
| 299 vsync_thread_->message_loop()->PostTask( |
| 300 FROM_HERE, |
| 301 base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, shim_)); |
| 302 } |
| 303 |
| 304 virtual ~SGIVideoSyncVSyncProvider() { |
| 305 { |
| 306 base::AutoLock locked(*vsync_lock_); |
| 307 cancel_vsync_flag_->Set(); |
| 308 } |
| 309 vsync_thread_->message_loop()->PostTask( |
| 310 FROM_HERE, |
| 311 base::Bind(&SGIVideoSyncProviderThreadShim::Destroy, shim_)); |
| 312 } |
| 313 |
| 314 virtual void GetVSyncParameters( |
| 315 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { |
| 316 // Only one outstanding request per surface. |
| 317 if (!pending_callback_) { |
| 318 pending_callback_.reset(new GLSurface::UpdateVSyncCallback(callback)); |
| 319 vsync_thread_->message_loop()->PostTask( |
| 320 FROM_HERE, |
| 321 base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters, |
| 322 shim_, base::Bind( |
| 323 &SGIVideoSyncVSyncProvider::PendingCallbackRunner, |
| 324 AsWeakPtr()))); |
| 325 } |
| 326 } |
| 327 |
| 328 private: |
| 329 void PendingCallbackRunner(const base::TimeTicks timebase, |
| 330 const base::TimeDelta interval) { |
| 331 DCHECK(pending_callback_); |
| 332 pending_callback_->Run(timebase, interval); |
| 333 pending_callback_.reset(); |
| 334 } |
| 335 |
| 336 scoped_refptr<SGIVideoSyncThread> vsync_thread_; |
| 337 base::WeakPtr<SGIVideoSyncProviderThreadShim> shim_; |
| 338 |
| 339 scoped_ptr<GLSurface::UpdateVSyncCallback> pending_callback_; |
| 340 |
| 341 // Raw pointers to sync primitives owned by the shim_. |
| 342 // These will only be referenced before we post a task to destroy |
| 343 // the shim_, so they are safe to access. |
| 344 base::CancellationFlag* cancel_vsync_flag_; |
| 345 base::Lock* vsync_lock_; |
| 346 |
| 347 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); |
| 348 }; |
| 349 |
| 350 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; |
| 351 |
| 352 // In order to take advantage of GLX_SGI_video_sync, we need a display |
| 353 // for use on a separate thread. We must allocate this before the sandbox |
| 354 // goes up (rather than on-demand when we start the thread). |
| 355 Display* SGIVideoSyncProviderThreadShim::g_display = NULL; |
| 356 |
48 } // namespace | 357 } // namespace |
49 | 358 |
50 GLSurfaceGLX::GLSurfaceGLX() {} | 359 GLSurfaceGLX::GLSurfaceGLX() {} |
51 | 360 |
52 bool GLSurfaceGLX::InitializeOneOff() { | 361 bool GLSurfaceGLX::InitializeOneOff() { |
53 static bool initialized = false; | 362 static bool initialized = false; |
54 if (initialized) | 363 if (initialized) |
55 return true; | 364 return true; |
56 | 365 |
| 366 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on |
| 367 // it's own thread. |
| 368 XInitThreads(); |
| 369 |
57 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); | 370 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
58 if (!g_display) { | 371 if (!g_display) { |
59 LOG(ERROR) << "XOpenDisplay failed."; | 372 LOG(ERROR) << "XOpenDisplay failed."; |
60 return false; | 373 return false; |
61 } | 374 } |
62 | 375 |
63 int major, minor; | 376 int major, minor; |
64 if (!glXQueryVersion(g_display, &major, &minor)) { | 377 if (!glXQueryVersion(g_display, &major, &minor)) { |
65 LOG(ERROR) << "glxQueryVersion failed"; | 378 LOG(ERROR) << "glxQueryVersion failed"; |
66 return false; | 379 return false; |
67 } | 380 } |
68 | 381 |
69 if (major == 1 && minor < 3) { | 382 if (major == 1 && minor < 3) { |
70 LOG(ERROR) << "GLX 1.3 or later is required."; | 383 LOG(ERROR) << "GLX 1.3 or later is required."; |
71 return false; | 384 return false; |
72 } | 385 } |
73 | 386 |
74 g_glx_extensions = glXQueryExtensionsString(g_display, 0); | 387 g_glx_extensions = glXQueryExtensionsString(g_display, 0); |
75 g_glx_create_context_robustness_supported = | 388 g_glx_create_context_robustness_supported = |
76 HasGLXExtension("GLX_ARB_create_context_robustness"); | 389 HasGLXExtension("GLX_ARB_create_context_robustness"); |
77 g_glx_texture_from_pixmap_supported = | 390 g_glx_texture_from_pixmap_supported = |
78 HasGLXExtension("GLX_EXT_texture_from_pixmap"); | 391 HasGLXExtension("GLX_EXT_texture_from_pixmap"); |
79 g_glx_oml_sync_control_supported = | 392 g_glx_oml_sync_control_supported = |
80 HasGLXExtension("GLX_OML_sync_control"); | 393 HasGLXExtension("GLX_OML_sync_control"); |
81 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; | 394 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; |
| 395 g_glx_sgi_video_sync_supported = |
| 396 HasGLXExtension("GLX_SGI_video_sync"); |
82 | 397 |
| 398 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) |
| 399 SGIVideoSyncProviderThreadShim::g_display = XOpenDisplay(NULL); |
83 | 400 |
84 initialized = true; | 401 initialized = true; |
85 return true; | 402 return true; |
86 } | 403 } |
87 | 404 |
88 // static | 405 // static |
89 const char* GLSurfaceGLX::GetGLXExtensions() { | 406 const char* GLSurfaceGLX::GetGLXExtensions() { |
90 return g_glx_extensions; | 407 return g_glx_extensions; |
91 } | 408 } |
92 | 409 |
(...skipping 28 matching lines...) Expand all Loading... |
121 config_(NULL) { | 438 config_(NULL) { |
122 } | 439 } |
123 | 440 |
124 bool NativeViewGLSurfaceGLX::Initialize() { | 441 bool NativeViewGLSurfaceGLX::Initialize() { |
125 XWindowAttributes attributes; | 442 XWindowAttributes attributes; |
126 if (!XGetWindowAttributes(g_display, window_, &attributes)) { | 443 if (!XGetWindowAttributes(g_display, window_, &attributes)) { |
127 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; | 444 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; |
128 return false; | 445 return false; |
129 } | 446 } |
130 size_ = gfx::Size(attributes.width, attributes.height); | 447 size_ = gfx::Size(attributes.width, attributes.height); |
| 448 |
| 449 if (g_glx_oml_sync_control_supported) |
| 450 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_)); |
| 451 else if (g_glx_sgi_video_sync_supported) |
| 452 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_)); |
| 453 |
131 return true; | 454 return true; |
132 } | 455 } |
133 | 456 |
134 void NativeViewGLSurfaceGLX::Destroy() { | 457 void NativeViewGLSurfaceGLX::Destroy() { |
135 } | 458 } |
136 | 459 |
137 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { | 460 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { |
138 // On Intel drivers, the frame buffer won't be resize until the next swap. If | 461 // On Intel drivers, the frame buffer won't be resize until the next swap. If |
139 // we only do PostSubBuffer, then we're stuck in the old size. Force a swap | 462 // we only do PostSubBuffer, then we're stuck in the old size. Force a swap |
140 // now. | 463 // now. |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 return config_; | 556 return config_; |
234 } | 557 } |
235 | 558 |
236 bool NativeViewGLSurfaceGLX::PostSubBuffer( | 559 bool NativeViewGLSurfaceGLX::PostSubBuffer( |
237 int x, int y, int width, int height) { | 560 int x, int y, int width, int height) { |
238 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); | 561 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); |
239 glXCopySubBufferMESA(g_display, window_, x, y, width, height); | 562 glXCopySubBufferMESA(g_display, window_, x, y, width, height); |
240 return true; | 563 return true; |
241 } | 564 } |
242 | 565 |
243 bool NativeViewGLSurfaceGLX::GetVSyncParameters(base::TimeTicks* timebase, | 566 void NativeViewGLSurfaceGLX::GetVSyncParameters( |
244 base::TimeDelta* interval) { | 567 const UpdateVSyncCallback& callback) { |
245 if (!g_glx_oml_sync_control_supported) | 568 if (vsync_provider_) |
246 return false; | 569 vsync_provider_->GetVSyncParameters(callback); |
247 | |
248 // The actual clock used for the system time returned by glXGetSyncValuesOML | |
249 // is unspecified. In practice, the clock used is likely to be either | |
250 // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the | |
251 // current time according to both clocks, and assume that the returned time | |
252 // was produced by the clock whose current time is closest to it, subject | |
253 // to the restriction that the returned time must not be in the future (since | |
254 // it is the time of a vblank that has already occurred). | |
255 int64 system_time; | |
256 int64 media_stream_counter; | |
257 int64 swap_buffer_counter; | |
258 if (!glXGetSyncValuesOML(g_display, window_, &system_time, | |
259 &media_stream_counter, &swap_buffer_counter)) | |
260 return false; | |
261 | |
262 struct timespec real_time; | |
263 struct timespec monotonic_time; | |
264 clock_gettime(CLOCK_REALTIME, &real_time); | |
265 clock_gettime(CLOCK_MONOTONIC, &monotonic_time); | |
266 | |
267 int64 real_time_in_microseconds = | |
268 real_time.tv_sec * base::Time::kMicrosecondsPerSecond + | |
269 real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; | |
270 int64 monotonic_time_in_microseconds = | |
271 monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond + | |
272 monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; | |
273 | |
274 if ((system_time > real_time_in_microseconds) && | |
275 (system_time > monotonic_time_in_microseconds)) | |
276 return false; | |
277 | |
278 // We need the time according to CLOCK_MONOTONIC, so if we've been given | |
279 // a time from CLOCK_REALTIME, we need to convert. | |
280 bool time_conversion_needed = | |
281 (system_time > monotonic_time_in_microseconds) || | |
282 (real_time_in_microseconds - system_time < | |
283 monotonic_time_in_microseconds - system_time); | |
284 | |
285 if (time_conversion_needed) { | |
286 int64 time_difference = | |
287 real_time_in_microseconds - monotonic_time_in_microseconds; | |
288 *timebase = base::TimeTicks::FromInternalValue( | |
289 system_time - time_difference); | |
290 } else { | |
291 *timebase = base::TimeTicks::FromInternalValue(system_time); | |
292 } | |
293 | |
294 // On platforms where glXGetMscRateOML doesn't work, we fall back to the | |
295 // assumption that we're displaying 60 frames per second. | |
296 const int64 kDefaultIntervalTime = | |
297 base::Time::kMicrosecondsPerSecond / 60; | |
298 int64 interval_time = kDefaultIntervalTime; | |
299 int32 numerator; | |
300 int32 denominator; | |
301 if (g_glx_get_msc_rate_oml_supported) { | |
302 if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { | |
303 interval_time = | |
304 (base::Time::kMicrosecondsPerSecond * denominator) / numerator; | |
305 } else { | |
306 // Once glXGetMscRateOML has been found to fail, don't try again, | |
307 // since each failing call may spew an error message. | |
308 g_glx_get_msc_rate_oml_supported = false; | |
309 } | |
310 } | |
311 | |
312 *interval = base::TimeDelta::FromMicroseconds(interval_time); | |
313 return true; | |
314 } | 570 } |
315 | 571 |
316 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() | 572 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() |
317 : window_(0), | 573 : window_(0), |
318 config_(NULL) { | 574 config_(NULL) { |
319 } | 575 } |
320 | 576 |
321 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { | 577 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { |
322 Destroy(); | 578 Destroy(); |
323 } | 579 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 | 661 |
406 void* PbufferGLSurfaceGLX::GetConfig() { | 662 void* PbufferGLSurfaceGLX::GetConfig() { |
407 return config_; | 663 return config_; |
408 } | 664 } |
409 | 665 |
410 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { | 666 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { |
411 Destroy(); | 667 Destroy(); |
412 } | 668 } |
413 | 669 |
414 } // namespace gfx | 670 } // namespace gfx |
OLD | NEW |