Closed Bug 1197954 Opened 10 years ago Closed 9 years ago

Implement a hardware Vsync source for GLX

Categories

(Core :: Graphics, defect)

Unspecified
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla50
Tracking Status
firefox50 --- fixed

People

(Reporter: acomminos, Assigned: acomminos)

References

Details

Attachments

(3 files, 7 obsolete files)

9.36 KB, patch
lsalzman
: review+
Details | Diff | Splinter Review
7.06 KB, patch
acomminos
: review+
Details | Diff | Splinter Review
9.00 KB, patch
lsalzman
: review+
Details | Diff | Splinter Review
GLX has several extensions we can use to wait on buffer swaps, such as GLX_SGI_video_sync. We can use these to provide vsync timing information on Linux.
Fairly straightforward, adds sync support to GLContextGLX.
Attachment #8652562 - Flags: review?(jgilbert)
This adds a flag to context creation to use a separate display connection. This is necessary to prevent contention on the Vsync thread.
Attachment #8652563 - Flags: review?(jgilbert)
This adds a vsync provider using SGI_video_sync, using glXWaitVideoSync to pull swap intervals.
Attachment #8652566 - Flags: review?(mchang)
Initial talos impressions: https://treeherder.mozilla.org/perf.html#/compare?originalProject=mozilla-central&originalRevision=23a04f9a321c&newProject=try&newRevision=7d1233f5148f Doesn't look to be affecting any results with the X11 basic compositor, hooray.
Updated to check result of setting up GLXDisplay and fallback appropriately.
Attachment #8652566 - Attachment is obsolete: true
Attachment #8652566 - Flags: review?(mchang)
Attachment #8652616 - Flags: review?(mchang)
Comment on attachment 8652616 [details] [diff] [review] Implement Linux hardware vsync using GLX_SGI_video_sync. Review of attachment 8652616 [details] [diff] [review]: ----------------------------------------------------------------- ::: gfx/thebes/gfxPlatformGtk.cpp @@ +593,5 @@ > + , mVsyncThread("GLXVsyncThread") > + , mVsyncEnabledLock("GLXVsyncEnabledLock") > + , mVsyncEnabled(false) > + { > + MOZ_RELEASE_ASSERT(mVsyncThread.Start(), "Failed to start GLX vsync thread"); Can we check this in setup instead? If it doesn't work correctly, we can just fall back to software. @@ +597,5 @@ > + MOZ_RELEASE_ASSERT(mVsyncThread.Start(), "Failed to start GLX vsync thread"); > + } > + > + // Sets up the display's GL context on a worker thread. > + // Returns true if setup was a success. nit: add comment why you need this. @@ +598,5 @@ > + } > + > + // Sets up the display's GL context on a worker thread. > + // Returns true if setup was a success. > + bool Setup() assert which thread this happens on. @@ +605,5 @@ > + CancelableTask* vsyncSetup = NewRunnableMethod(this, &GLXDisplay::SetupGLContext); > + mVsyncThread.message_loop()->PostTask(FROM_HERE, vsyncSetup); > + // Wait until the setup has completed. > + lock.Wait(); > + return mGLContext; nit: return mGLContext == nullptr; Make this explicit. @@ +610,5 @@ > + } > + > + virtual void EnableVsync() override > + { > + MOZ_ASSERT(mGLContext, "GLContext not setup!"); assert main thread. @@ +616,5 @@ > + MonitorAutoLock lock(mVsyncEnabledLock); > + if (mVsyncEnabled) > + return; > + > + mVsyncEnabled = true; nit: set this to true after we post the task. @@ +628,5 @@ > + mVsyncEnabled = false; > + } > + > + virtual bool IsVsyncEnabled() override > + { Need a lock. @@ +669,5 @@ > + if (!mVsyncEnabled) return; > + } > + > + unsigned int nextSync = syncCounter + 1; > + if (gl::sGLXLibrary.xWaitVideoSync(2, nextSync % 2, nit: Please add a comment explaining this API and the wierdness. @@ +692,5 @@ > + bool mVsyncEnabled; > + }; > +private: > + virtual ~GLXVsyncSource() > + { nit: assert which thread this is destroyed on. @@ +708,5 @@ > + if (!static_cast<GLXVsyncSource::GLXDisplay&>(display).Setup()) { > + NS_WARNING("Failed to setup GLContext, falling back to software vsync."); > + return gfxPlatform::CreateHardwareVsyncSource(); > + } > + display.EnableVsync(); I think you can leave this disabled when this returns.
Attachment #8652616 - Flags: review?(mchang) → feedback+
Updated to address review comments.
Attachment #8652616 - Attachment is obsolete: true
Attachment #8652625 - Flags: review?(mchang)
Comment on attachment 8652625 [details] [diff] [review] Implement Linux hardware vsync using GLX_SGI_video_sync. Review of attachment 8652625 [details] [diff] [review]: ----------------------------------------------------------------- Couple of changes. The biggest is to ensure that we only have 1 vsync loop running at a time. ::: gfx/thebes/gfxPlatformGtk.cpp @@ +575,5 @@ > +{ > +public: > + GLXVsyncSource() > + { > + mGlobalDisplay = new GLXDisplay(); assert main thread. @@ +580,5 @@ > + } > + > + virtual Display& GetGlobalDisplay() override > + { > + return *mGlobalDisplay; assert main thread. @@ +585,5 @@ > + } > + > + class GLXDisplay final : public VsyncSource::Display > + { > + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLXDisplay) Don't make this refcounted. Just make the object instantiate as a member of GlxVsyncSource. @@ +610,5 @@ > + mVsyncThread.message_loop()->PostTask(FROM_HERE, vsyncSetup); > + // Wait until the setup has completed. > + lock.Wait(); > + return mGLContext != nullptr; > + } nit: move SetupGLContext() here. @@ +618,5 @@ > + MOZ_ASSERT(NS_IsMainThread()); > + MOZ_ASSERT(mGLContext, "GLContext not setup!"); > + > + MonitorAutoLock lock(mVsyncEnabledLock); > + if (mVsyncEnabled) nit: add {} @@ +629,5 @@ > + > + virtual void DisableVsync() override > + { > + MonitorAutoLock lock(mVsyncEnabledLock); > + mVsyncEnabled = false; You probably have to keep a pointer to the vsyncStart task from EnableVsync. If We disable Vsync and somehow the vsyncStart hasn't started executing, you need to cancel the vsyncStart task in DisableVsync(). A thing that can happen is that vsync is quickly enabled / disabled. In those cases, you could hit an edge case where the vysnc start runs, quickly called DisableVsync(), and then quickly called EnableVsync(). The first posted task would enter the loop and run vsync. The second task would as well, so you'd have 2 vsync loops. @@ +648,5 @@ > + } > + > + void SetupGLContext() > + { > + MonitorAutoLock lock(mSetupLock); assert ! main thread. Add a comment that this is on the vsync thread. @@ +652,5 @@ > + MonitorAutoLock lock(mSetupLock); > + MOZ_ASSERT(!mGLContext, "GLContext already setup!"); > + > + // Create video sync timer on a separate Display to prevent locking the > + // main thread X display. what happens if we use the main thread X display? If we use a separate X11 display, which physical monitor's vsync does this listen to? @@ +658,5 @@ > + gl::CreateContextFlags::USE_SEPARATE_X11_DISPLAY); > + > + // Test that SGI_video_sync lets us get the counter. > + unsigned int syncCounter = 0; > + if (gl::sGLXLibrary.xGetVideoSync(&syncCounter) != 0) nit: add {} @@ +705,5 @@ > + { > + MOZ_ASSERT(NS_IsMainThread()); > + } > + > + RefPtr<GLXDisplay> mGlobalDisplay; nit: Make this a member instead of a RefPtr.
Attachment #8652625 - Flags: review?(mchang) → feedback+
Updated, thanks. > what happens if we use the main thread X display? If we use a separate X11 display, which physical monitor's vsync does this listen to? If we use the main X display, depending on the GLX implementation we can either: a) crash due to threading issues (mesa) b) block a lot (NVIDIA) Neither are preferable. An X11 display doesn't really correspond to a monitor, so nothing effectively changes with regards to what gets synced. In this case we synchronize with the default CRTC (at least on NVIDIA).
Attachment #8652625 - Attachment is obsolete: true
Attachment #8652938 - Flags: review?(mchang)
Attachment #8652562 - Flags: review?(jgilbert) → review+
Comment on attachment 8652563 [details] [diff] [review] Add support for creating a GLContextGLX with a separate X11 display. Review of attachment 8652563 [details] [diff] [review]: ----------------------------------------------------------------- ::: gfx/gl/GLContextProviderGLX.cpp @@ +1187,5 @@ > return nullptr; > } > > + bool createDisplay = static_cast<bool>(flags & CreateContextFlags::USE_SEPARATE_X11_DISPLAY); > + Display *display; Display* display;
Attachment #8652563 - Flags: review?(jgilbert) → review+
Comment on attachment 8652938 [details] [diff] [review] Implement Linux hardware vsync using GLX_SGI_video_sync. Review of attachment 8652938 [details] [diff] [review]: ----------------------------------------------------------------- ::: gfx/thebes/gfxPlatformGtk.cpp @@ +698,5 @@ > + // until the parity of the counter value changes. > + unsigned int nextSync = syncCounter + 1; > + if (gl::sGLXLibrary.xWaitVideoSync(2, nextSync % 2, > + &syncCounter) == 0) { > + if (syncCounter == (nextSync - 1)) { can syncCounter ever be less than nextVsync - 1? Do we ever get really bad values?
Attachment #8652938 - Flags: review?(mchang) → review+
Will this land anytime soon?
Flags: needinfo?(andrew)
> Will this land anytime soon? Currently this patch retriggers bug 1189132- even if the test infrastructure is an unstable condition, I'd rather not regress obtaining talos results with GL layers, especially considering that half of the benefit of this patch comes from improved glXSwapBuffers timing for GLX implementations that block until VSync. Maybe we'll have to block on bug 1198290 or a real fix.
Flags: needinfo?(andrew)
This moves the GLXFBConfig matching code for windows into its own function so that we can use it to get the root window GLXFBConfig in the vsync source.
Attachment #8726068 - Flags: review?(lsalzman)
Attachment #8652563 - Attachment is obsolete: true
Attachment #8652562 - Attachment is obsolete: true
Updated to listen to vsync events on a GLX context hooked up to the root window instead of a pixmap; this is what many compositors (e.g. compton) do for their SGI_video_sync implementation of vsync. Sending r? to Lee for X11 changes, the vsync strategy hasn't changed.
Attachment #8726070 - Flags: review?(lsalzman)
Attachment #8652938 - Attachment is obsolete: true
Attachment #8726068 - Flags: review?(lsalzman) → review+
Attachment #8726070 - Flags: review?(lsalzman) → review+
Looks like this is causing hangs with talos tests similar to what we had when using the GL compositor with GLX (sigh). Reverting the last commit for now while I figure this out.
Depends on: 1273286
Updated to destroy the GLContext on the correct thread, close the X11 display, and fix a race condition. Thanks!
Attachment #8753377 - Flags: review?(lsalzman)
Attachment #8726070 - Attachment is obsolete: true
Attachment #8753377 - Flags: review?(lsalzman) → review+
With bug 1273286 fixed, we should be good to land this now. If there are still a few machines that are left hanging on talos jobs, the issue should be resolved after a restart.
Pushed by acomminos@mozilla.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/4f20674c7792 Add support for GLX_SGI_video_sync to GLContextProviderGLX. r=jgilbert https://hg.mozilla.org/integration/mozilla-inbound/rev/b3930a21b6ed Implement Linux hardware vsync using GLX_SGI_video_sync. r=mchang,lsalzman
Status: ASSIGNED → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla50
Depends on: 1279309
Depends on: 1279664
Regressions: 1710400
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: