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 |
| 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/threading/non_thread_safe.h" | |
| 19 #include "base/threading/thread.h" | |
| 17 #include "base/time.h" | 20 #include "base/time.h" |
| 18 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | 21 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" |
| 19 #include "ui/base/x/x11_util.h" | 22 #include "ui/base/x/x11_util.h" |
| 20 #include "ui/gl/gl_bindings.h" | 23 #include "ui/gl/gl_bindings.h" |
| 21 #include "ui/gl/gl_implementation.h" | 24 #include "ui/gl/gl_implementation.h" |
| 22 | 25 |
| 23 namespace gfx { | 26 namespace gfx { |
| 24 | 27 |
| 25 namespace { | 28 namespace { |
| 26 | 29 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 38 const char* g_glx_extensions = NULL; | 41 const char* g_glx_extensions = NULL; |
| 39 bool g_glx_create_context_robustness_supported = false; | 42 bool g_glx_create_context_robustness_supported = false; |
| 40 bool g_glx_texture_from_pixmap_supported = false; | 43 bool g_glx_texture_from_pixmap_supported = false; |
| 41 bool g_glx_oml_sync_control_supported = false; | 44 bool g_glx_oml_sync_control_supported = false; |
| 42 | 45 |
| 43 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a | 46 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a |
| 44 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML | 47 // 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. | 48 // always fails even though GLX_OML_sync_control is reported as being supported. |
| 46 bool g_glx_get_msc_rate_oml_supported = false; | 49 bool g_glx_get_msc_rate_oml_supported = false; |
| 47 | 50 |
| 51 bool g_glx_sgi_video_sync_supported = false; | |
| 52 | |
| 53 class OMLSyncControlVSyncProvider | |
| 54 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider { | |
| 55 public: | |
| 56 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window) | |
| 57 : window_(window) { | |
| 58 } | |
| 59 | |
| 60 virtual ~OMLSyncControlVSyncProvider() { } | |
| 61 | |
| 62 virtual void GetVSyncParameters( | |
| 63 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { | |
| 64 base::TimeTicks timebase; | |
| 65 base::TimeDelta interval; | |
| 66 | |
| 67 // The actual clock used for the system time returned by glXGetSyncValuesOML | |
| 68 // is unspecified. In practice, the clock used is likely to be either | |
| 69 // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the | |
| 70 // current time according to both clocks, and assume that the returned time | |
| 71 // was produced by the clock whose current time is closest to it, subject | |
| 72 // to the restriction that the returned time must not be in the future | |
| 73 // (since it is the time of a vblank that has already occurred). | |
| 74 int64 system_time; | |
| 75 int64 media_stream_counter; | |
| 76 int64 swap_buffer_counter; | |
| 77 if (!glXGetSyncValuesOML(g_display, window_, &system_time, | |
| 78 &media_stream_counter, &swap_buffer_counter)) | |
| 79 return; | |
| 80 | |
| 81 struct timespec real_time; | |
| 82 struct timespec monotonic_time; | |
| 83 clock_gettime(CLOCK_REALTIME, &real_time); | |
| 84 clock_gettime(CLOCK_MONOTONIC, &monotonic_time); | |
| 85 | |
| 86 int64 real_time_in_microseconds = | |
| 87 real_time.tv_sec * base::Time::kMicrosecondsPerSecond + | |
| 88 real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; | |
| 89 int64 monotonic_time_in_microseconds = | |
| 90 monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond + | |
| 91 monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; | |
| 92 | |
| 93 if ((system_time > real_time_in_microseconds) && | |
| 94 (system_time > monotonic_time_in_microseconds)) | |
| 95 return; | |
| 96 | |
| 97 // We need the time according to CLOCK_MONOTONIC, so if we've been given | |
| 98 // a time from CLOCK_REALTIME, we need to convert. | |
| 99 bool time_conversion_needed = | |
| 100 (system_time > monotonic_time_in_microseconds) || | |
| 101 (real_time_in_microseconds - system_time < | |
| 102 monotonic_time_in_microseconds - system_time); | |
| 103 | |
| 104 if (time_conversion_needed) { | |
| 105 int64 time_difference = | |
| 106 real_time_in_microseconds - monotonic_time_in_microseconds; | |
| 107 timebase = base::TimeTicks::FromInternalValue( | |
| 108 system_time - time_difference); | |
| 109 } else { | |
| 110 timebase = base::TimeTicks::FromInternalValue(system_time); | |
| 111 } | |
| 112 | |
| 113 // On platforms where glXGetMscRateOML doesn't work, we fall back to the | |
| 114 // assumption that we're displaying 60 frames per second. | |
| 115 const int64 kDefaultIntervalTime = | |
| 116 base::Time::kMicrosecondsPerSecond / 60; | |
| 117 int64 interval_time = kDefaultIntervalTime; | |
| 118 int32 numerator; | |
| 119 int32 denominator; | |
| 120 if (g_glx_get_msc_rate_oml_supported) { | |
| 121 if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { | |
| 122 interval_time = | |
| 123 (base::Time::kMicrosecondsPerSecond * denominator) / numerator; | |
| 124 } else { | |
| 125 // Once glXGetMscRateOML has been found to fail, don't try again, | |
| 126 // since each failing call may spew an error message. | |
| 127 g_glx_get_msc_rate_oml_supported = false; | |
| 128 } | |
| 129 } | |
| 130 interval = base::TimeDelta::FromMicroseconds(interval_time); | |
| 131 callback.Run(timebase, interval); | |
| 132 } | |
| 133 | |
| 134 private: | |
| 135 XID window_; | |
| 136 | |
| 137 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); | |
| 138 }; | |
| 139 | |
| 140 class SGIVideoSyncThread | |
| 141 : public base::Thread, | |
| 142 public base::NonThreadSafe, | |
| 143 public base::RefCounted<SGIVideoSyncThread> { | |
| 144 public: | |
| 145 static scoped_refptr<SGIVideoSyncThread> Create() { | |
| 146 if (!g_video_sync_thread) { | |
| 147 g_video_sync_thread = new SGIVideoSyncThread(); | |
| 148 g_video_sync_thread->Start(); | |
| 149 } | |
| 150 return g_video_sync_thread; | |
| 151 } | |
| 152 | |
| 153 ~SGIVideoSyncThread() { | |
| 154 DCHECK(CalledOnValidThread()); | |
| 155 g_video_sync_thread = NULL; | |
| 156 Stop(); | |
| 157 } | |
| 158 | |
| 159 private: | |
| 160 friend class base::RefCounted<SGIVideoSyncThread>; | |
| 161 | |
| 162 SGIVideoSyncThread() : base::Thread("SGI_video_sync") { | |
| 163 DCHECK(CalledOnValidThread()); | |
| 164 } | |
| 165 | |
| 166 static SGIVideoSyncThread* g_video_sync_thread; | |
| 167 | |
| 168 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread); | |
| 169 }; | |
| 170 | |
| 171 class SGIVideoSyncProviderThreadShim | |
| 172 : public base::SupportsWeakPtr<SGIVideoSyncProviderThreadShim> { | |
| 173 public: | |
| 174 explicit SGIVideoSyncProviderThreadShim(XID window) | |
| 175 : window_(window), | |
| 176 context_(NULL), | |
| 177 message_loop_(base::MessageLoopProxy::current()) { | |
| 178 } | |
| 179 | |
| 180 void Initialize() { | |
| 181 DCHECK(SGIVideoSyncProviderThreadShim::g_display); | |
| 182 | |
| 183 XWindowAttributes attributes; | |
| 184 if (!XGetWindowAttributes(SGIVideoSyncProviderThreadShim::g_display, | |
| 185 window_, &attributes)) { | |
|
piman
2012/11/08 23:51:16
It makes me somewhat uncomfortable to use the wind
jonathan.backer
2012/11/09 17:02:35
FWIW, this is not much worse than the current situ
piman
2012/11/09 18:08:05
On Aura we have a round trip to X right after we c
| |
| 186 LOG(ERROR) << "XGetWindowAttributes failed for window " << | |
| 187 window_ << "."; | |
| 188 return; | |
| 189 } | |
| 190 | |
| 191 XVisualInfo visual_info_template; | |
| 192 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); | |
| 193 | |
| 194 int visual_info_count = 0; | |
| 195 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( | |
| 196 XGetVisualInfo(SGIVideoSyncProviderThreadShim::g_display, VisualIDMask, | |
| 197 &visual_info_template, &visual_info_count)); | |
| 198 | |
| 199 DCHECK(visual_info_list.get()); | |
| 200 if (visual_info_count == 0) { | |
| 201 LOG(ERROR) << "No visual info for visual ID."; | |
| 202 return; | |
| 203 } | |
| 204 | |
| 205 context_ = glXCreateContext(SGIVideoSyncProviderThreadShim::g_display, | |
| 206 visual_info_list.get(), | |
| 207 NULL, | |
| 208 True); | |
| 209 | |
| 210 DCHECK(NULL != context_); | |
| 211 } | |
| 212 | |
| 213 void Destroy() { | |
| 214 if (context_) { | |
| 215 glXDestroyContext(SGIVideoSyncProviderThreadShim::g_display, context_); | |
| 216 context_ = NULL; | |
| 217 } | |
| 218 delete this; | |
| 219 } | |
| 220 | |
| 221 void GetVSyncParameters(const GLSurface::UpdateVSyncCallback& callback) { | |
| 222 if (!context_) | |
| 223 return; | |
| 224 | |
| 225 glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, | |
| 226 window_, context_); | |
|
piman
2012/11/08 23:51:16
How do we know that the window hasn't been destroy
jonathan.backer
2012/11/09 17:02:35
Good point. I've added a cancellation flag and a l
| |
| 227 | |
| 228 unsigned int retrace_count = 0; | |
| 229 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) | |
| 230 return; | |
| 231 | |
| 232 TRACE_EVENT_INSTANT0("gpu", "vblank"); | |
| 233 base::TimeTicks now = base::TimeTicks::HighResNow(); | |
| 234 | |
| 235 const int64 kDefaultIntervalTime = | |
| 236 base::Time::kMicrosecondsPerSecond / 60; | |
| 237 base::TimeDelta interval = | |
| 238 base::TimeDelta::FromMicroseconds(kDefaultIntervalTime); | |
| 239 | |
| 240 message_loop_->PostTask(FROM_HERE, base::Bind(callback, now, interval)); | |
| 241 } | |
| 242 | |
| 243 private: | |
| 244 // For initialization of g_display in GLSurface::InitializeOneOff before | |
| 245 // the sandbox goes up. | |
| 246 friend class gfx::GLSurfaceGLX; | |
| 247 | |
| 248 virtual ~SGIVideoSyncProviderThreadShim() { | |
| 249 } | |
| 250 | |
| 251 static Display* g_display; | |
| 252 | |
| 253 XID window_; | |
| 254 GLXContext context_; | |
| 255 | |
| 256 scoped_refptr<base::MessageLoopProxy> message_loop_; | |
| 257 | |
| 258 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); | |
| 259 }; | |
| 260 | |
| 261 class SGIVideoSyncVSyncProvider | |
| 262 : public gfx::NativeViewGLSurfaceGLX::VSyncProvider, | |
| 263 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { | |
| 264 public: | |
| 265 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window) | |
| 266 : vsync_thread_(SGIVideoSyncThread::Create()), | |
| 267 shim_((new SGIVideoSyncProviderThreadShim(window))->AsWeakPtr()) { | |
| 268 // The WeakPtr is bound to the SGIVideoSyncThread. We only use it for | |
| 269 // PostTask. | |
| 270 shim_->DetachFromThread(); | |
| 271 vsync_thread_->message_loop()->PostTask( | |
| 272 FROM_HERE, | |
| 273 base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, shim_)); | |
| 274 } | |
| 275 | |
| 276 virtual ~SGIVideoSyncVSyncProvider() { | |
| 277 vsync_thread_->message_loop()->PostTask( | |
| 278 FROM_HERE, | |
| 279 base::Bind(&SGIVideoSyncProviderThreadShim::Destroy, shim_)); | |
| 280 } | |
| 281 | |
| 282 virtual void GetVSyncParameters( | |
| 283 const GLSurface::UpdateVSyncCallback& callback) OVERRIDE { | |
| 284 // Only one outstanding request per surface. | |
| 285 if (!pending_callback_) { | |
| 286 pending_callback_.reset(new GLSurface::UpdateVSyncCallback(callback)); | |
| 287 vsync_thread_->message_loop()->PostTask( | |
| 288 FROM_HERE, | |
| 289 base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters, | |
| 290 shim_, base::Bind( | |
| 291 &SGIVideoSyncVSyncProvider::PendingCallbackRunner, | |
| 292 AsWeakPtr()))); | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 private: | |
| 297 void PendingCallbackRunner(const base::TimeTicks timebase, | |
| 298 const base::TimeDelta interval) { | |
| 299 DCHECK(pending_callback_); | |
| 300 pending_callback_->Run(timebase, interval); | |
| 301 pending_callback_.reset(); | |
| 302 } | |
| 303 | |
| 304 scoped_refptr<SGIVideoSyncThread> vsync_thread_; | |
| 305 base::WeakPtr<SGIVideoSyncProviderThreadShim> shim_; | |
| 306 | |
| 307 scoped_ptr<GLSurface::UpdateVSyncCallback> pending_callback_; | |
| 308 | |
| 309 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); | |
| 310 }; | |
| 311 | |
| 312 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; | |
| 313 | |
| 314 // In order to take advantage of GLX_SGI_video_sync, we need a display | |
| 315 // for use on a separate thread. We must allocate this before the sandbox | |
| 316 // goes up (rather than on-demand when we start the thread). | |
| 317 Display* SGIVideoSyncProviderThreadShim::g_display = NULL; | |
| 318 | |
| 48 } // namespace | 319 } // namespace |
| 49 | 320 |
| 50 GLSurfaceGLX::GLSurfaceGLX() {} | 321 GLSurfaceGLX::GLSurfaceGLX() {} |
| 51 | 322 |
| 52 bool GLSurfaceGLX::InitializeOneOff() { | 323 bool GLSurfaceGLX::InitializeOneOff() { |
| 53 static bool initialized = false; | 324 static bool initialized = false; |
| 54 if (initialized) | 325 if (initialized) |
| 55 return true; | 326 return true; |
| 56 | 327 |
| 57 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); | 328 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 72 } | 343 } |
| 73 | 344 |
| 74 g_glx_extensions = glXQueryExtensionsString(g_display, 0); | 345 g_glx_extensions = glXQueryExtensionsString(g_display, 0); |
| 75 g_glx_create_context_robustness_supported = | 346 g_glx_create_context_robustness_supported = |
| 76 HasGLXExtension("GLX_ARB_create_context_robustness"); | 347 HasGLXExtension("GLX_ARB_create_context_robustness"); |
| 77 g_glx_texture_from_pixmap_supported = | 348 g_glx_texture_from_pixmap_supported = |
| 78 HasGLXExtension("GLX_EXT_texture_from_pixmap"); | 349 HasGLXExtension("GLX_EXT_texture_from_pixmap"); |
| 79 g_glx_oml_sync_control_supported = | 350 g_glx_oml_sync_control_supported = |
| 80 HasGLXExtension("GLX_OML_sync_control"); | 351 HasGLXExtension("GLX_OML_sync_control"); |
| 81 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; | 352 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; |
| 353 g_glx_sgi_video_sync_supported = | |
| 354 HasGLXExtension("GLX_SGI_video_sync"); | |
| 82 | 355 |
| 356 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) | |
| 357 SGIVideoSyncProviderThreadShim::g_display = XOpenDisplay(NULL); | |
| 83 | 358 |
| 84 initialized = true; | 359 initialized = true; |
| 85 return true; | 360 return true; |
| 86 } | 361 } |
| 87 | 362 |
| 88 // static | 363 // static |
| 89 const char* GLSurfaceGLX::GetGLXExtensions() { | 364 const char* GLSurfaceGLX::GetGLXExtensions() { |
| 90 return g_glx_extensions; | 365 return g_glx_extensions; |
| 91 } | 366 } |
| 92 | 367 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 112 | 387 |
| 113 void* GLSurfaceGLX::GetDisplay() { | 388 void* GLSurfaceGLX::GetDisplay() { |
| 114 return g_display; | 389 return g_display; |
| 115 } | 390 } |
| 116 | 391 |
| 117 GLSurfaceGLX::~GLSurfaceGLX() {} | 392 GLSurfaceGLX::~GLSurfaceGLX() {} |
| 118 | 393 |
| 119 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) | 394 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
| 120 : window_(window), | 395 : window_(window), |
| 121 config_(NULL) { | 396 config_(NULL) { |
| 397 if (g_glx_oml_sync_control_supported) | |
| 398 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_)); | |
| 399 else if (g_glx_sgi_video_sync_supported) | |
| 400 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_)); | |
| 122 } | 401 } |
| 123 | 402 |
| 124 bool NativeViewGLSurfaceGLX::Initialize() { | 403 bool NativeViewGLSurfaceGLX::Initialize() { |
| 125 XWindowAttributes attributes; | 404 XWindowAttributes attributes; |
| 126 if (!XGetWindowAttributes(g_display, window_, &attributes)) { | 405 if (!XGetWindowAttributes(g_display, window_, &attributes)) { |
| 127 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; | 406 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; |
| 128 return false; | 407 return false; |
| 129 } | 408 } |
| 130 size_ = gfx::Size(attributes.width, attributes.height); | 409 size_ = gfx::Size(attributes.width, attributes.height); |
| 131 return true; | 410 return true; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 return config_; | 512 return config_; |
| 234 } | 513 } |
| 235 | 514 |
| 236 bool NativeViewGLSurfaceGLX::PostSubBuffer( | 515 bool NativeViewGLSurfaceGLX::PostSubBuffer( |
| 237 int x, int y, int width, int height) { | 516 int x, int y, int width, int height) { |
| 238 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); | 517 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); |
| 239 glXCopySubBufferMESA(g_display, window_, x, y, width, height); | 518 glXCopySubBufferMESA(g_display, window_, x, y, width, height); |
| 240 return true; | 519 return true; |
| 241 } | 520 } |
| 242 | 521 |
| 243 bool NativeViewGLSurfaceGLX::GetVSyncParameters(base::TimeTicks* timebase, | 522 void NativeViewGLSurfaceGLX::GetVSyncParameters( |
| 244 base::TimeDelta* interval) { | 523 const UpdateVSyncCallback& callback) { |
| 245 if (!g_glx_oml_sync_control_supported) | 524 if (vsync_provider_) |
| 246 return false; | 525 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 } | 526 } |
| 315 | 527 |
| 316 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() | 528 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() |
| 317 : window_(0), | 529 : window_(0), |
| 318 config_(NULL) { | 530 config_(NULL) { |
| 319 } | 531 } |
| 320 | 532 |
| 321 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { | 533 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { |
| 322 Destroy(); | 534 Destroy(); |
| 323 } | 535 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 | 617 |
| 406 void* PbufferGLSurfaceGLX::GetConfig() { | 618 void* PbufferGLSurfaceGLX::GetConfig() { |
| 407 return config_; | 619 return config_; |
| 408 } | 620 } |
| 409 | 621 |
| 410 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { | 622 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { |
| 411 Destroy(); | 623 Destroy(); |
| 412 } | 624 } |
| 413 | 625 |
| 414 } // namespace gfx | 626 } // namespace gfx |
| OLD | NEW |