From 7ef383580e486a93df633482e7ec6275c7fb7e9e Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Thu, 15 Jul 2021 11:50:19 -0700 Subject: [PATCH] Metal sync interval support (#2187) * Metal sync interval support Add shader name to SRGPool for debugging purposes Set default value of rpi_vsync_interval to 1 Signed-off-by: moudgils --- .../Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp | 33 ++++++++++++++++--- .../Source/Platform/iOS/RHI/Metal_RHI_iOS.cpp | 16 ++++++--- .../RHI/Metal/Code/Source/RHI/SwapChain.cpp | 17 +++++++--- .../RHI/Metal/Code/Source/RHI/SwapChain.h | 1 + .../Shader/ShaderResourceGroupPool.cpp | 4 +-- .../Code/Source/RPI.Public/WindowContext.cpp | 2 +- 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp b/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp index de3bc23a11..cb9e72118a 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp @@ -43,11 +43,36 @@ namespace Platform } return physicalDeviceList; } - - void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval) + + float GetRefreshRate() { - AZ_UNUSED(syncInterval); - [mtlCommandBuffer presentDrawable:drawable]; + CGDirectDisplayID display = CGMainDisplayID(); + CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display); + return CGDisplayModeGetRefreshRate(currentMode); + } + + void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval, float refreshRate) + { + bool framePresented = false; + + //seconds per frame (1/refreshrate) * num frames (sync interval) + float presentAfterMinimumDuration = syncInterval / refreshRate; + +#if defined(__MAC_10_15_4) + if(@available(macOS 10.15.4, *)) + { + if(presentAfterMinimumDuration > 0.0f) + { + [mtlCommandBuffer presentDrawable:drawable afterMinimumDuration:presentAfterMinimumDuration]; + framePresented = true; + } + } +#endif + + if(!framePresented) + { + [mtlCommandBuffer presentDrawable:drawable]; + } } CGRect GetScreenBounds(NativeWindowType* nativeWindow) diff --git a/Gems/Atom/RHI/Metal/Code/Source/Platform/iOS/RHI/Metal_RHI_iOS.cpp b/Gems/Atom/RHI/Metal/Code/Source/Platform/iOS/RHI/Metal_RHI_iOS.cpp index b7c309fba2..007655a93e 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/Platform/iOS/RHI/Metal_RHI_iOS.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/Platform/iOS/RHI/Metal_RHI_iOS.cpp @@ -29,13 +29,19 @@ namespace Platform return physicalDeviceList; } - void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval) + float GetRefreshRate() { - bool hasPresentAfterMinimumDuration = [drawable respondsToSelector:@selector(presentAfterMinimumDuration:)]; - - if (hasPresentAfterMinimumDuration && syncInterval > 0.0f) + NativeScreenType* nativeScreen = [NativeScreenType mainScreen]; + return [nativeScreen maximumFramesPerSecond]; + } + + void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval, float refreshRate) + { + //seconds per frame (1/refreshrate) * num frames (sync interval) + float presentAfterMinimumDuration = syncInterval / refreshRate; + if (hasPresentAfterMinimumDuration > 0.0f) { - [mtlCommandBuffer presentDrawable:drawable afterMinimumDuration:syncInterval]; + [mtlCommandBuffer presentDrawable:drawable afterMinimumDuration:presentAfterMinimumDuration]; } else { diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp index 31d23e5100..08d5d2be87 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp @@ -19,8 +19,9 @@ namespace Platform CGFloat GetScreenScale(); void AttachViewController(NativeWindowType* nativeWindow, NativeViewControllerType* viewController, RHIMetalView* metalView); void UnAttachViewController(NativeWindowType* nativeWindow, NativeViewControllerType* viewController); - void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval); + void PresentInternal(id mtlCommandBuffer, id drawable, float syncInterval, float refreshRate); void ResizeInternal(RHIMetalView* metalView, CGSize viewSize); + float GetRefreshRate(); RHIMetalView* GetMetalView(NativeWindowType* nativeWindow); } @@ -73,6 +74,15 @@ namespace AZ 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); if (nativeDimensions) @@ -148,10 +158,9 @@ namespace AZ uint32_t SwapChain::PresentInternal() { const uint32_t currentImageIndex = GetCurrentImageIndex(); - //GFX TODO][ATOM-432] - Hardcoding to 30fps for now. Only used by ios. This needs to be driven by higher level code. - float syncInterval = 1.0f/30.0f; + //Preset the drawable - Platform::PresentInternal(m_mtlCommandBuffer, m_drawables[currentImageIndex], syncInterval); + Platform::PresentInternal(m_mtlCommandBuffer, m_drawables[currentImageIndex], GetDescriptor().m_verticalSyncInterval, m_refreshRate); [m_drawables[currentImageIndex] release]; m_drawables[currentImageIndex] = nil; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h index c86bd1f7a5..72014005ac 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h @@ -52,6 +52,7 @@ namespace AZ id m_mtlDevice = nil; NativeWindowType* m_nativeWindow = nullptr; AZStd::vector> m_drawables; + float m_refreshRate = 0.0f; }; } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroupPool.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroupPool.cpp index d8c69cf8a0..4e858e4880 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroupPool.cpp @@ -58,8 +58,8 @@ namespace AZ RHI::ShaderResourceGroupPoolDescriptor poolDescriptor; poolDescriptor.m_layout = shaderAsset.FindShaderResourceGroupLayout(srgName, supervariantIndex).get(); - - m_pool->SetName(srgName); + m_pool->SetName(AZ::Name(AZStd::string::format("%s_%s",shaderAsset.GetName().GetCStr(),srgName.GetCStr()))); + const RHI::ResultCode resultCode = m_pool->Init(*device, poolDescriptor); return resultCode; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/WindowContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/WindowContext.cpp index 16ad7a1155..4b8c061b68 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/WindowContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/WindowContext.cpp @@ -27,7 +27,7 @@ void OnVsyncIntervalChanged(uint32_t const& interval) // 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, 0, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval"); +AZ_CVAR(uint32_t, rpi_vsync_interval, 1, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval"); namespace AZ {