diff --git a/Engine/gapi/abstractgraphicsapi.h b/Engine/gapi/abstractgraphicsapi.h index 7938dfe0..cf4ba7c7 100644 --- a/Engine/gapi/abstractgraphicsapi.h +++ b/Engine/gapi/abstractgraphicsapi.h @@ -522,6 +522,7 @@ namespace Tempest { struct Swapchain:NoCopy { virtual ~Swapchain()=default; virtual void reset()=0; + virtual void setPreferredFrameRateRange(uint32_t, uint32_t, uint32_t) {} virtual uint32_t currentBackBufferIndex()=0; virtual NonUniqResId syncId() const; virtual uint32_t imageCount() const=0; diff --git a/Engine/gapi/metal/mtswapchain.h b/Engine/gapi/metal/mtswapchain.h index 0f250bd1..b4fcfef3 100644 --- a/Engine/gapi/metal/mtswapchain.h +++ b/Engine/gapi/metal/mtswapchain.h @@ -22,6 +22,9 @@ class MtSwapchain : public AbstractGraphicsApi::Swapchain { ~MtSwapchain(); void reset() override; +#ifdef __IOS__ + void setPreferredFrameRateRange(uint32_t minimum, uint32_t maximum, uint32_t preferred) override; +#endif uint32_t currentBackBufferIndex() override; uint32_t imageCount() const override; uint32_t w() const override; diff --git a/Engine/gapi/metal/mtswapchain.mm b/Engine/gapi/metal/mtswapchain.mm index e0eaf26c..3d82e04b 100644 --- a/Engine/gapi/metal/mtswapchain.mm +++ b/Engine/gapi/metal/mtswapchain.mm @@ -156,6 +156,12 @@ static CGRect windowRect(UIWindow* wnd) { return currentImg; } +#ifdef __IOS__ +void MtSwapchain::setPreferredFrameRateRange(uint32_t minimum, uint32_t maximum, uint32_t preferred) { + SystemApi::setPreferredFrameRateRange(reinterpret_cast(pimpl->wnd),minimum,maximum,preferred); + } +#endif + void MtSwapchain::present() { auto pool = NsPtr::init(); diff --git a/Engine/graphics/swapchain.cpp b/Engine/graphics/swapchain.cpp index 564c7996..e0fcf8cd 100644 --- a/Engine/graphics/swapchain.cpp +++ b/Engine/graphics/swapchain.cpp @@ -44,6 +44,14 @@ void Swapchain::reset() { implReset(); } +void Swapchain::setPreferredFrameRate(uint32_t fps) { + setPreferredFrameRateRange(fps,fps,fps); + } + +void Swapchain::setPreferredFrameRateRange(uint32_t minimum, uint32_t maximum, uint32_t preferred) { + impl.handler->setPreferredFrameRateRange(minimum,maximum,preferred); + } + uint32_t Swapchain::imageCount() const { return impl.handler->imageCount(); } diff --git a/Engine/graphics/swapchain.h b/Engine/graphics/swapchain.h index f10513a8..5e74aa96 100644 --- a/Engine/graphics/swapchain.h +++ b/Engine/graphics/swapchain.h @@ -21,6 +21,15 @@ class Swapchain final { void reset(); + // Requests a display callback rate, not a guaranteed rendering rate. + // Zero restores the system default. Ignored on unsupported platforms. + void setPreferredFrameRate(uint32_t fps); + + // Rates are limited to the screen's maximum; minimum and preferred are + // clamped to the resulting range. Zero minimum means 1, zero preferred + // leaves the choice to the system, and zero maximum restores the default. + void setPreferredFrameRateRange(uint32_t minimum, uint32_t maximum, uint32_t preferred = 0); + uint32_t currentImage() const; uint32_t imageCount() const; Attachment& operator[](size_t id); diff --git a/Engine/system/api/iosapi.h b/Engine/system/api/iosapi.h index c9f837dc..d05e99d0 100644 --- a/Engine/system/api/iosapi.h +++ b/Engine/system/api/iosapi.h @@ -19,6 +19,7 @@ class iOSApi final: SystemApi { Rect implWindowClientRect(SystemApi::Window *w) override; bool implSetAsFullscreen(SystemApi::Window *w, bool fullScreen) override; bool implIsFullscreen(SystemApi::Window *w) override; + void implSetPreferredFrameRateRange(SystemApi::Window *w, uint32_t minimum, uint32_t maximum, uint32_t preferred) override; void implSetCursorPosition(SystemApi::Window *w, int x, int y) override; void implShowCursor(SystemApi::Window *w, CursorShape cursor) override; diff --git a/Engine/system/api/iosapi.mm b/Engine/system/api/iosapi.mm index 0f78f751..37598af4 100644 --- a/Engine/system/api/iosapi.mm +++ b/Engine/system/api/iosapi.mm @@ -6,6 +6,7 @@ #ifdef __IOS__ #import +#include #include #include #include @@ -617,4 +618,18 @@ static void appleMain(void*) { } +void iOSApi::implSetPreferredFrameRateRange(Window* w, uint32_t minimum, uint32_t maximum, uint32_t preferred) { + auto wx = reinterpret_cast(w); + if(maximum==0) { + wx->displayLink.preferredFrameRateRange = CAFrameRateRangeDefault; + return; + } + + maximum = std::min(maximum,uint32_t(wx.screen.maximumFramesPerSecond)); + minimum = std::clamp(minimum,1u,maximum); + if(preferred!=0) + preferred = std::clamp(preferred,minimum,maximum); + wx->displayLink.preferredFrameRateRange = CAFrameRateRangeMake(minimum,maximum,preferred); + } + #endif diff --git a/Engine/system/systemapi.cpp b/Engine/system/systemapi.cpp index 04e3d1dd..96d3b579 100644 --- a/Engine/system/systemapi.cpp +++ b/Engine/system/systemapi.cpp @@ -24,6 +24,13 @@ SystemApi::Data SystemApi::m; SystemApi::SystemApi() { } +void SystemApi::implSetPreferredFrameRateRange(Window*, uint32_t, uint32_t, uint32_t) { + } + +void SystemApi::setPreferredFrameRateRange(Window *w, uint32_t minimum, uint32_t maximum, uint32_t preferred) { + return inst().implSetPreferredFrameRateRange(w,minimum,maximum,preferred); + } + float SystemApi::implUiScale(Window* w) { // default to 1.0, on platforms without hidpi implementation return 1; diff --git a/Engine/system/systemapi.h b/Engine/system/systemapi.h index 31482d0f..bc175b4c 100644 --- a/Engine/system/systemapi.h +++ b/Engine/system/systemapi.h @@ -45,6 +45,8 @@ class SystemApi { static void destroyWindow(Window* w); static void exit(); + static void setPreferredFrameRateRange(SystemApi::Window *w, uint32_t minimum, uint32_t maximum, uint32_t preferred); + static Rect windowClientRect(SystemApi::Window *w); static bool setAsFullscreen(SystemApi::Window *w, bool fullScreen); @@ -80,6 +82,7 @@ class SystemApi { virtual void implShowCursor(SystemApi::Window *w, CursorShape show) = 0; virtual float implUiScale(SystemApi::Window* w); + virtual void implSetPreferredFrameRateRange(SystemApi::Window *w, uint32_t minimum, uint32_t maximum, uint32_t preferred); virtual bool implIsRunning() = 0; virtual int implExec(AppCallBack& cb) = 0;