| 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 #include "ui/gl/gl_surface_glx.h" | 5 #include "ui/gl/gl_surface_glx.h" |
| 6 | 6 |
| 7 extern "C" { | 7 extern "C" { |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 } | 9 } |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 bool g_glx_texture_from_pixmap_supported = false; | 43 bool g_glx_texture_from_pixmap_supported = false; |
| 44 bool g_glx_oml_sync_control_supported = false; | 44 bool g_glx_oml_sync_control_supported = false; |
| 45 | 45 |
| 46 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a | 46 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a |
| 47 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML | 47 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML |
| 48 // always fails even though GLX_OML_sync_control is reported as being supported. | 48 // always fails even though GLX_OML_sync_control is reported as being supported. |
| 49 bool g_glx_get_msc_rate_oml_supported = false; | 49 bool g_glx_get_msc_rate_oml_supported = false; |
| 50 | 50 |
| 51 bool g_glx_sgi_video_sync_supported = false; | 51 bool g_glx_sgi_video_sync_supported = false; |
| 52 | 52 |
| 53 static const int kGetVSyncParametersMinSeconds = | |
| 54 #if defined(OS_LINUX) | |
| 55 // See crbug.com/373489 | |
| 56 // On Linux, querying the vsync parameters might burn CPU for up to an | |
| 57 // entire vsync, so we only query periodically to reduce CPU usage. | |
| 58 // 5 seconds is chosen somewhat abitrarily as a balance between: | |
| 59 // a) Drift in the phase of our signal. | |
| 60 // b) Potential janks from periodically pegging the CPU. | |
| 61 5; | |
| 62 #else | |
| 63 0; | |
| 64 #endif | |
| 65 | |
| 66 GLXFBConfig GetConfigForWindow(Display* display, | 53 GLXFBConfig GetConfigForWindow(Display* display, |
| 67 gfx::AcceleratedWidget window) { | 54 gfx::AcceleratedWidget window) { |
| 68 DCHECK(window != 0); | 55 DCHECK(window != 0); |
| 69 | 56 |
| 70 // This code path is expensive, but we only take it when | 57 // This code path is expensive, but we only take it when |
| 71 // attempting to use GLX_ARB_create_context_robustness, in which | 58 // attempting to use GLX_ARB_create_context_robustness, in which |
| 72 // case we need a GLXFBConfig for the window in order to create a | 59 // case we need a GLXFBConfig for the window in order to create a |
| 73 // context for it. | 60 // context for it. |
| 74 // | 61 // |
| 75 // TODO(kbr): this is not a reliable code path. On platforms which | 62 // TODO(kbr): this is not a reliable code path. On platforms which |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 found = true; | 98 found = true; |
| 112 break; | 99 break; |
| 113 } | 100 } |
| 114 } | 101 } |
| 115 if (found) { | 102 if (found) { |
| 116 return configs.get()[i]; | 103 return configs.get()[i]; |
| 117 } | 104 } |
| 118 return nullptr; | 105 return nullptr; |
| 119 } | 106 } |
| 120 | 107 |
| 108 bool CreateDummyWindow(Display* display) { |
| 109 DCHECK(display); |
| 110 gfx::AcceleratedWidget parent_window = |
| 111 RootWindow(display, DefaultScreen(display)); |
| 112 // We create a window with CopyFromParent visual so that we have the same |
| 113 // visual as NativeViewGLSurfaceGLX (i.e. same GLXFBConfig), to ensure |
| 114 // contexts are compatible and can be made current with either. |
| 115 gfx::AcceleratedWidget window = |
| 116 XCreateWindow(display, parent_window, 0, 0, 1, 1, 0, CopyFromParent, |
| 117 InputOutput, CopyFromParent, 0, nullptr); |
| 118 if (!window) { |
| 119 LOG(ERROR) << "XCreateWindow failed"; |
| 120 return false; |
| 121 } |
| 122 GLXFBConfig config = GetConfigForWindow(display, window); |
| 123 GLXWindow glx_window = glXCreateWindow(display, config, window, nullptr); |
| 124 if (!glx_window) { |
| 125 LOG(ERROR) << "glXCreateWindow failed"; |
| 126 XDestroyWindow(display, window); |
| 127 return false; |
| 128 } |
| 129 glXDestroyWindow(display, glx_window); |
| 130 XDestroyWindow(display, window); |
| 131 return true; |
| 132 } |
| 133 |
| 121 class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider { | 134 class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider { |
| 122 public: | 135 public: |
| 123 explicit OMLSyncControlVSyncProvider(GLXWindow glx_window) | 136 explicit OMLSyncControlVSyncProvider(GLXWindow glx_window) |
| 124 : SyncControlVSyncProvider(), | 137 : SyncControlVSyncProvider(), glx_window_(glx_window) {} |
| 125 glx_window_(glx_window) { | |
| 126 } | |
| 127 | 138 |
| 128 ~OMLSyncControlVSyncProvider() override {} | 139 ~OMLSyncControlVSyncProvider() override {} |
| 129 | 140 |
| 130 protected: | 141 protected: |
| 131 bool GetSyncValues(int64_t* system_time, | 142 bool GetSyncValues(int64_t* system_time, |
| 132 int64_t* media_stream_counter, | 143 int64_t* media_stream_counter, |
| 133 int64_t* swap_buffer_counter) override { | 144 int64_t* swap_buffer_counter) override { |
| 134 return glXGetSyncValuesOML(g_display, glx_window_, system_time, | 145 return glXGetSyncValuesOML(g_display, glx_window_, system_time, |
| 135 media_stream_counter, swap_buffer_counter); | 146 media_stream_counter, swap_buffer_counter); |
| 136 } | 147 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 148 | 159 |
| 149 return true; | 160 return true; |
| 150 } | 161 } |
| 151 | 162 |
| 152 private: | 163 private: |
| 153 GLXWindow glx_window_; | 164 GLXWindow glx_window_; |
| 154 | 165 |
| 155 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); | 166 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); |
| 156 }; | 167 }; |
| 157 | 168 |
| 158 class SGIVideoSyncThread | 169 class SGIVideoSyncThread : public base::Thread, |
| 159 : public base::Thread, | 170 public base::NonThreadSafe, |
| 160 public base::NonThreadSafe, | 171 public base::RefCounted<SGIVideoSyncThread> { |
| 161 public base::RefCounted<SGIVideoSyncThread> { | |
| 162 public: | 172 public: |
| 163 static scoped_refptr<SGIVideoSyncThread> Create() { | 173 static scoped_refptr<SGIVideoSyncThread> Create() { |
| 164 if (!g_video_sync_thread) { | 174 if (!g_video_sync_thread) { |
| 165 g_video_sync_thread = new SGIVideoSyncThread(); | 175 g_video_sync_thread = new SGIVideoSyncThread(); |
| 166 g_video_sync_thread->Start(); | 176 g_video_sync_thread->Start(); |
| 167 } | 177 } |
| 168 return g_video_sync_thread; | 178 return g_video_sync_thread; |
| 169 } | 179 } |
| 170 | 180 |
| 171 private: | 181 private: |
| 172 friend class base::RefCounted<SGIVideoSyncThread>; | 182 friend class base::RefCounted<SGIVideoSyncThread>; |
| 173 | 183 |
| 174 SGIVideoSyncThread() : base::Thread("SGI_video_sync") { | 184 SGIVideoSyncThread() : base::Thread("SGI_video_sync") { |
| 175 DCHECK(CalledOnValidThread()); | 185 DCHECK(CalledOnValidThread()); |
| 176 } | 186 } |
| 177 | 187 |
| 178 ~SGIVideoSyncThread() override { | 188 ~SGIVideoSyncThread() override { |
| 179 DCHECK(CalledOnValidThread()); | 189 DCHECK(CalledOnValidThread()); |
| 180 g_video_sync_thread = nullptr; | 190 g_video_sync_thread = nullptr; |
| 181 Stop(); | 191 Stop(); |
| 182 } | 192 } |
| 183 | 193 |
| 184 static SGIVideoSyncThread* g_video_sync_thread; | 194 static SGIVideoSyncThread* g_video_sync_thread; |
| 185 | 195 |
| 186 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread); | 196 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread); |
| 187 }; | 197 }; |
| 188 | 198 |
| 189 class SGIVideoSyncProviderThreadShim { | 199 class SGIVideoSyncProviderThreadShim { |
| 190 public: | 200 public: |
| 191 explicit SGIVideoSyncProviderThreadShim(GLXFBConfig config, | 201 explicit SGIVideoSyncProviderThreadShim(gfx::AcceleratedWidget parent_window) |
| 192 GLXWindow glx_window) | 202 : parent_window_(parent_window), |
| 193 : config_(config), | 203 window_(0), |
| 194 glx_window_(glx_window), | 204 glx_window_(0), |
| 195 context_(nullptr), | |
| 196 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 205 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 197 cancel_vsync_flag_(), | 206 cancel_vsync_flag_(), |
| 198 vsync_lock_() { | 207 vsync_lock_() { |
| 199 // This ensures that creation of |window_| has occured when this shim | 208 // This ensures that creation of |parent_window_| has occured when this shim |
| 200 // is executing in the same process as the call to create |window_|. | 209 // is executing in the same thread as the call to create |parent_window_|. |
| 201 XSync(g_display, False); | 210 XSync(g_display, False); |
| 202 } | 211 } |
| 203 | 212 |
| 204 virtual ~SGIVideoSyncProviderThreadShim() { | 213 virtual ~SGIVideoSyncProviderThreadShim() { |
| 205 if (context_) { | 214 if (glx_window_) |
| 206 glXDestroyContext(display_, context_); | 215 glXDestroyWindow(display_, glx_window_); |
| 207 context_ = nullptr; | 216 |
| 208 } | 217 if (window_) |
| 218 XDestroyWindow(display_, window_); |
| 209 } | 219 } |
| 210 | 220 |
| 211 base::CancellationFlag* cancel_vsync_flag() { | 221 base::CancellationFlag* cancel_vsync_flag() { return &cancel_vsync_flag_; } |
| 212 return &cancel_vsync_flag_; | |
| 213 } | |
| 214 | 222 |
| 215 base::Lock* vsync_lock() { | 223 base::Lock* vsync_lock() { return &vsync_lock_; } |
| 216 return &vsync_lock_; | |
| 217 } | |
| 218 | 224 |
| 219 void Initialize() { | 225 void Initialize() { |
| 220 DCHECK(display_); | 226 DCHECK(display_); |
| 221 | 227 |
| 222 context_ = | 228 window_ = |
| 223 glXCreateNewContext(display_, config_, GLX_RGBA_TYPE, nullptr, True); | 229 XCreateWindow(display_, parent_window_, 0, 0, 1, 1, 0, CopyFromParent, |
| 230 InputOutput, CopyFromParent, 0, nullptr); |
| 231 if (!window_) { |
| 232 LOG(ERROR) << "video_sync: XCreateWindow failed"; |
| 233 return; |
| 234 } |
| 224 | 235 |
| 225 DCHECK(nullptr != context_); | 236 GLXFBConfig config = GetConfigForWindow(display_, window_); |
| 237 DCHECK(config); |
| 238 |
| 239 glx_window_ = glXCreateWindow(display_, config, window_, nullptr); |
| 240 if (!glx_window_) { |
| 241 LOG(ERROR) << "video_sync: glXCreateWindow failed"; |
| 242 return; |
| 243 } |
| 244 |
| 245 // Create the context only once for all vsync providers. |
| 246 if (!context_) { |
| 247 context_ = |
| 248 glXCreateNewContext(display_, config, GLX_RGBA_TYPE, nullptr, True); |
| 249 if (!context_) |
| 250 LOG(ERROR) << "video_sync: glXCreateNewContext failed"; |
| 251 } |
| 226 } | 252 } |
| 227 | 253 |
| 228 void GetVSyncParameters( | 254 void GetVSyncParameters( |
| 229 const gfx::VSyncProvider::UpdateVSyncCallback& callback) { | 255 const gfx::VSyncProvider::UpdateVSyncCallback& callback) { |
| 230 base::TimeTicks now; | 256 base::TimeTicks now; |
| 231 { | 257 { |
| 232 // Don't allow |window_| destruction while we're probing vsync. | 258 // Don't allow |window_| destruction while we're probing vsync. |
| 233 base::AutoLock locked(vsync_lock_); | 259 base::AutoLock locked(vsync_lock_); |
| 234 | 260 |
| 235 if (!context_ || cancel_vsync_flag_.IsSet()) | 261 if (!context_ || cancel_vsync_flag_.IsSet()) |
| 236 return; | 262 return; |
| 237 | 263 |
| 238 glXMakeContextCurrent(display_, glx_window_, glx_window_, context_); | 264 glXMakeContextCurrent(display_, glx_window_, glx_window_, context_); |
| 239 | 265 |
| 240 unsigned int retrace_count = 0; | 266 unsigned int retrace_count = 0; |
| 241 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) | 267 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) |
| 242 return; | 268 return; |
| 243 | 269 |
| 244 TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD); | 270 TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD); |
| 245 now = base::TimeTicks::Now(); | 271 now = base::TimeTicks::Now(); |
| 246 | 272 |
| 247 glXMakeContextCurrent(display_, 0, 0, nullptr); | 273 glXMakeContextCurrent(display_, 0, 0, nullptr); |
| 248 } | 274 } |
| 249 | 275 |
| 250 const base::TimeDelta kDefaultInterval = | 276 const base::TimeDelta kDefaultInterval = |
| 251 base::TimeDelta::FromSeconds(1) / 60; | 277 base::TimeDelta::FromSeconds(1) / 60; |
| 252 | 278 |
| 253 task_runner_->PostTask( | 279 task_runner_->PostTask(FROM_HERE, |
| 254 FROM_HERE, base::Bind(callback, now, kDefaultInterval)); | 280 base::Bind(callback, now, kDefaultInterval)); |
| 255 } | 281 } |
| 256 | 282 |
| 257 private: | 283 private: |
| 258 // For initialization of display_ in GLSurface::InitializeOneOff before | 284 // For initialization of display_ in GLSurface::InitializeOneOff before |
| 259 // the sandbox goes up. | 285 // the sandbox goes up. |
| 260 friend class gl::GLSurfaceGLX; | 286 friend class gl::GLSurfaceGLX; |
| 261 | 287 |
| 288 // We only need one Display and GLXContext because we only use one thread for |
| 289 // SGI_video_sync. The display is created in GLSurfaceGLX::InitializeOneOff |
| 290 // and the context is created the first time a vsync provider is initialized. |
| 262 static Display* display_; | 291 static Display* display_; |
| 292 static GLXContext context_; |
| 263 | 293 |
| 264 GLXFBConfig config_; | 294 gfx::AcceleratedWidget parent_window_; |
| 295 |
| 296 gfx::AcceleratedWidget window_; |
| 265 GLXWindow glx_window_; | 297 GLXWindow glx_window_; |
| 266 GLXContext context_; | |
| 267 | 298 |
| 268 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 299 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 269 | 300 |
| 270 base::CancellationFlag cancel_vsync_flag_; | 301 base::CancellationFlag cancel_vsync_flag_; |
| 271 base::Lock vsync_lock_; | 302 base::Lock vsync_lock_; |
| 272 | 303 |
| 273 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); | 304 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); |
| 274 }; | 305 }; |
| 275 | 306 |
| 276 class SGIVideoSyncVSyncProvider | 307 class SGIVideoSyncVSyncProvider |
| 277 : public gfx::VSyncProvider, | 308 : public gfx::VSyncProvider, |
| 278 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { | 309 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { |
| 279 public: | 310 public: |
| 280 explicit SGIVideoSyncVSyncProvider(GLXFBConfig config, GLXWindow glx_window) | 311 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget parent_window) |
| 281 : vsync_thread_(SGIVideoSyncThread::Create()), | 312 : vsync_thread_(SGIVideoSyncThread::Create()), |
| 282 shim_(new SGIVideoSyncProviderThreadShim(config, glx_window)), | 313 shim_(new SGIVideoSyncProviderThreadShim(parent_window)), |
| 283 cancel_vsync_flag_(shim_->cancel_vsync_flag()), | 314 cancel_vsync_flag_(shim_->cancel_vsync_flag()), |
| 284 vsync_lock_(shim_->vsync_lock()) { | 315 vsync_lock_(shim_->vsync_lock()) { |
| 285 vsync_thread_->task_runner()->PostTask( | 316 vsync_thread_->task_runner()->PostTask( |
| 286 FROM_HERE, base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, | 317 FROM_HERE, base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, |
| 287 base::Unretained(shim_.get()))); | 318 base::Unretained(shim_.get()))); |
| 288 } | 319 } |
| 289 | 320 |
| 290 ~SGIVideoSyncVSyncProvider() override { | 321 ~SGIVideoSyncVSyncProvider() override { |
| 291 { | 322 { |
| 292 base::AutoLock locked(*vsync_lock_); | 323 base::AutoLock locked(*vsync_lock_); |
| 293 cancel_vsync_flag_->Set(); | 324 cancel_vsync_flag_->Set(); |
| 294 } | 325 } |
| 295 | 326 |
| 296 // Hand-off |shim_| to be deleted on the |vsync_thread_|. | 327 // Hand-off |shim_| to be deleted on the |vsync_thread_|. |
| 297 vsync_thread_->task_runner()->DeleteSoon(FROM_HERE, shim_.release()); | 328 vsync_thread_->task_runner()->DeleteSoon(FROM_HERE, shim_.release()); |
| 298 } | 329 } |
| 299 | 330 |
| 300 void GetVSyncParameters( | 331 void GetVSyncParameters( |
| 301 const gfx::VSyncProvider::UpdateVSyncCallback& callback) override { | 332 const gfx::VSyncProvider::UpdateVSyncCallback& callback) override { |
| 302 if (kGetVSyncParametersMinSeconds > 0) { | |
| 303 base::TimeTicks now = base::TimeTicks::Now(); | |
| 304 base::TimeDelta delta = now - last_get_vsync_parameters_time_; | |
| 305 if (delta.InSeconds() < kGetVSyncParametersMinSeconds) | |
| 306 return; | |
| 307 last_get_vsync_parameters_time_ = now; | |
| 308 } | |
| 309 | |
| 310 // Only one outstanding request per surface. | 333 // Only one outstanding request per surface. |
| 311 if (!pending_callback_) { | 334 if (!pending_callback_) { |
| 312 pending_callback_.reset( | 335 pending_callback_.reset( |
| 313 new gfx::VSyncProvider::UpdateVSyncCallback(callback)); | 336 new gfx::VSyncProvider::UpdateVSyncCallback(callback)); |
| 314 vsync_thread_->task_runner()->PostTask( | 337 vsync_thread_->task_runner()->PostTask( |
| 315 FROM_HERE, | 338 FROM_HERE, |
| 316 base::Bind( | 339 base::Bind( |
| 317 &SGIVideoSyncProviderThreadShim::GetVSyncParameters, | 340 &SGIVideoSyncProviderThreadShim::GetVSyncParameters, |
| 318 base::Unretained(shim_.get()), | 341 base::Unretained(shim_.get()), |
| 319 base::Bind(&SGIVideoSyncVSyncProvider::PendingCallbackRunner, | 342 base::Bind(&SGIVideoSyncVSyncProvider::PendingCallbackRunner, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 335 std::unique_ptr<SGIVideoSyncProviderThreadShim> shim_; | 358 std::unique_ptr<SGIVideoSyncProviderThreadShim> shim_; |
| 336 | 359 |
| 337 std::unique_ptr<gfx::VSyncProvider::UpdateVSyncCallback> pending_callback_; | 360 std::unique_ptr<gfx::VSyncProvider::UpdateVSyncCallback> pending_callback_; |
| 338 | 361 |
| 339 // Raw pointers to sync primitives owned by the shim_. | 362 // Raw pointers to sync primitives owned by the shim_. |
| 340 // These will only be referenced before we post a task to destroy | 363 // These will only be referenced before we post a task to destroy |
| 341 // the shim_, so they are safe to access. | 364 // the shim_, so they are safe to access. |
| 342 base::CancellationFlag* cancel_vsync_flag_; | 365 base::CancellationFlag* cancel_vsync_flag_; |
| 343 base::Lock* vsync_lock_; | 366 base::Lock* vsync_lock_; |
| 344 | 367 |
| 345 base::TimeTicks last_get_vsync_parameters_time_; | |
| 346 | |
| 347 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); | 368 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); |
| 348 }; | 369 }; |
| 349 | 370 |
| 350 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = nullptr; | 371 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = nullptr; |
| 351 | 372 |
| 352 // In order to take advantage of GLX_SGI_video_sync, we need a display | 373 // In order to take advantage of GLX_SGI_video_sync, we need a display |
| 353 // for use on a separate thread. We must allocate this before the sandbox | 374 // for use on a separate thread. We must allocate this before the sandbox |
| 354 // goes up (rather than on-demand when we start the thread). | 375 // goes up (rather than on-demand when we start the thread). |
| 355 Display* SGIVideoSyncProviderThreadShim::display_ = nullptr; | 376 Display* SGIVideoSyncProviderThreadShim::display_ = nullptr; |
| 377 GLXContext SGIVideoSyncProviderThreadShim::context_ = 0; |
| 356 | 378 |
| 357 } // namespace | 379 } // namespace |
| 358 | 380 |
| 359 GLSurfaceGLX::GLSurfaceGLX() {} | 381 GLSurfaceGLX::GLSurfaceGLX() {} |
| 360 | 382 |
| 361 bool GLSurfaceGLX::InitializeOneOff() { | 383 bool GLSurfaceGLX::InitializeOneOff() { |
| 362 static bool initialized = false; | 384 static bool initialized = false; |
| 363 if (initialized) | 385 if (initialized) |
| 364 return true; | 386 return true; |
| 365 | 387 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 380 if (!glXQueryVersion(g_display, &major, &minor)) { | 402 if (!glXQueryVersion(g_display, &major, &minor)) { |
| 381 LOG(ERROR) << "glxQueryVersion failed"; | 403 LOG(ERROR) << "glxQueryVersion failed"; |
| 382 return false; | 404 return false; |
| 383 } | 405 } |
| 384 | 406 |
| 385 if (major == 1 && minor < 3) { | 407 if (major == 1 && minor < 3) { |
| 386 LOG(ERROR) << "GLX 1.3 or later is required."; | 408 LOG(ERROR) << "GLX 1.3 or later is required."; |
| 387 return false; | 409 return false; |
| 388 } | 410 } |
| 389 | 411 |
| 390 g_glx_context_create = | 412 g_glx_context_create = HasGLXExtension("GLX_ARB_create_context"); |
| 391 HasGLXExtension("GLX_ARB_create_context"); | |
| 392 g_glx_create_context_robustness_supported = | 413 g_glx_create_context_robustness_supported = |
| 393 HasGLXExtension("GLX_ARB_create_context_robustness"); | 414 HasGLXExtension("GLX_ARB_create_context_robustness"); |
| 394 g_glx_create_context_profile_supported = | 415 g_glx_create_context_profile_supported = |
| 395 HasGLXExtension("GLX_ARB_create_context_profile"); | 416 HasGLXExtension("GLX_ARB_create_context_profile"); |
| 396 g_glx_create_context_profile_es2_supported = | 417 g_glx_create_context_profile_es2_supported = |
| 397 HasGLXExtension("GLX_ARB_create_context_es2_profile"); | 418 HasGLXExtension("GLX_ARB_create_context_es2_profile"); |
| 398 g_glx_texture_from_pixmap_supported = | 419 g_glx_texture_from_pixmap_supported = |
| 399 HasGLXExtension("GLX_EXT_texture_from_pixmap"); | 420 HasGLXExtension("GLX_EXT_texture_from_pixmap"); |
| 400 g_glx_oml_sync_control_supported = | 421 g_glx_oml_sync_control_supported = HasGLXExtension("GLX_OML_sync_control"); |
| 401 HasGLXExtension("GLX_OML_sync_control"); | |
| 402 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; | 422 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; |
| 403 g_glx_sgi_video_sync_supported = | 423 g_glx_sgi_video_sync_supported = HasGLXExtension("GLX_SGI_video_sync"); |
| 404 HasGLXExtension("GLX_SGI_video_sync") && | |
| 405 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 406 switches::kEnableSgiVideoSync); | |
| 407 | 424 |
| 408 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) | 425 // We create a dummy unmapped window for both the main Display and the video |
| 409 SGIVideoSyncProviderThreadShim::display_ = gfx::OpenNewXDisplay(); | 426 // sync Display so that the Nvidia driver can initialize itself before the |
| 427 // sandbox is set up. |
| 428 // Unfortunately some fds e.g. /dev/nvidia0 are cached per thread and because |
| 429 // we can't start threads before the sandbox is set up, these are accessed |
| 430 // through the broker process. See GpuProcessPolicy::InitGpuBrokerProcess. |
| 431 if (!CreateDummyWindow(g_display)) { |
| 432 LOG(ERROR) << "CreateDummyWindow(g_display) failed"; |
| 433 return false; |
| 434 } |
| 435 |
| 436 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) { |
| 437 Display* video_sync_display = gfx::OpenNewXDisplay(); |
| 438 if (!CreateDummyWindow(video_sync_display)) { |
| 439 LOG(ERROR) << "CreateDummyWindow(video_sync_display) failed"; |
| 440 return false; |
| 441 } |
| 442 SGIVideoSyncProviderThreadShim::display_ = video_sync_display; |
| 443 } |
| 410 | 444 |
| 411 initialized = true; | 445 initialized = true; |
| 412 return true; | 446 return true; |
| 413 } | 447 } |
| 414 | 448 |
| 415 // static | 449 // static |
| 416 const char* GLSurfaceGLX::GetGLXExtensions() { | 450 const char* GLSurfaceGLX::GetGLXExtensions() { |
| 417 return glXQueryExtensionsString(g_display, 0); | 451 return glXQueryExtensionsString(g_display, 0); |
| 418 } | 452 } |
| 419 | 453 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 return g_glx_oml_sync_control_supported; | 486 return g_glx_oml_sync_control_supported; |
| 453 } | 487 } |
| 454 | 488 |
| 455 void* GLSurfaceGLX::GetDisplay() { | 489 void* GLSurfaceGLX::GetDisplay() { |
| 456 return g_display; | 490 return g_display; |
| 457 } | 491 } |
| 458 | 492 |
| 459 GLSurfaceGLX::~GLSurfaceGLX() {} | 493 GLSurfaceGLX::~GLSurfaceGLX() {} |
| 460 | 494 |
| 461 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) | 495 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
| 462 : parent_window_(window), window_(0), glx_window_(0), config_(nullptr) { | 496 : parent_window_(window), window_(0), glx_window_(0), config_(nullptr) {} |
| 463 } | |
| 464 | 497 |
| 465 GLXDrawable NativeViewGLSurfaceGLX::GetDrawableHandle() const { | 498 GLXDrawable NativeViewGLSurfaceGLX::GetDrawableHandle() const { |
| 466 return glx_window_; | 499 return glx_window_; |
| 467 } | 500 } |
| 468 | 501 |
| 469 bool NativeViewGLSurfaceGLX::Initialize(GLSurface::Format format) { | 502 bool NativeViewGLSurfaceGLX::Initialize(GLSurface::Format format) { |
| 470 XWindowAttributes attributes; | 503 XWindowAttributes attributes; |
| 471 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { | 504 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
| 472 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ | 505 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
| 473 << "."; | 506 << "."; |
| 474 return false; | 507 return false; |
| 475 } | 508 } |
| 476 size_ = gfx::Size(attributes.width, attributes.height); | 509 size_ = gfx::Size(attributes.width, attributes.height); |
| 477 // Create a child window, with a CopyFromParent visual (to avoid inducing | 510 // Create a child window, with a CopyFromParent visual (to avoid inducing |
| 478 // extra blits in the driver), that we can resize exactly in Resize(), | 511 // extra blits in the driver), that we can resize exactly in Resize(), |
| 479 // correctly ordered with GL, so that we don't have invalid transient states. | 512 // correctly ordered with GL, so that we don't have invalid transient states. |
| 480 // See https://crbug.com/326995. | 513 // See https://crbug.com/326995. |
| 481 XSetWindowAttributes swa; | 514 XSetWindowAttributes swa; |
| 482 memset(&swa, 0, sizeof(swa)); | 515 memset(&swa, 0, sizeof(swa)); |
| 483 swa.background_pixmap = 0; | 516 swa.background_pixmap = 0; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 496 } | 529 } |
| 497 XFlush(g_display); | 530 XFlush(g_display); |
| 498 | 531 |
| 499 GetConfig(); | 532 GetConfig(); |
| 500 DCHECK(config_); | 533 DCHECK(config_); |
| 501 glx_window_ = glXCreateWindow(g_display, config_, window_, NULL); | 534 glx_window_ = glXCreateWindow(g_display, config_, window_, NULL); |
| 502 | 535 |
| 503 if (g_glx_oml_sync_control_supported) { | 536 if (g_glx_oml_sync_control_supported) { |
| 504 vsync_provider_.reset(new OMLSyncControlVSyncProvider(glx_window_)); | 537 vsync_provider_.reset(new OMLSyncControlVSyncProvider(glx_window_)); |
| 505 } else if (g_glx_sgi_video_sync_supported) { | 538 } else if (g_glx_sgi_video_sync_supported) { |
| 506 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(config_, glx_window_)); | 539 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(parent_window_)); |
| 507 } else { | 540 } else { |
| 508 // Assume a refresh rate of 59.9 Hz, which will cause us to skip | 541 // Assume a refresh rate of 59.9 Hz, which will cause us to skip |
| 509 // 1 frame every 10 seconds on a 60Hz monitor, but will prevent us | 542 // 1 frame every 10 seconds on a 60Hz monitor, but will prevent us |
| 510 // from blocking the GPU service due to back pressure. This would still | 543 // from blocking the GPU service due to back pressure. This would still |
| 511 // encounter backpressure on a <60Hz monitor, but hopefully that is | 544 // encounter backpressure on a <60Hz monitor, but hopefully that is |
| 512 // not common. | 545 // not common. |
| 513 const base::TimeTicks kDefaultTimebase; | 546 const base::TimeTicks kDefaultTimebase; |
| 514 const base::TimeDelta kDefaultInterval = | 547 const base::TimeDelta kDefaultInterval = |
| 515 base::TimeDelta::FromSeconds(1) / 59.9; | 548 base::TimeDelta::FromSeconds(1) / 59.9; |
| 516 vsync_provider_.reset( | 549 vsync_provider_.reset( |
| (...skipping 20 matching lines...) Expand all Loading... |
| 537 } | 570 } |
| 538 } | 571 } |
| 539 | 572 |
| 540 bool NativeViewGLSurfaceGLX::CanDispatchEvent(const ui::PlatformEvent& event) { | 573 bool NativeViewGLSurfaceGLX::CanDispatchEvent(const ui::PlatformEvent& event) { |
| 541 return event->type == Expose && event->xexpose.window == window_; | 574 return event->type == Expose && event->xexpose.window == window_; |
| 542 } | 575 } |
| 543 | 576 |
| 544 uint32_t NativeViewGLSurfaceGLX::DispatchEvent(const ui::PlatformEvent& event) { | 577 uint32_t NativeViewGLSurfaceGLX::DispatchEvent(const ui::PlatformEvent& event) { |
| 545 XEvent forwarded_event = *event; | 578 XEvent forwarded_event = *event; |
| 546 forwarded_event.xexpose.window = parent_window_; | 579 forwarded_event.xexpose.window = parent_window_; |
| 547 XSendEvent(g_display, parent_window_, False, ExposureMask, | 580 XSendEvent(g_display, parent_window_, False, ExposureMask, &forwarded_event); |
| 548 &forwarded_event); | |
| 549 XFlush(g_display); | 581 XFlush(g_display); |
| 550 return ui::POST_DISPATCH_STOP_PROPAGATION; | 582 return ui::POST_DISPATCH_STOP_PROPAGATION; |
| 551 } | 583 } |
| 552 | 584 |
| 553 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size, | 585 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size, |
| 554 float scale_factor, | 586 float scale_factor, |
| 555 bool has_alpha) { | 587 bool has_alpha) { |
| 556 size_ = size; | 588 size_ = size; |
| 557 glXWaitGL(); | 589 glXWaitGL(); |
| 558 XResizeWindow(g_display, window_, size.width(), size.height()); | 590 XResizeWindow(g_display, window_, size.width(), size.height()); |
| 559 glXWaitX(); | 591 glXWaitX(); |
| 560 return true; | 592 return true; |
| 561 } | 593 } |
| 562 | 594 |
| 563 bool NativeViewGLSurfaceGLX::IsOffscreen() { | 595 bool NativeViewGLSurfaceGLX::IsOffscreen() { |
| 564 return false; | 596 return false; |
| 565 } | 597 } |
| 566 | 598 |
| 567 gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers() { | 599 gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers() { |
| 568 TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", | 600 TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width", |
| 569 "width", GetSize().width(), | 601 GetSize().width(), "height", GetSize().height()); |
| 570 "height", GetSize().height()); | |
| 571 | 602 |
| 572 glXSwapBuffers(g_display, GetDrawableHandle()); | 603 glXSwapBuffers(g_display, GetDrawableHandle()); |
| 573 return gfx::SwapResult::SWAP_ACK; | 604 return gfx::SwapResult::SWAP_ACK; |
| 574 } | 605 } |
| 575 | 606 |
| 576 gfx::Size NativeViewGLSurfaceGLX::GetSize() { | 607 gfx::Size NativeViewGLSurfaceGLX::GetSize() { |
| 577 return size_; | 608 return size_; |
| 578 } | 609 } |
| 579 | 610 |
| 580 void* NativeViewGLSurfaceGLX::GetHandle() { | 611 void* NativeViewGLSurfaceGLX::GetHandle() { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 if (!config_) | 698 if (!config_) |
| 668 config_ = GetConfigForWindow(g_display, window_); | 699 config_ = GetConfigForWindow(g_display, window_); |
| 669 return config_; | 700 return config_; |
| 670 } | 701 } |
| 671 | 702 |
| 672 UnmappedNativeViewGLSurfaceGLX::~UnmappedNativeViewGLSurfaceGLX() { | 703 UnmappedNativeViewGLSurfaceGLX::~UnmappedNativeViewGLSurfaceGLX() { |
| 673 Destroy(); | 704 Destroy(); |
| 674 } | 705 } |
| 675 | 706 |
| 676 } // namespace gl | 707 } // namespace gl |
| OLD | NEW |