summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-01 15:40:36 +0000
committerajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-01 15:40:36 +0000
commita0c3fbb4d5b603835cc756fce5d75c7dbb08a3ac (patch)
treebf1278eab4fc0d35c309988f0784ff8dee16a91e /ui
parente3ccc01fb64e2a9b5e4b5923754f28139a6640ad (diff)
downloadchromium_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')
-rw-r--r--ui/compositor/compositor.cc87
-rw-r--r--ui/compositor/compositor.h10
-rwxr-xr-xui/gl/generate_bindings.py10
-rw-r--r--ui/gl/gl_surface.cc10
-rw-r--r--ui/gl/gl_surface.h13
-rw-r--r--ui/gl/gl_surface_glx.cc89
-rw-r--r--ui/gl/gl_surface_glx.h3
7 files changed, 171 insertions, 51 deletions
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index f1c1b25..e41128a 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -44,6 +44,43 @@ ui::ContextFactory* g_context_factory = NULL;
const int kCompositorLockTimeoutMs = 67;
+// Adapts a pure WebGraphicsContext3D into a WebCompositorOutputSurface.
+class WebGraphicsContextToOutputSurfaceAdapter :
+ public WebKit::WebCompositorOutputSurface {
+public:
+ explicit WebGraphicsContextToOutputSurfaceAdapter(
+ WebKit::WebGraphicsContext3D* context)
+ : context3D_(context),
+ client_(NULL) {
+ }
+
+ virtual bool bindToClient(
+ WebKit::WebCompositorOutputSurfaceClient* client) OVERRIDE {
+ DCHECK(client);
+ if (!context3D_->makeContextCurrent())
+ return false;
+ client_ = client;
+ return true;
+ }
+
+ virtual const Capabilities& capabilities() const OVERRIDE {
+ return capabilities_;
+ }
+
+ virtual WebKit::WebGraphicsContext3D* context3D() const OVERRIDE {
+ return context3D_.get();
+ }
+
+ virtual void sendFrameToParentCompositor(
+ const WebKit::WebCompositorFrame&) OVERRIDE {
+ }
+
+private:
+ scoped_ptr<WebKit::WebGraphicsContext3D> context3D_;
+ Capabilities capabilities_;
+ WebKit::WebCompositorOutputSurfaceClient* client_;
+};
+
} // namespace
namespace ui {
@@ -86,9 +123,10 @@ bool DefaultContextFactory::Initialize() {
return true;
}
-WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContext(
+WebKit::WebCompositorOutputSurface* DefaultContextFactory::CreateOutputSurface(
Compositor* compositor) {
- return CreateContextCommon(compositor, false);
+ return new WebGraphicsContextToOutputSurfaceAdapter(
+ CreateContextCommon(compositor, false));
}
WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext() {
@@ -348,48 +386,6 @@ void Compositor::applyScrollAndScale(const WebKit::WebSize& scrollDelta,
float scaleFactor) {
}
-// Adapts a pure WebGraphicsContext3D into a WebCompositorOutputSurface.
-class WebGraphicsContextToOutputSurfaceAdapter :
- public WebKit::WebCompositorOutputSurface {
-public:
- explicit WebGraphicsContextToOutputSurfaceAdapter(
- WebKit::WebGraphicsContext3D* context)
- : m_context3D(context)
- , m_client(0)
- {
- }
-
- virtual bool bindToClient(
- WebKit::WebCompositorOutputSurfaceClient* client) OVERRIDE
- {
- DCHECK(client);
- if (!m_context3D->makeContextCurrent())
- return false;
- m_client = client;
- return true;
- }
-
- virtual const Capabilities& capabilities() const OVERRIDE
- {
- return m_capabilities;
- }
-
- virtual WebKit::WebGraphicsContext3D* context3D() const OVERRIDE
- {
- return m_context3D.get();
- }
-
- virtual void sendFrameToParentCompositor(
- const WebKit::WebCompositorFrame&) OVERRIDE
- {
- }
-
-private:
- scoped_ptr<WebKit::WebGraphicsContext3D> m_context3D;
- Capabilities m_capabilities;
- WebKit::WebCompositorOutputSurfaceClient* m_client;
-};
-
WebKit::WebCompositorOutputSurface* Compositor::createOutputSurface() {
if (test_compositor_enabled) {
ui::TestWebGraphicsContext3D* test_context =
@@ -397,8 +393,7 @@ WebKit::WebCompositorOutputSurface* Compositor::createOutputSurface() {
test_context->Initialize();
return new WebGraphicsContextToOutputSurfaceAdapter(test_context);
} else {
- return new WebGraphicsContextToOutputSurfaceAdapter(
- ContextFactory::GetInstance()->CreateContext(this));
+ return ContextFactory::GetInstance()->CreateOutputSurface(this);
}
}
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index f3720bc..6ab4f9f 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -48,10 +48,10 @@ class COMPOSITOR_EXPORT ContextFactory {
// created on the first call of GetInstance.
static void SetInstance(ContextFactory* instance);
- // Creates a context for given compositor. The factory may keep per-compositor
- // data (e.g. a shared context), that needs to be cleaned up by calling
- // RemoveCompositor when the compositor gets destroyed.
- virtual WebKit::WebGraphicsContext3D* CreateContext(
+ // Creates an output surface for the given compositor. The factory may keep
+ // per-compositor data (e.g. a shared context), that needs to be cleaned up
+ // by calling RemoveCompositor when the compositor gets destroyed.
+ virtual WebKit::WebCompositorOutputSurface* CreateOutputSurface(
Compositor* compositor) = 0;
// Creates a context used for offscreen rendering. This context can be shared
@@ -69,7 +69,7 @@ class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory {
virtual ~DefaultContextFactory();
// ContextFactory implementation
- virtual WebKit::WebGraphicsContext3D* CreateContext(
+ virtual WebKit::WebCompositorOutputSurface* CreateOutputSurface(
Compositor* compositor) OVERRIDE;
virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext() OVERRIDE;
virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
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();