Index: ui/gl/gl_surface_glx.cc |
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc |
index 6d0ba1593c6eb92247f7cfda657f73e2024c3740..e8427ed9e64cb56ffdb46aaa27c1c25ebf773a08 100644 |
--- a/ui/gl/gl_surface_glx.cc |
+++ b/ui/gl/gl_surface_glx.cc |
@@ -50,19 +50,6 @@ bool g_glx_get_msc_rate_oml_supported = false; |
bool g_glx_sgi_video_sync_supported = false; |
-static const int kGetVSyncParametersMinSeconds = |
-#if defined(OS_LINUX) |
- // See crbug.com/373489 |
- // On Linux, querying the vsync parameters might burn CPU for up to an |
- // entire vsync, so we only query periodically to reduce CPU usage. |
- // 5 seconds is chosen somewhat abitrarily as a balance between: |
- // a) Drift in the phase of our signal. |
- // b) Potential janks from periodically pegging the CPU. |
- 5; |
-#else |
- 0; |
-#endif |
- |
GLXFBConfig GetConfigForWindow(Display* display, |
gfx::AcceleratedWidget window) { |
DCHECK(window != 0); |
@@ -118,12 +105,36 @@ GLXFBConfig GetConfigForWindow(Display* display, |
return nullptr; |
} |
+bool CreateDummyWindow(Display* display) { |
+ DCHECK(display); |
+ gfx::AcceleratedWidget parent_window = |
+ RootWindow(display, DefaultScreen(display)); |
+ // We create a window with CopyFromParent visual so that we have the same |
+ // visual as NativeViewGLSurfaceGLX (i.e. same GLXFBConfig), to ensure |
+ // contexts are compatible and can be made current with either. |
+ gfx::AcceleratedWidget window = |
+ XCreateWindow(display, parent_window, 0, 0, 1, 1, 0, CopyFromParent, |
+ InputOutput, CopyFromParent, 0, nullptr); |
+ if (!window) { |
+ LOG(ERROR) << "XCreateWindow failed"; |
+ return false; |
+ } |
+ GLXFBConfig config = GetConfigForWindow(display, window); |
+ GLXWindow glx_window = glXCreateWindow(display, config, window, nullptr); |
+ if (!glx_window) { |
+ LOG(ERROR) << "glXCreateWindow failed"; |
+ XDestroyWindow(display, window); |
+ return false; |
+ } |
+ glXDestroyWindow(display, glx_window); |
+ XDestroyWindow(display, window); |
+ return true; |
+} |
+ |
class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider { |
public: |
explicit OMLSyncControlVSyncProvider(GLXWindow glx_window) |
- : SyncControlVSyncProvider(), |
- glx_window_(glx_window) { |
- } |
+ : SyncControlVSyncProvider(), glx_window_(glx_window) {} |
~OMLSyncControlVSyncProvider() override {} |
@@ -155,10 +166,9 @@ class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider { |
DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); |
}; |
-class SGIVideoSyncThread |
- : public base::Thread, |
- public base::NonThreadSafe, |
- public base::RefCounted<SGIVideoSyncThread> { |
+class SGIVideoSyncThread : public base::Thread, |
+ public base::NonThreadSafe, |
+ public base::RefCounted<SGIVideoSyncThread> { |
public: |
static scoped_refptr<SGIVideoSyncThread> Create() { |
if (!g_video_sync_thread) { |
@@ -188,41 +198,57 @@ class SGIVideoSyncThread |
class SGIVideoSyncProviderThreadShim { |
public: |
- explicit SGIVideoSyncProviderThreadShim(GLXFBConfig config, |
- GLXWindow glx_window) |
- : config_(config), |
- glx_window_(glx_window), |
- context_(nullptr), |
+ explicit SGIVideoSyncProviderThreadShim(gfx::AcceleratedWidget parent_window) |
+ : parent_window_(parent_window), |
+ window_(0), |
+ glx_window_(0), |
task_runner_(base::ThreadTaskRunnerHandle::Get()), |
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_|. |
+ // This ensures that creation of |parent_window_| has occured when this shim |
+ // is executing in the same thread as the call to create |parent_window_|. |
XSync(g_display, False); |
} |
virtual ~SGIVideoSyncProviderThreadShim() { |
- if (context_) { |
- glXDestroyContext(display_, context_); |
- context_ = nullptr; |
- } |
- } |
+ if (glx_window_) |
+ glXDestroyWindow(display_, glx_window_); |
- base::CancellationFlag* cancel_vsync_flag() { |
- return &cancel_vsync_flag_; |
+ if (window_) |
+ XDestroyWindow(display_, window_); |
} |
- base::Lock* vsync_lock() { |
- return &vsync_lock_; |
- } |
+ base::CancellationFlag* cancel_vsync_flag() { return &cancel_vsync_flag_; } |
+ |
+ base::Lock* vsync_lock() { return &vsync_lock_; } |
void Initialize() { |
DCHECK(display_); |
- context_ = |
- glXCreateNewContext(display_, config_, GLX_RGBA_TYPE, nullptr, True); |
+ window_ = |
+ XCreateWindow(display_, parent_window_, 0, 0, 1, 1, 0, CopyFromParent, |
+ InputOutput, CopyFromParent, 0, nullptr); |
+ if (!window_) { |
+ LOG(ERROR) << "video_sync: XCreateWindow failed"; |
+ return; |
+ } |
+ |
+ GLXFBConfig config = GetConfigForWindow(display_, window_); |
+ DCHECK(config); |
+ |
+ glx_window_ = glXCreateWindow(display_, config, window_, nullptr); |
+ if (!glx_window_) { |
+ LOG(ERROR) << "video_sync: glXCreateWindow failed"; |
+ return; |
+ } |
- DCHECK(nullptr != context_); |
+ // Create the context only once for all vsync providers. |
+ if (!context_) { |
+ context_ = |
+ glXCreateNewContext(display_, config, GLX_RGBA_TYPE, nullptr, True); |
+ if (!context_) |
+ LOG(ERROR) << "video_sync: glXCreateNewContext failed"; |
+ } |
} |
void GetVSyncParameters( |
@@ -250,8 +276,8 @@ class SGIVideoSyncProviderThreadShim { |
const base::TimeDelta kDefaultInterval = |
base::TimeDelta::FromSeconds(1) / 60; |
- task_runner_->PostTask( |
- FROM_HERE, base::Bind(callback, now, kDefaultInterval)); |
+ task_runner_->PostTask(FROM_HERE, |
+ base::Bind(callback, now, kDefaultInterval)); |
} |
private: |
@@ -259,11 +285,16 @@ class SGIVideoSyncProviderThreadShim { |
// the sandbox goes up. |
friend class gl::GLSurfaceGLX; |
+ // We only need one Display and GLXContext because we only use one thread for |
+ // SGI_video_sync. The display is created in GLSurfaceGLX::InitializeOneOff |
+ // and the context is created the first time a vsync provider is initialized. |
static Display* display_; |
+ static GLXContext context_; |
+ |
+ gfx::AcceleratedWidget parent_window_; |
- GLXFBConfig config_; |
+ gfx::AcceleratedWidget window_; |
GLXWindow glx_window_; |
- GLXContext context_; |
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
@@ -277,9 +308,9 @@ class SGIVideoSyncVSyncProvider |
: public gfx::VSyncProvider, |
public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { |
public: |
- explicit SGIVideoSyncVSyncProvider(GLXFBConfig config, GLXWindow glx_window) |
+ explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget parent_window) |
: vsync_thread_(SGIVideoSyncThread::Create()), |
- shim_(new SGIVideoSyncProviderThreadShim(config, glx_window)), |
+ shim_(new SGIVideoSyncProviderThreadShim(parent_window)), |
cancel_vsync_flag_(shim_->cancel_vsync_flag()), |
vsync_lock_(shim_->vsync_lock()) { |
vsync_thread_->task_runner()->PostTask( |
@@ -299,14 +330,6 @@ class SGIVideoSyncVSyncProvider |
void GetVSyncParameters( |
const gfx::VSyncProvider::UpdateVSyncCallback& callback) override { |
- if (kGetVSyncParametersMinSeconds > 0) { |
- base::TimeTicks now = base::TimeTicks::Now(); |
- base::TimeDelta delta = now - last_get_vsync_parameters_time_; |
- if (delta.InSeconds() < kGetVSyncParametersMinSeconds) |
- return; |
- last_get_vsync_parameters_time_ = now; |
- } |
- |
// Only one outstanding request per surface. |
if (!pending_callback_) { |
pending_callback_.reset( |
@@ -342,8 +365,6 @@ class SGIVideoSyncVSyncProvider |
base::CancellationFlag* cancel_vsync_flag_; |
base::Lock* vsync_lock_; |
- base::TimeTicks last_get_vsync_parameters_time_; |
- |
DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); |
}; |
@@ -353,6 +374,7 @@ SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = nullptr; |
// 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::display_ = nullptr; |
+GLXContext SGIVideoSyncProviderThreadShim::context_ = 0; |
} // namespace |
@@ -387,8 +409,7 @@ bool GLSurfaceGLX::InitializeOneOff() { |
return false; |
} |
- g_glx_context_create = |
- HasGLXExtension("GLX_ARB_create_context"); |
+ g_glx_context_create = HasGLXExtension("GLX_ARB_create_context"); |
g_glx_create_context_robustness_supported = |
HasGLXExtension("GLX_ARB_create_context_robustness"); |
g_glx_create_context_profile_supported = |
@@ -397,16 +418,29 @@ bool GLSurfaceGLX::InitializeOneOff() { |
HasGLXExtension("GLX_ARB_create_context_es2_profile"); |
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_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") && |
- base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kEnableSgiVideoSync); |
+ g_glx_sgi_video_sync_supported = HasGLXExtension("GLX_SGI_video_sync"); |
+ |
+ // We create a dummy unmapped window for both the main Display and the video |
+ // sync Display so that the Nvidia driver can initialize itself before the |
+ // sandbox is set up. |
+ // Unfortunately some fds e.g. /dev/nvidia0 are cached per thread and because |
+ // we can't start threads before the sandbox is set up, these are accessed |
+ // through the broker process. See GpuProcessPolicy::InitGpuBrokerProcess. |
+ if (!CreateDummyWindow(g_display)) { |
+ LOG(ERROR) << "CreateDummyWindow(g_display) failed"; |
+ return false; |
+ } |
- if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) |
- SGIVideoSyncProviderThreadShim::display_ = gfx::OpenNewXDisplay(); |
+ if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) { |
+ Display* video_sync_display = gfx::OpenNewXDisplay(); |
+ if (!CreateDummyWindow(video_sync_display)) { |
+ LOG(ERROR) << "CreateDummyWindow(video_sync_display) failed"; |
+ return false; |
+ } |
+ SGIVideoSyncProviderThreadShim::display_ = video_sync_display; |
+ } |
initialized = true; |
return true; |
@@ -459,8 +493,7 @@ void* GLSurfaceGLX::GetDisplay() { |
GLSurfaceGLX::~GLSurfaceGLX() {} |
NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
- : parent_window_(window), window_(0), glx_window_(0), config_(nullptr) { |
-} |
+ : parent_window_(window), window_(0), glx_window_(0), config_(nullptr) {} |
GLXDrawable NativeViewGLSurfaceGLX::GetDrawableHandle() const { |
return glx_window_; |
@@ -470,7 +503,7 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurface::Format format) { |
XWindowAttributes attributes; |
if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
- << "."; |
+ << "."; |
return false; |
} |
size_ = gfx::Size(attributes.width, attributes.height); |
@@ -503,7 +536,7 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurface::Format format) { |
if (g_glx_oml_sync_control_supported) { |
vsync_provider_.reset(new OMLSyncControlVSyncProvider(glx_window_)); |
} else if (g_glx_sgi_video_sync_supported) { |
- vsync_provider_.reset(new SGIVideoSyncVSyncProvider(config_, glx_window_)); |
+ vsync_provider_.reset(new SGIVideoSyncVSyncProvider(parent_window_)); |
} else { |
// Assume a refresh rate of 59.9 Hz, which will cause us to skip |
// 1 frame every 10 seconds on a 60Hz monitor, but will prevent us |
@@ -544,8 +577,7 @@ bool NativeViewGLSurfaceGLX::CanDispatchEvent(const ui::PlatformEvent& event) { |
uint32_t NativeViewGLSurfaceGLX::DispatchEvent(const ui::PlatformEvent& event) { |
XEvent forwarded_event = *event; |
forwarded_event.xexpose.window = parent_window_; |
- XSendEvent(g_display, parent_window_, False, ExposureMask, |
- &forwarded_event); |
+ XSendEvent(g_display, parent_window_, False, ExposureMask, &forwarded_event); |
XFlush(g_display); |
return ui::POST_DISPATCH_STOP_PROPAGATION; |
} |
@@ -565,9 +597,8 @@ bool NativeViewGLSurfaceGLX::IsOffscreen() { |
} |
gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers() { |
- TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", |
- "width", GetSize().width(), |
- "height", GetSize().height()); |
+ TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width", |
+ GetSize().width(), "height", GetSize().height()); |
glXSwapBuffers(g_display, GetDrawableHandle()); |
return gfx::SwapResult::SWAP_ACK; |