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