Skip to content

Commit

Permalink
bug 552020 Part 1: Hook into CVDisplayLink to get vsync events on OSX…
Browse files Browse the repository at this point in the history
…. r=benwa,mstange
  • Loading branch information
Mason Chang committed Nov 18, 2014
1 parent 037d5ad commit 74c8040
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 9 deletions.
4 changes: 4 additions & 0 deletions gfx/thebes/gfxPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ gfxPlatform::Init()
}

RegisterStrongMemoryReporter(new GfxMemoryImageReporter());

if (gfxPrefs::HardwareVsyncEnabled() && gfxPrefs::VsyncAlignedCompositor()) {
gPlatform->InitHardwareVsync();
}
}

static bool sLayersIPCIsUp = false;
Expand Down
7 changes: 6 additions & 1 deletion gfx/thebes/gfxPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,14 @@ class gfxPlatform {
gfxPlatform();
virtual ~gfxPlatform();

void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
eFontPrefLang aCharLang, eFontPrefLang aPageLang);

/**
* Initialized hardware vsync based on each platform.
*/
virtual void InitHardwareVsync() {}

/**
* Helper method, creates a draw target for a specific Azure backend.
* Used by CreateOffscreenDrawTarget.
Expand Down
91 changes: 89 additions & 2 deletions gfx/thebes/gfxPlatformMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

#include "nsTArray.h"
#include "mozilla/Preferences.h"
#include "mozilla/VsyncDispatcher.h"
#include "qcms.h"
#include "gfx2DGlue.h"
#include "gfxPrefs.h"

#include <dlfcn.h>
#include <CoreVideo/CoreVideo.h>

#include "nsCocoaFeatures.h"

Expand Down Expand Up @@ -373,14 +375,14 @@ uint32_t
gfxPlatformMac::ReadAntiAliasingThreshold()
{
uint32_t threshold = 0; // default == no threshold

// first read prefs flag to determine whether to use the setting or not
bool useAntiAliasingThreshold = Preferences::GetBool("gfx.use_text_smoothing_setting", false);

// if the pref setting is disabled, return 0 which effectively disables this feature
if (!useAntiAliasingThreshold)
return threshold;

// value set via Appearance pref panel, "Turn off text smoothing for font sizes xxx and smaller"
CFNumberRef prefValue = (CFNumberRef)CFPreferencesCopyAppValue(CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication);

Expand Down Expand Up @@ -419,6 +421,91 @@ gfxPlatformMac::UseProgressivePaint()
return nsCocoaFeatures::OnLionOrLater() && gfxPlatform::UseProgressivePaint();
}

// This is the renderer output callback function, called on the vsync thread
static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
const CVTimeStamp* aNow,
const CVTimeStamp* aOutputTime,
CVOptionFlags aFlagsIn,
CVOptionFlags* aFlagsOut,
void* aDisplayLinkContext)
{
mozilla::VsyncSource* vsyncSource = (mozilla::VsyncSource*) aDisplayLinkContext;
if (vsyncSource->IsVsyncEnabled()) {
// Now refers to "Now" as in when this callback is called or when the current frame
// is displayed. aOutputTime is when the next frame should be displayed.
// Now is VERY VERY noisy, aOutputTime is in the future though.
int64_t timestamp = aOutputTime->hostTime;
mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
mozilla::VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
return kCVReturnSuccess;
} else {
return kCVReturnDisplayLinkNotRunning;
}
}

class OSXVsyncSource MOZ_FINAL : public mozilla::VsyncSource
{
public:
OSXVsyncSource()
{
EnableVsync();
}

virtual void EnableVsync() MOZ_OVERRIDE
{
// Create a display link capable of being used with all active displays
// TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
// situations. According to the docs, it is compatible with all displays running on the computer
// But if we have different monitors at different display rates, we may hit issues.
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not create a display link, returning");
return;
}

// Set the renderer output callback function
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
NS_WARNING("Could not set displaylink output callback");
return;
}

// Activate the display link
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
mDisplayLink = nullptr;
}
}

virtual void DisableVsync() MOZ_OVERRIDE
{
// Release the display link
if (mDisplayLink) {
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
}
}

virtual bool IsVsyncEnabled() MOZ_OVERRIDE
{
return mDisplayLink != nullptr;
}

private:
virtual ~OSXVsyncSource()
{
DisableVsync();
}

// Manages the display link render thread
CVDisplayLinkRef mDisplayLink;
}; // OSXVsyncSource

void
gfxPlatformMac::InitHardwareVsync()
{
nsRefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
mozilla::VsyncDispatcher::GetInstance()->SetVsyncSource(osxVsyncSource);
}

void
gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
{
Expand Down
1 change: 1 addition & 0 deletions gfx/thebes/gfxPlatformMac.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class gfxPlatformMac : public gfxPlatform {

virtual bool UseTiling() MOZ_OVERRIDE;
virtual bool UseProgressivePaint() MOZ_OVERRIDE;
virtual void InitHardwareVsync() MOZ_OVERRIDE;

// lower threshold on font anti-aliasing
uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
Expand Down
8 changes: 7 additions & 1 deletion widget/VsyncDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ VsyncDispatcher::~VsyncDispatcher()
mCompositorObservers.Clear();
}

void
VsyncDispatcher::SetVsyncSource(VsyncSource* aVsyncSource)
{
mVsyncSource = aVsyncSource;
}

void
VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime)
{
Expand Down Expand Up @@ -88,7 +94,7 @@ VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
void
VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
MutexAutoLock lock(mCompositorObserverLock);
if (mCompositorObservers.Contains(aVsyncObserver)) {
mCompositorObservers.RemoveElement(aVsyncObserver);
Expand Down
24 changes: 22 additions & 2 deletions widget/VsyncDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ namespace layers {
class CompositorVsyncObserver;
}

// Controls how and when to enable/disable vsync.
class VsyncSource
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
virtual void EnableVsync() = 0;
virtual void DisableVsync() = 0;
virtual bool IsVsyncEnabled() = 0;

protected:
virtual ~VsyncSource() {}
}; // VsyncSource

class VsyncObserver
{
// Must be destroyed on main thread since the compositor is as well
Expand All @@ -34,7 +47,7 @@ class VsyncObserver
protected:
VsyncObserver() {}
virtual ~VsyncObserver() {}
};
}; // VsyncObserver

// VsyncDispatcher is used to dispatch vsync events to the registered observers.
class VsyncDispatcher
Expand All @@ -44,7 +57,13 @@ class VsyncDispatcher
public:
static VsyncDispatcher* GetInstance();
// Called on the vsync thread when a hardware vsync occurs
// The aVsyncTimestamp can mean different things depending on the platform:
// b2g - The vsync timestamp of the previous frame that was just displayed
// OSX - The vsync timestamp of the upcoming frame
// TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
// Android: TODO
void NotifyVsync(TimeStamp aVsyncTimestamp);
void SetVsyncSource(VsyncSource* aVsyncSource);

// Compositor vsync observers must be added/removed on the compositor thread
void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
Expand All @@ -61,7 +80,8 @@ class VsyncDispatcher
// Can have multiple compositors. On desktop, this is 1 compositor per window
Mutex mCompositorObserverLock;
nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
};
nsRefPtr<VsyncSource> mVsyncSource;
}; // VsyncDispatcher

} // namespace mozilla

Expand Down
4 changes: 2 additions & 2 deletions widget/cocoa/nsAppShell.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

/*
* Runs the main native Cocoa run loop, interrupting it as needed to process
* Gecko events.
* Gecko events.
*/

#ifndef nsAppShell_h_
Expand All @@ -30,7 +30,7 @@ class nsAppShell : public nsBaseAppShell
{
public:
NS_IMETHOD ResumeNative(void);

nsAppShell();

nsresult Init();
Expand Down
2 changes: 1 addition & 1 deletion widget/cocoa/nsAppShell.mm
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) {
}
return NS_OK;
}
};
}; // MacWakeLockListener

// defined in nsCocoaWindow.mm
extern int32_t gXULModalLevel;
Expand Down

0 comments on commit 74c8040

Please sign in to comment.