Bug 1628137 - Switch to using WaitForVBlank for vsync on Windows r=jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D70463

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Bert Peers 2020-04-10 02:24:07 +00:00
parent 8b5365a15b
commit 9051184fab
4 changed files with 73 additions and 4 deletions

View File

@ -170,6 +170,34 @@ nsTArray<DXGI_OUTPUT_DESC1> DeviceManagerDx::EnumerateOutputs() {
return outputs;
}
bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor,
RefPtr<IDXGIOutput>* aOutOutput) {
RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
if (!adapter) {
NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor.");
return false;
}
for (UINT i = 0;; ++i) {
RefPtr<IDXGIOutput> output = nullptr;
if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
break;
}
DXGI_OUTPUT_DESC desc;
if (FAILED(output->GetDesc(&desc))) {
continue;
}
if (desc.Monitor == monitor) {
*aOutOutput = output;
return true;
}
}
return false;
}
bool DeviceManagerDx::CheckHardwareStretchingSupport() {
RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();

View File

@ -87,6 +87,10 @@ class DeviceManagerDx final {
// Enumerate and return all outputs on the current adapter.
nsTArray<DXGI_OUTPUT_DESC1> EnumerateOutputs();
// find the IDXGIOutput with a description.Monitor matching
// 'monitor'; returns false if not found or some error occurred.
bool GetOutputFromMonitor(HMONITOR monitor, RefPtr<IDXGIOutput>* aOutOutput);
// Check if the current adapter supports hardware stretching
bool CheckHardwareStretchingSupport();

View File

@ -1621,7 +1621,8 @@ class D3DVsyncSource final : public VsyncSource {
D3DVsyncDisplay()
: mPrevVsync(TimeStamp::Now()),
mVsyncEnabledLock("D3DVsyncEnabledLock"),
mVsyncEnabled(false) {
mVsyncEnabled(false),
mWaitVBlankMonitor(NULL) {
mVsyncThread = new base::Thread("WindowsVsyncThread");
MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
"GFX: Could not start Windows vsync thread");
@ -1796,9 +1797,16 @@ class D3DVsyncSource final : public VsyncSource {
return;
}
// Using WaitForVBlank, the whole system dies because WaitForVBlank
// only works if it's run on the same thread as the Present();
HRESULT hr = DwmFlush();
HRESULT hr = E_FAIL;
if (StaticPrefs::gfx_vsync_use_waitforvblank()) {
UpdateVBlankOutput();
if (mWaitVBlankOutput) {
hr = mWaitVBlankOutput->WaitForVBlank();
}
}
if (!SUCCEEDED(hr)) {
hr = DwmFlush();
}
if (!SUCCEEDED(hr)) {
// DWMFlush isn't working, fallback to software vsync.
ScheduleSoftwareVsync(TimeStamp::Now());
@ -1846,11 +1854,35 @@ class D3DVsyncSource final : public VsyncSource {
return mVsyncThread->thread_id() == PlatformThread::CurrentId();
}
void UpdateVBlankOutput() {
HMONITOR primary_monitor =
MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
if (primary_monitor == mWaitVBlankMonitor && mWaitVBlankOutput) {
return;
}
mWaitVBlankMonitor = primary_monitor;
RefPtr<IDXGIOutput> output = nullptr;
if (DeviceManagerDx* dx = DeviceManagerDx::Get()) {
if (dx->GetOutputFromMonitor(mWaitVBlankMonitor, &output)) {
mWaitVBlankOutput = output;
return;
}
}
// failed to convert a monitor to an output so keep trying
mWaitVBlankOutput = nullptr;
}
TimeStamp mPrevVsync;
Monitor mVsyncEnabledLock;
base::Thread* mVsyncThread;
TimeDuration mVsyncRate;
bool mVsyncEnabled;
HMONITOR mWaitVBlankMonitor;
RefPtr<IDXGIOutput> mWaitVBlankOutput;
}; // end d3dvsyncdisplay
D3DVsyncSource() { mPrimaryDisplay = new D3DVsyncDisplay(); }

View File

@ -3989,6 +3989,11 @@
value: 10
mirror: once
- name: gfx.vsync.use-waitforvblank
type: RelaxedAtomicBool
value: false
mirror: always
# We expose two prefs: gfx.webrender.all and gfx.webrender.enabled.
# The first enables WR+additional features, and the second just enables WR.
# For developer convenience, building with --enable-webrender=true or just