Support for refresh rate and sync interval (#2989)

* Add support for querying the refresh rate and sync interval
monroegm-disable-blank-issue-2
moudgils 4 years ago committed by GitHub
parent 589a05062b
commit c2b8542bbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,6 +10,17 @@
#include <AzCore/Console/IConsole.h> #include <AzCore/Console/IConsole.h>
void OnVsyncIntervalChanged(uint32_t const& interval)
{
AzFramework::WindowNotificationBus::Broadcast(
&AzFramework::WindowNotificationBus::Events::OnVsyncIntervalChanged, AZ::GetClamp(interval, 0u, 4u));
}
// NOTE: On change, broadcasts the new requested vsync interval to all windows.
// The value of the vsync interval is constrained between 0 and 4
// Vsync intervals greater than 1 are not currently supported on the Vulkan RHI (see #2061 for discussion)
AZ_CVAR(uint32_t, vsync_interval, 1, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval");
namespace AzFramework namespace AzFramework
{ {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -122,6 +133,16 @@ namespace AzFramework
return m_pimpl->GetDpiScaleFactor(); return m_pimpl->GetDpiScaleFactor();
} }
uint32_t NativeWindow::GetDisplayRefreshRate() const
{
return m_pimpl->GetDisplayRefreshRate();
}
uint32_t NativeWindow::GetSyncInterval() const
{
return vsync_interval;
}
/*static*/ bool NativeWindow::GetFullScreenStateOfDefaultWindow() /*static*/ bool NativeWindow::GetFullScreenStateOfDefaultWindow()
{ {
NativeWindowHandle defaultWindowHandle = nullptr; NativeWindowHandle defaultWindowHandle = nullptr;
@ -240,4 +261,10 @@ namespace AzFramework
return 1.0f; return 1.0f;
} }
uint32_t NativeWindow::Implementation::GetDisplayRefreshRate() const
{
// Default to 60
return 60;
}
} // namespace AzFramework } // namespace AzFramework

@ -130,6 +130,8 @@ namespace AzFramework
bool CanToggleFullScreenState() const override; bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override; void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override; float GetDpiScaleFactor() const override;
uint32_t GetSyncInterval() const override;
uint32_t GetDisplayRefreshRate() const override;
//! Get the full screen state of the default window. //! Get the full screen state of the default window.
//! \return True if the default window is currently in full screen, false otherwise. //! \return True if the default window is currently in full screen, false otherwise.
@ -172,6 +174,7 @@ namespace AzFramework
virtual void SetFullScreenState(bool fullScreenState); virtual void SetFullScreenState(bool fullScreenState);
virtual bool CanToggleFullScreenState() const; virtual bool CanToggleFullScreenState() const;
virtual float GetDpiScaleFactor() const; virtual float GetDpiScaleFactor() const;
virtual uint32_t GetDisplayRefreshRate() const;
protected: protected:
uint32_t m_width = 0; uint32_t m_width = 0;

@ -74,6 +74,12 @@ namespace AzFramework
//! to a "standard" value of 96, the default for Windows in a DPI unaware setting. This can //! to a "standard" value of 96, the default for Windows in a DPI unaware setting. This can
//! be used to scale user interface elements to ensure legibility on high density displays. //! be used to scale user interface elements to ensure legibility on high density displays.
virtual float GetDpiScaleFactor() const = 0; virtual float GetDpiScaleFactor() const = 0;
//! Returns the sync interval which tells the drivers the number of v-blanks to synchronize with
virtual uint32_t GetSyncInterval() const = 0;
//! Returns the refresh rate of the main display
virtual uint32_t GetDisplayRefreshRate() const = 0;
}; };
using WindowRequestBus = AZ::EBus<WindowRequests>; using WindowRequestBus = AZ::EBus<WindowRequests>;
@ -101,6 +107,9 @@ namespace AzFramework
//! This is called when vsync interval is changed. //! This is called when vsync interval is changed.
virtual void OnVsyncIntervalChanged(uint32_t interval) { AZ_UNUSED(interval); }; virtual void OnVsyncIntervalChanged(uint32_t interval) { AZ_UNUSED(interval); };
//! This is called if the main display's refresh rate changes
virtual void OnRefreshRateChanged([[maybe_unused]] uint32_t refreshRate) {}
}; };
using WindowNotificationBus = AZ::EBus<WindowNotifications>; using WindowNotificationBus = AZ::EBus<WindowNotifications>;

@ -25,7 +25,7 @@ namespace AzFramework
const WindowGeometry& geometry, const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override; const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override; NativeWindowHandle GetWindowHandle() const override;
uint32_t GetDisplayRefreshRate() const override;
private: private:
ANativeWindow* m_nativeWindow = nullptr; ANativeWindow* m_nativeWindow = nullptr;
}; };
@ -55,4 +55,9 @@ namespace AzFramework
return reinterpret_cast<NativeWindowHandle>(m_nativeWindow); return reinterpret_cast<NativeWindowHandle>(m_nativeWindow);
} }
uint32_t NativeWindowImpl_Android::GetDisplayRefreshRate() const
{
// Using 60 for now until proper support is added
return 60;
}
} // namespace AzFramework } // namespace AzFramework

@ -23,6 +23,7 @@ namespace AzFramework
const WindowGeometry& geometry, const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override; const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override; NativeWindowHandle GetWindowHandle() const override;
uint32_t GetDisplayRefreshRate() const override;
}; };
NativeWindow::Implementation* NativeWindow::Implementation::Create() NativeWindow::Implementation* NativeWindow::Implementation::Create()
@ -44,4 +45,9 @@ namespace AzFramework
return nullptr; return nullptr;
} }
uint32_t NativeWindowImpl_Linux::GetDisplayRefreshRate() const
{
//Using 60 for now until proper support is added
return 60;
}
} // namespace AzFramework } // namespace AzFramework

@ -34,12 +34,14 @@ namespace AzFramework
bool GetFullScreenState() const override; bool GetFullScreenState() const override;
void SetFullScreenState(bool fullScreenState) override; void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; } bool CanToggleFullScreenState() const override { return true; }
uint32_t GetMainDisplayRefreshRate() const override;
private: private:
static NSWindowStyleMask ConvertToNSWindowStyleMask(const WindowStyleMasks& styleMasks); static NSWindowStyleMask ConvertToNSWindowStyleMask(const WindowStyleMasks& styleMasks);
NSWindow* m_nativeWindow; NSWindow* m_nativeWindow;
NSString* m_windowTitle; NSString* m_windowTitle;
uint32_t m_mainDisplayRefreshRate = 0;
}; };
NativeWindow::Implementation* NativeWindow::Implementation::Create() NativeWindow::Implementation* NativeWindow::Implementation::Create()
@ -76,6 +78,17 @@ namespace AzFramework
// Make the window active // Make the window active
[m_nativeWindow makeKeyAndOrderFront:nil]; [m_nativeWindow makeKeyAndOrderFront:nil];
m_nativeWindow.title = m_windowTitle; m_nativeWindow.title = m_windowTitle;
CGDirectDisplayID display = CGMainDisplayID();
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display);
m_mainDisplayRefreshRate = CGDisplayModeGetRefreshRate(currentMode);
// Assume 60hz if 0 is returned.
// This can happen on OSX. In future we can hopefully use maximumFramesPerSecond which wont have this issue
if (m_mainDisplayRefreshRate == 0)
{
m_mainDisplayRefreshRate = 60;
}
} }
NativeWindowHandle NativeWindowImpl_Darwin::GetWindowHandle() const NativeWindowHandle NativeWindowImpl_Darwin::GetWindowHandle() const
@ -128,4 +141,9 @@ namespace AzFramework
const NSWindowStyleMask defaultMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; const NSWindowStyleMask defaultMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
return nativeMask ? nativeMask : defaultMask; return nativeMask ? nativeMask : defaultMask;
} }
uint32_t NativeWindowImpl_Darwin::GetMainDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
} // namespace AzFramework } // namespace AzFramework

@ -37,6 +37,7 @@ namespace AzFramework
void SetFullScreenState(bool fullScreenState) override; void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; } bool CanToggleFullScreenState() const override { return true; }
float GetDpiScaleFactor() const override; float GetDpiScaleFactor() const override;
uint32_t GetDisplayRefreshRate() const override;
private: private:
static DWORD ConvertToWin32WindowStyleMask(const WindowStyleMasks& styleMasks); static DWORD ConvertToWin32WindowStyleMask(const WindowStyleMasks& styleMasks);
@ -56,6 +57,7 @@ namespace AzFramework
using GetDpiForWindowType = UINT(HWND hwnd); using GetDpiForWindowType = UINT(HWND hwnd);
GetDpiForWindowType* m_getDpiFunction = nullptr; GetDpiForWindowType* m_getDpiFunction = nullptr;
uint32_t m_mainDisplayRefreshRate = 0;
}; };
const wchar_t* NativeWindowImpl_Win32::s_defaultClassName = L"O3DEWin32Class"; const wchar_t* NativeWindowImpl_Win32::s_defaultClassName = L"O3DEWin32Class";
@ -144,6 +146,10 @@ namespace AzFramework
{ {
SetWindowLongPtr(m_win32Handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); SetWindowLongPtr(m_win32Handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
} }
DEVMODE DisplayConfig;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
m_mainDisplayRefreshRate = DisplayConfig.dmDisplayFrequency;
} }
void NativeWindowImpl_Win32::Activate() void NativeWindowImpl_Win32::Activate()
@ -263,6 +269,15 @@ namespace AzFramework
WindowNotificationBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnDpiScaleFactorChanged, newScaleFactor); WindowNotificationBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnDpiScaleFactorChanged, newScaleFactor);
break; break;
} }
case WM_WINDOWPOSCHANGED:
{
DEVMODE DisplayConfig;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
uint32_t refreshRate = DisplayConfig.dmDisplayFrequency;
WindowNotificationBus::Event(
nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnRefreshRateChanged, refreshRate);
break;
}
default: default:
return DefWindowProc(hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
break; break;
@ -367,6 +382,11 @@ namespace AzFramework
return aznumeric_cast<float>(dotsPerInch) / aznumeric_cast<float>(defaultDotsPerInch); return aznumeric_cast<float>(dotsPerInch) / aznumeric_cast<float>(defaultDotsPerInch);
} }
uint32_t NativeWindowImpl_Win32::GetDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
void NativeWindowImpl_Win32::EnterBorderlessWindowFullScreen() void NativeWindowImpl_Win32::EnterBorderlessWindowFullScreen()
{ {
if (m_isInBorderlessWindowFullScreenState) if (m_isInBorderlessWindowFullScreenState)

@ -27,9 +27,11 @@ namespace AzFramework
const WindowGeometry& geometry, const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override; const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override; NativeWindowHandle GetWindowHandle() const override;
uint32_t GetMainDisplayRefreshRate() const override;
private: private:
UIWindow* m_nativeWindow; UIWindow* m_nativeWindow;
uint32_t m_mainDisplayRefreshRate = 0;
}; };
NativeWindow::Implementation* NativeWindow::Implementation::Create() NativeWindow::Implementation* NativeWindow::Implementation::Create()
@ -56,6 +58,7 @@ namespace AzFramework
m_width = geometry.m_width; m_width = geometry.m_width;
m_height = geometry.m_height; m_height = geometry.m_height;
m_mainDisplayRefreshRate = [[UIScreen mainScreen] maximumFramesPerSecond];
} }
NativeWindowHandle NativeWindowImpl_Ios::GetWindowHandle() const NativeWindowHandle NativeWindowImpl_Ios::GetWindowHandle() const
@ -63,5 +66,9 @@ namespace AzFramework
return m_nativeWindow; return m_nativeWindow;
} }
uint32_t NativeWindowImpl_Ios::GetMainDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
} // namespace AzFramework } // namespace AzFramework

@ -125,7 +125,6 @@ namespace AZ
Format GetNearestSupportedFormat(Format requestedFormat, FormatCapabilities requestedCapabilities) const; Format GetNearestSupportedFormat(Format requestedFormat, FormatCapabilities requestedCapabilities) const;
//! Small API to support getting supported/working swapchain formats for a window. //! Small API to support getting supported/working swapchain formats for a window.
//! [GFX TODO]ATOM-1125] [RHI] Device::GetValidSwapChainImageFormats()
//! Returns the set of supported formats for swapchain images. //! Returns the set of supported formats for swapchain images.
virtual AZStd::vector<Format> GetValidSwapChainImageFormats(const WindowHandle& windowHandle) const; virtual AZStd::vector<Format> GetValidSwapChainImageFormats(const WindowHandle& windowHandle) const;

@ -85,7 +85,7 @@ namespace Aftermath
#if defined(USE_NSIGHT_AFTERMATH) #if defined(USE_NSIGHT_AFTERMATH)
AZStd::vector<GFSDK_Aftermath_ContextHandle> cntxtHandles = static_cast<GpuCrashTracker*>(crashTracker)->GetContextHandles(); AZStd::vector<GFSDK_Aftermath_ContextHandle> cntxtHandles = static_cast<GpuCrashTracker*>(crashTracker)->GetContextHandles();
GFSDK_Aftermath_ContextData* outContextData = new GFSDK_Aftermath_ContextData[cntxtHandles.size()]; GFSDK_Aftermath_ContextData* outContextData = new GFSDK_Aftermath_ContextData[cntxtHandles.size()];
GFSDK_Aftermath_Result result = GFSDK_Aftermath_GetData(cntxtHandles.size(), cntxtHandles.data(), outContextData); GFSDK_Aftermath_Result result = GFSDK_Aftermath_GetData(static_cast<uint32_t>(cntxtHandles.size()), cntxtHandles.data(), outContextData);
AssertOnError(result); AssertOnError(result);
for (int i = 0; i < cntxtHandles.size(); i++) for (int i = 0; i < cntxtHandles.size(); i++)
{ {

@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once
namespace AZ namespace AZ
{ {
namespace Metal namespace Metal

@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once
namespace AZ namespace AZ
{ {
namespace Metal namespace Metal

@ -77,7 +77,6 @@ namespace AZ
m_samplerCache = [[NSCache alloc]init]; m_samplerCache = [[NSCache alloc]init];
[m_samplerCache setName:@"SamplerCache"]; [m_samplerCache setName:@"SamplerCache"];
return RHI::ResultCode::Success; return RHI::ResultCode::Success;
} }

@ -74,21 +74,16 @@ namespace AZ
AddSubView(); AddSubView();
} }
m_refreshRate = Platform::GetRefreshRate();
//Assume 60hz if 0 is returned.
//Internal OSX displays have 'flexible' refresh rates, with a max of 60Hz - but report 0hz
if (m_refreshRate < 0.1f)
{
m_refreshRate = 60.0f;
}
m_drawables.resize(descriptor.m_dimensions.m_imageCount); m_drawables.resize(descriptor.m_dimensions.m_imageCount);
if (nativeDimensions) if (nativeDimensions)
{ {
*nativeDimensions = descriptor.m_dimensions; *nativeDimensions = descriptor.m_dimensions;
} }
AzFramework::WindowRequestBus::EventResult(
m_refreshRate, m_nativeWindow, &AzFramework::WindowRequestBus::Events::GetDisplayRefreshRate);
return RHI::ResultCode::Success; return RHI::ResultCode::Success;
} }
@ -160,7 +155,10 @@ namespace AZ
const uint32_t currentImageIndex = GetCurrentImageIndex(); const uint32_t currentImageIndex = GetCurrentImageIndex();
//Preset the drawable //Preset the drawable
Platform::PresentInternal(m_mtlCommandBuffer, m_drawables[currentImageIndex], GetDescriptor().m_verticalSyncInterval, m_refreshRate); Platform::PresentInternal(
m_mtlCommandBuffer,
m_drawables[currentImageIndex], GetDescriptor().m_verticalSyncInterval,
m_refreshRate);
[m_drawables[currentImageIndex] release]; [m_drawables[currentImageIndex] release];
m_drawables[currentImageIndex] = nil; m_drawables[currentImageIndex] = nil;

@ -53,7 +53,7 @@ namespace AZ
id<MTLDevice> m_mtlDevice = nil; id<MTLDevice> m_mtlDevice = nil;
NativeWindowType* m_nativeWindow = nullptr; NativeWindowType* m_nativeWindow = nullptr;
AZStd::vector<id<CAMetalDrawable>> m_drawables; AZStd::vector<id<CAMetalDrawable>> m_drawables;
float m_refreshRate = 0.0f; uint32_t m_refreshRate = 0;
}; };
} }
} }

@ -17,19 +17,6 @@
#include <AzCore/Console/IConsole.h> #include <AzCore/Console/IConsole.h>
#include <AzCore/Math/MathUtils.h> #include <AzCore/Math/MathUtils.h>
void OnVsyncIntervalChanged(uint32_t const& interval)
{
AzFramework::WindowNotificationBus::Broadcast(
&AzFramework::WindowNotificationBus::Events::OnVsyncIntervalChanged,
AZ::GetClamp(interval, 0u, 4u));
}
// NOTE: On change, broadcasts the new requested vsync interval to all windows.
// The value of the vsync interval is constrained between 0 and 4
// Vsync intervals greater than 1 are not currently supported on the Vulkan RHI (see #2061 for discussion)
AZ_CVAR(uint32_t, rpi_vsync_interval, 1, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval");
namespace AZ namespace AZ
{ {
namespace RPI namespace RPI
@ -158,9 +145,13 @@ namespace AZ
const RHI::WindowHandle windowHandle = RHI::WindowHandle(reinterpret_cast<uintptr_t>(m_windowHandle)); const RHI::WindowHandle windowHandle = RHI::WindowHandle(reinterpret_cast<uintptr_t>(m_windowHandle));
uint32_t syncInterval = 1;
AzFramework::WindowRequestBus::EventResult(
syncInterval, m_windowHandle, &AzFramework::WindowRequestBus::Events::GetSyncInterval);
RHI::SwapChainDescriptor descriptor; RHI::SwapChainDescriptor descriptor;
descriptor.m_window = windowHandle; descriptor.m_window = windowHandle;
descriptor.m_verticalSyncInterval = rpi_vsync_interval; descriptor.m_verticalSyncInterval = syncInterval;
descriptor.m_dimensions.m_imageWidth = width; descriptor.m_dimensions.m_imageWidth = width;
descriptor.m_dimensions.m_imageHeight = height; descriptor.m_dimensions.m_imageHeight = height;
descriptor.m_dimensions.m_imageCount = 3; descriptor.m_dimensions.m_imageCount = 3;

@ -121,6 +121,8 @@ namespace AtomToolsFramework
bool CanToggleFullScreenState() const override; bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override; void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override; float GetDpiScaleFactor() const override;
uint32_t GetSyncInterval() const override;
uint32_t GetDisplayRefreshRate() const;
protected: protected:
// AzFramework::InputChannelEventListener ... // AzFramework::InputChannelEventListener ...

@ -465,4 +465,14 @@ namespace AtomToolsFramework
{ {
return aznumeric_cast<float>(devicePixelRatioF()); return aznumeric_cast<float>(devicePixelRatioF());
} }
uint32_t RenderViewportWidget::GetDisplayRefreshRate() const
{
return 60;
}
uint32_t RenderViewportWidget::GetSyncInterval() const
{
return 1;
}
} //namespace AtomToolsFramework } //namespace AtomToolsFramework

Loading…
Cancel
Save