Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Unified Diff: ui/gl/gl_surface_glx.cc

Issue 11293194: ui: Prefer +/- operators to apply offsets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: floats Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« .gitmodules ('K') | « ui/gl/gl_surface_glx.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gl/gl_surface_glx.cc
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index a164f3f56c1793cf84c36821d12874659f372c59..da2d74c3cf7665115f65d94a9ec8142b8a784132 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -12,8 +12,13 @@ extern "C" {
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/process_util.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
#include "base/time.h"
#include "third_party/mesa/MesaLib/include/GL/osmesa.h"
#include "ui/base/x/x11_util.h"
@@ -45,6 +50,310 @@ bool g_glx_oml_sync_control_supported = false;
// always fails even though GLX_OML_sync_control is reported as being supported.
bool g_glx_get_msc_rate_oml_supported = false;
+bool g_glx_sgi_video_sync_supported = false;
+
+class OMLSyncControlVSyncProvider
+ : public gfx::NativeViewGLSurfaceGLX::VSyncProvider {
+ public:
+ explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window)
+ : window_(window) {
+ }
+
+ virtual ~OMLSyncControlVSyncProvider() { }
+
+ virtual void GetVSyncParameters(
+ const GLSurface::UpdateVSyncCallback& callback) OVERRIDE {
+ base::TimeTicks timebase;
+ base::TimeDelta interval;
+
+ // 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;
+
+ 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;
+
+ // 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);
+ callback.Run(timebase, interval);
+ }
+
+ private:
+ XID window_;
+
+ DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider);
+};
+
+class SGIVideoSyncThread
+ : public base::Thread,
+ public base::NonThreadSafe,
+ public base::RefCounted<SGIVideoSyncThread> {
+ public:
+ static scoped_refptr<SGIVideoSyncThread> Create() {
+ if (!g_video_sync_thread) {
+ g_video_sync_thread = new SGIVideoSyncThread();
+ g_video_sync_thread->Start();
+ }
+ return g_video_sync_thread;
+ }
+
+ private:
+ friend class base::RefCounted<SGIVideoSyncThread>;
+
+ SGIVideoSyncThread() : base::Thread("SGI_video_sync") {
+ DCHECK(CalledOnValidThread());
+ }
+
+ ~SGIVideoSyncThread() {
+ DCHECK(CalledOnValidThread());
+ g_video_sync_thread = NULL;
+ Stop();
+ }
+
+ static SGIVideoSyncThread* g_video_sync_thread;
+
+ DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread);
+};
+
+class SGIVideoSyncProviderThreadShim
+ : public base::SupportsWeakPtr<SGIVideoSyncProviderThreadShim> {
+ public:
+ explicit SGIVideoSyncProviderThreadShim(XID window)
+ : window_(window),
+ context_(NULL),
+ message_loop_(base::MessageLoopProxy::current()),
+ cancel_vsync_flag_(),
+ vsync_lock_() {
+ // This ensures that creation of |window_| has occured when this shim
+ // is executing in the same process as the call to create |window_|.
+ XSync(::gfx::g_display, False);
+ }
+
+ base::CancellationFlag* cancel_vsync_flag() {
+ return &cancel_vsync_flag_;
+ }
+
+ base::Lock* vsync_lock() {
+ return &vsync_lock_;
+ }
+
+ void Initialize() {
+ DCHECK(SGIVideoSyncProviderThreadShim::g_display);
+
+ XWindowAttributes attributes;
+ if (!XGetWindowAttributes(SGIVideoSyncProviderThreadShim::g_display,
+ window_, &attributes)) {
+ LOG(ERROR) << "XGetWindowAttributes failed for window " <<
+ window_ << ".";
+ return;
+ }
+
+ XVisualInfo visual_info_template;
+ visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
+
+ int visual_info_count = 0;
+ scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
+ XGetVisualInfo(SGIVideoSyncProviderThreadShim::g_display, VisualIDMask,
+ &visual_info_template, &visual_info_count));
+
+ DCHECK(visual_info_list.get());
+ if (visual_info_count == 0) {
+ LOG(ERROR) << "No visual info for visual ID.";
+ return;
+ }
+
+ context_ = glXCreateContext(SGIVideoSyncProviderThreadShim::g_display,
+ visual_info_list.get(),
+ NULL,
+ True);
+
+ DCHECK(NULL != context_);
+ }
+
+ void Destroy() {
+ if (context_) {
+ glXDestroyContext(SGIVideoSyncProviderThreadShim::g_display, context_);
+ context_ = NULL;
+ }
+ delete this;
+ }
+
+ void GetVSyncParameters(const GLSurface::UpdateVSyncCallback& callback) {
+ base::TimeTicks now;
+ {
+ // Don't allow |window_| destruction while we're probing vsync.
+ base::AutoLock locked(vsync_lock_);
+
+ if (!context_ || cancel_vsync_flag_.IsSet())
+ return;
+
+ glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display,
+ window_, context_);
+
+ unsigned int retrace_count = 0;
+ if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0)
+ return;
+
+ TRACE_EVENT_INSTANT0("gpu", "vblank");
+ now = base::TimeTicks::HighResNow();
+
+ glXMakeCurrent(SGIVideoSyncProviderThreadShim::g_display, 0, 0);
+ }
+
+ const int64 kDefaultIntervalTime =
+ base::Time::kMicrosecondsPerSecond / 60;
+ base::TimeDelta interval =
+ base::TimeDelta::FromMicroseconds(kDefaultIntervalTime);
+
+ message_loop_->PostTask(FROM_HERE, base::Bind(callback, now, interval));
+ }
+
+ private:
+ // For initialization of g_display in GLSurface::InitializeOneOff before
+ // the sandbox goes up.
+ friend class gfx::GLSurfaceGLX;
+
+ virtual ~SGIVideoSyncProviderThreadShim() {
+ }
+
+ static Display* g_display;
+
+ XID window_;
+ GLXContext context_;
+
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
+
+ base::CancellationFlag cancel_vsync_flag_;
+ base::Lock vsync_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim);
+};
+
+class SGIVideoSyncVSyncProvider
+ : public gfx::NativeViewGLSurfaceGLX::VSyncProvider,
+ public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> {
+ public:
+ explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window)
+ : vsync_thread_(SGIVideoSyncThread::Create()),
+ shim_((new SGIVideoSyncProviderThreadShim(window))->AsWeakPtr()),
+ cancel_vsync_flag_(shim_->cancel_vsync_flag()),
+ vsync_lock_(shim_->vsync_lock()) {
+ // The WeakPtr is bound to the SGIVideoSyncThread. We only use it for
+ // PostTask.
+ shim_->DetachFromThread();
+ vsync_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, shim_));
+ }
+
+ virtual ~SGIVideoSyncVSyncProvider() {
+ {
+ base::AutoLock locked(*vsync_lock_);
+ cancel_vsync_flag_->Set();
+ }
+ vsync_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SGIVideoSyncProviderThreadShim::Destroy, shim_));
+ }
+
+ virtual void GetVSyncParameters(
+ const GLSurface::UpdateVSyncCallback& callback) OVERRIDE {
+ // Only one outstanding request per surface.
+ if (!pending_callback_) {
+ pending_callback_.reset(new GLSurface::UpdateVSyncCallback(callback));
+ vsync_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
+ shim_, base::Bind(
+ &SGIVideoSyncVSyncProvider::PendingCallbackRunner,
+ AsWeakPtr())));
+ }
+ }
+
+ private:
+ void PendingCallbackRunner(const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ DCHECK(pending_callback_);
+ pending_callback_->Run(timebase, interval);
+ pending_callback_.reset();
+ }
+
+ scoped_refptr<SGIVideoSyncThread> vsync_thread_;
+ base::WeakPtr<SGIVideoSyncProviderThreadShim> shim_;
+
+ scoped_ptr<GLSurface::UpdateVSyncCallback> pending_callback_;
+
+ // Raw pointers to sync primitives owned by the shim_.
+ // These will only be referenced before we post a task to destroy
+ // the shim_, so they are safe to access.
+ base::CancellationFlag* cancel_vsync_flag_;
+ base::Lock* vsync_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider);
+};
+
+SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
+
+// In order to take advantage of GLX_SGI_video_sync, we need a display
+// for use on a separate thread. We must allocate this before the sandbox
+// goes up (rather than on-demand when we start the thread).
+Display* SGIVideoSyncProviderThreadShim::g_display = NULL;
+
} // namespace
GLSurfaceGLX::GLSurfaceGLX() {}
@@ -54,6 +363,10 @@ bool GLSurfaceGLX::InitializeOneOff() {
if (initialized)
return true;
+ // SGIVideoSyncProviderShim (if instantiated) will issue X commands on
+ // it's own thread.
+ XInitThreads();
+
g_display = base::MessagePumpForUI::GetDefaultXDisplay();
if (!g_display) {
LOG(ERROR) << "XOpenDisplay failed.";
@@ -79,7 +392,11 @@ bool GLSurfaceGLX::InitializeOneOff() {
g_glx_oml_sync_control_supported =
HasGLXExtension("GLX_OML_sync_control");
g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported;
+ g_glx_sgi_video_sync_supported =
+ HasGLXExtension("GLX_SGI_video_sync");
+ if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported)
+ SGIVideoSyncProviderThreadShim::g_display = XOpenDisplay(NULL);
initialized = true;
return true;
@@ -128,6 +445,12 @@ bool NativeViewGLSurfaceGLX::Initialize() {
return false;
}
size_ = gfx::Size(attributes.width, attributes.height);
+
+ if (g_glx_oml_sync_control_supported)
+ vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_));
+ else if (g_glx_sgi_video_sync_supported)
+ vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_));
+
return true;
}
@@ -240,77 +563,10 @@ 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;
+void NativeViewGLSurfaceGLX::GetVSyncParameters(
+ const UpdateVSyncCallback& callback) {
+ if (vsync_provider_)
+ vsync_provider_->GetVSyncParameters(callback);
}
NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
« .gitmodules ('K') | « ui/gl/gl_surface_glx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698