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/message_loop.h" | 15 #include "base/message_loop.h" |
16 #include "base/process_util.h" | 16 #include "base/process_util.h" |
| 17 #include "base/time.h" |
17 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | 18 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" |
18 #include "ui/base/x/x11_util.h" | 19 #include "ui/base/x/x11_util.h" |
19 #include "ui/gl/gl_bindings.h" | 20 #include "ui/gl/gl_bindings.h" |
20 #include "ui/gl/gl_implementation.h" | 21 #include "ui/gl/gl_implementation.h" |
21 | 22 |
22 namespace gfx { | 23 namespace gfx { |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 // scoped_ptr functor for XFree(). Use as follows: | 27 // scoped_ptr functor for XFree(). Use as follows: |
27 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); | 28 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); |
28 // where "XVisualInfo" is any X type that is freed with XFree. | 29 // where "XVisualInfo" is any X type that is freed with XFree. |
29 class ScopedPtrXFree { | 30 class ScopedPtrXFree { |
30 public: | 31 public: |
31 void operator()(void* x) const { | 32 void operator()(void* x) const { |
32 ::XFree(x); | 33 ::XFree(x); |
33 } | 34 } |
34 }; | 35 }; |
35 | 36 |
36 Display* g_display; | 37 Display* g_display; |
37 const char* g_glx_extensions = NULL; | 38 const char* g_glx_extensions = NULL; |
38 bool g_glx_create_context_robustness_supported = false; | 39 bool g_glx_create_context_robustness_supported = false; |
39 bool g_glx_texture_from_pixmap_supported = false; | 40 bool g_glx_texture_from_pixmap_supported = false; |
| 41 bool g_glx_oml_sync_control_supported = false; |
| 42 |
| 43 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a |
| 44 // 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. |
| 46 bool g_glx_get_msc_rate_oml_supported = false; |
40 | 47 |
41 } // namespace | 48 } // namespace |
42 | 49 |
43 GLSurfaceGLX::GLSurfaceGLX() {} | 50 GLSurfaceGLX::GLSurfaceGLX() {} |
44 | 51 |
45 bool GLSurfaceGLX::InitializeOneOff() { | 52 bool GLSurfaceGLX::InitializeOneOff() { |
46 static bool initialized = false; | 53 static bool initialized = false; |
47 if (initialized) | 54 if (initialized) |
48 return true; | 55 return true; |
49 | 56 |
(...skipping 12 matching lines...) Expand all Loading... |
62 if (major == 1 && minor < 3) { | 69 if (major == 1 && minor < 3) { |
63 LOG(ERROR) << "GLX 1.3 or later is required."; | 70 LOG(ERROR) << "GLX 1.3 or later is required."; |
64 return false; | 71 return false; |
65 } | 72 } |
66 | 73 |
67 g_glx_extensions = glXQueryExtensionsString(g_display, 0); | 74 g_glx_extensions = glXQueryExtensionsString(g_display, 0); |
68 g_glx_create_context_robustness_supported = | 75 g_glx_create_context_robustness_supported = |
69 HasGLXExtension("GLX_ARB_create_context_robustness"); | 76 HasGLXExtension("GLX_ARB_create_context_robustness"); |
70 g_glx_texture_from_pixmap_supported = | 77 g_glx_texture_from_pixmap_supported = |
71 HasGLXExtension("GLX_EXT_texture_from_pixmap"); | 78 HasGLXExtension("GLX_EXT_texture_from_pixmap"); |
| 79 g_glx_oml_sync_control_supported = |
| 80 HasGLXExtension("GLX_OML_sync_control"); |
| 81 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; |
| 82 |
72 | 83 |
73 initialized = true; | 84 initialized = true; |
74 return true; | 85 return true; |
75 } | 86 } |
76 | 87 |
77 // static | 88 // static |
78 const char* GLSurfaceGLX::GetGLXExtensions() { | 89 const char* GLSurfaceGLX::GetGLXExtensions() { |
79 return g_glx_extensions; | 90 return g_glx_extensions; |
80 } | 91 } |
81 | 92 |
82 // static | 93 // static |
83 bool GLSurfaceGLX::HasGLXExtension(const char* name) { | 94 bool GLSurfaceGLX::HasGLXExtension(const char* name) { |
84 return ExtensionsContain(GetGLXExtensions(), name); | 95 return ExtensionsContain(GetGLXExtensions(), name); |
85 } | 96 } |
86 | 97 |
87 // static | 98 // static |
88 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { | 99 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { |
89 return g_glx_create_context_robustness_supported; | 100 return g_glx_create_context_robustness_supported; |
90 } | 101 } |
91 | 102 |
92 // static | 103 // static |
93 bool GLSurfaceGLX::IsTextureFromPixmapSupported() { | 104 bool GLSurfaceGLX::IsTextureFromPixmapSupported() { |
94 return g_glx_texture_from_pixmap_supported; | 105 return g_glx_texture_from_pixmap_supported; |
95 } | 106 } |
96 | 107 |
| 108 // static |
| 109 bool GLSurfaceGLX::IsOMLSyncControlSupported() { |
| 110 return g_glx_oml_sync_control_supported; |
| 111 } |
| 112 |
97 void* GLSurfaceGLX::GetDisplay() { | 113 void* GLSurfaceGLX::GetDisplay() { |
98 return g_display; | 114 return g_display; |
99 } | 115 } |
100 | 116 |
101 GLSurfaceGLX::~GLSurfaceGLX() {} | 117 GLSurfaceGLX::~GLSurfaceGLX() {} |
102 | 118 |
103 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) | 119 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
104 : window_(window), | 120 : window_(window), |
105 config_(NULL) { | 121 config_(NULL) { |
106 } | 122 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 return config_; | 233 return config_; |
218 } | 234 } |
219 | 235 |
220 bool NativeViewGLSurfaceGLX::PostSubBuffer( | 236 bool NativeViewGLSurfaceGLX::PostSubBuffer( |
221 int x, int y, int width, int height) { | 237 int x, int y, int width, int height) { |
222 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); | 238 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); |
223 glXCopySubBufferMESA(g_display, window_, x, y, width, height); | 239 glXCopySubBufferMESA(g_display, window_, x, y, width, height); |
224 return true; | 240 return true; |
225 } | 241 } |
226 | 242 |
| 243 bool NativeViewGLSurfaceGLX::GetVSyncParameters(base::TimeTicks* timebase, |
| 244 base::TimeDelta* interval) { |
| 245 if (!g_glx_oml_sync_control_supported) |
| 246 return false; |
| 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 } |
| 315 |
227 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() | 316 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() |
228 : window_(0), | 317 : window_(0), |
229 config_(NULL) { | 318 config_(NULL) { |
230 } | 319 } |
231 | 320 |
232 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { | 321 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { |
233 Destroy(); | 322 Destroy(); |
234 } | 323 } |
235 | 324 |
236 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) | 325 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 405 |
317 void* PbufferGLSurfaceGLX::GetConfig() { | 406 void* PbufferGLSurfaceGLX::GetConfig() { |
318 return config_; | 407 return config_; |
319 } | 408 } |
320 | 409 |
321 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { | 410 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { |
322 Destroy(); | 411 Destroy(); |
323 } | 412 } |
324 | 413 |
325 } // namespace gfx | 414 } // namespace gfx |
OLD | NEW |