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 |