diff options
author | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-01 15:40:36 +0000 |
---|---|---|
committer | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-01 15:40:36 +0000 |
commit | a0c3fbb4d5b603835cc756fce5d75c7dbb08a3ac (patch) | |
tree | bf1278eab4fc0d35c309988f0784ff8dee16a91e /ui/gl | |
parent | e3ccc01fb64e2a9b5e4b5923754f28139a6640ad (diff) | |
download | chromium_src-a0c3fbb4d5b603835cc756fce5d75c7dbb08a3ac.zip chromium_src-a0c3fbb4d5b603835cc756fce5d75c7dbb08a3ac.tar.gz chromium_src-a0c3fbb4d5b603835cc756fce5d75c7dbb08a3ac.tar.bz2 |
Send vsync timebase updates to the browser compositor
This uses the GLX_OML_sync_control extension to get vsync timebase
and interval information and forward it to the browser compositor
on Aura, and to the renderer compositor on non-Aura.
BUG=143466
Review URL: https://chromiumcodereview.appspot.com/11195011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@165389 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gl')
-rwxr-xr-x | ui/gl/generate_bindings.py | 10 | ||||
-rw-r--r-- | ui/gl/gl_surface.cc | 10 | ||||
-rw-r--r-- | ui/gl/gl_surface.h | 13 | ||||
-rw-r--r-- | ui/gl/gl_surface_glx.cc | 89 | ||||
-rw-r--r-- | ui/gl/gl_surface_glx.h | 3 |
5 files changed, 125 insertions, 0 deletions
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index 0090602..3bf7b37 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py @@ -1108,6 +1108,16 @@ GLX_FUNCTIONS = [ 'arguments': 'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, ' 'const int* attrib_list', }, +{ 'return_type': 'bool', + 'names': ['glXGetSyncValuesOML'], + 'arguments': + 'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, ' + 'int64* sbc' }, +{ 'return_type': 'bool', + 'names': ['glXGetMscRateOML'], + 'arguments': + 'Display* dpy, GLXDrawable drawable, int32* numerator, ' + 'int32* denominator' }, ] FUNCTION_SETS = [ diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index a05eae8..832015b 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc @@ -147,6 +147,11 @@ unsigned GLSurface::GetFormat() { return 0; } +bool GLSurface::GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval) { + return false; +} + GLSurface* GLSurface::GetCurrent() { return current_surface_.Pointer()->Get(); } @@ -251,6 +256,11 @@ unsigned GLSurfaceAdapter::GetFormat() { return surface_->GetFormat(); } +bool GLSurfaceAdapter::GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval) { + return surface_->GetVSyncParameters(timebase, interval); +} + GLSurfaceAdapter::~GLSurfaceAdapter() {} } // namespace gfx diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index 4ecc472..56d8ae7 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h @@ -13,6 +13,11 @@ #include "ui/gfx/size.h" #include "ui/gl/gl_export.h" +namespace base { +class TimeDelta; +class TimeTicks; +} + namespace gfx { class GLContext; @@ -102,6 +107,12 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> { // Get the GL pixel format of the surface, if available. virtual unsigned GetFormat(); + // Get the time of the most recent screen refresh, along with the time + // between consecutive refreshes. Returns false when these values are + // unavailable. + virtual bool GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval); + // Create a GL surface that renders directly to a view. static scoped_refptr<GLSurface> CreateViewGLSurface( bool software, @@ -153,6 +164,8 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface { virtual void* GetDisplay() OVERRIDE; virtual void* GetConfig() OVERRIDE; virtual unsigned GetFormat() OVERRIDE; + virtual bool GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval) OVERRIDE; GLSurface* surface() const { return surface_.get(); } diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc index f810114..a164f3f 100644 --- a/ui/gl/gl_surface_glx.cc +++ b/ui/gl/gl_surface_glx.cc @@ -14,6 +14,7 @@ extern "C" { #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/process_util.h" +#include "base/time.h" #include "third_party/mesa/MesaLib/include/GL/osmesa.h" #include "ui/base/x/x11_util.h" #include "ui/gl/gl_bindings.h" @@ -37,6 +38,12 @@ Display* g_display; const char* g_glx_extensions = NULL; bool g_glx_create_context_robustness_supported = false; bool g_glx_texture_from_pixmap_supported = false; +bool g_glx_oml_sync_control_supported = false; + +// Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a +// whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML +// always fails even though GLX_OML_sync_control is reported as being supported. +bool g_glx_get_msc_rate_oml_supported = false; } // namespace @@ -69,6 +76,10 @@ bool GLSurfaceGLX::InitializeOneOff() { HasGLXExtension("GLX_ARB_create_context_robustness"); g_glx_texture_from_pixmap_supported = HasGLXExtension("GLX_EXT_texture_from_pixmap"); + g_glx_oml_sync_control_supported = + HasGLXExtension("GLX_OML_sync_control"); + g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; + initialized = true; return true; @@ -94,6 +105,11 @@ bool GLSurfaceGLX::IsTextureFromPixmapSupported() { return g_glx_texture_from_pixmap_supported; } +// static +bool GLSurfaceGLX::IsOMLSyncControlSupported() { + return g_glx_oml_sync_control_supported; +} + void* GLSurfaceGLX::GetDisplay() { return g_display; } @@ -224,6 +240,79 @@ bool NativeViewGLSurfaceGLX::PostSubBuffer( return true; } +bool NativeViewGLSurfaceGLX::GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval) { + if (!g_glx_oml_sync_control_supported) + return false; + + // The actual clock used for the system time returned by glXGetSyncValuesOML + // is unspecified. In practice, the clock used is likely to be either + // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the + // current time according to both clocks, and assume that the returned time + // was produced by the clock whose current time is closest to it, subject + // to the restriction that the returned time must not be in the future (since + // it is the time of a vblank that has already occurred). + int64 system_time; + int64 media_stream_counter; + int64 swap_buffer_counter; + if (!glXGetSyncValuesOML(g_display, window_, &system_time, + &media_stream_counter, &swap_buffer_counter)) + return false; + + struct timespec real_time; + struct timespec monotonic_time; + clock_gettime(CLOCK_REALTIME, &real_time); + clock_gettime(CLOCK_MONOTONIC, &monotonic_time); + + int64 real_time_in_microseconds = + real_time.tv_sec * base::Time::kMicrosecondsPerSecond + + real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; + int64 monotonic_time_in_microseconds = + monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond + + monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond; + + if ((system_time > real_time_in_microseconds) && + (system_time > monotonic_time_in_microseconds)) + return false; + + // We need the time according to CLOCK_MONOTONIC, so if we've been given + // a time from CLOCK_REALTIME, we need to convert. + bool time_conversion_needed = + (system_time > monotonic_time_in_microseconds) || + (real_time_in_microseconds - system_time < + monotonic_time_in_microseconds - system_time); + + if (time_conversion_needed) { + int64 time_difference = + real_time_in_microseconds - monotonic_time_in_microseconds; + *timebase = base::TimeTicks::FromInternalValue( + system_time - time_difference); + } else { + *timebase = base::TimeTicks::FromInternalValue(system_time); + } + + // On platforms where glXGetMscRateOML doesn't work, we fall back to the + // assumption that we're displaying 60 frames per second. + const int64 kDefaultIntervalTime = + base::Time::kMicrosecondsPerSecond / 60; + int64 interval_time = kDefaultIntervalTime; + int32 numerator; + int32 denominator; + if (g_glx_get_msc_rate_oml_supported) { + if (glXGetMscRateOML(g_display, window_, &numerator, &denominator)) { + interval_time = + (base::Time::kMicrosecondsPerSecond * denominator) / numerator; + } else { + // Once glXGetMscRateOML has been found to fail, don't try again, + // since each failing call may spew an error message. + g_glx_get_msc_rate_oml_supported = false; + } + } + + *interval = base::TimeDelta::FromMicroseconds(interval_time); + return true; +} + NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() : window_(0), config_(NULL) { diff --git a/ui/gl/gl_surface_glx.h b/ui/gl/gl_surface_glx.h index 0dc235c..908c2fb 100644 --- a/ui/gl/gl_surface_glx.h +++ b/ui/gl/gl_surface_glx.h @@ -28,6 +28,7 @@ class GL_EXPORT GLSurfaceGLX : public GLSurface { static bool HasGLXExtension(const char* name); static bool IsCreateContextRobustnessSupported(); static bool IsTextureFromPixmapSupported(); + static bool IsOMLSyncControlSupported(); virtual void* GetDisplay() OVERRIDE; @@ -58,6 +59,8 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX { virtual std::string GetExtensions() OVERRIDE; virtual void* GetConfig() OVERRIDE; virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + virtual bool GetVSyncParameters(base::TimeTicks* timebase, + base::TimeDelta* interval) OVERRIDE; protected: NativeViewGLSurfaceGLX(); |