diff --git a/src/plugins/simulator/xplane/xswiftbusserviceproxy.cpp b/src/plugins/simulator/xplane/xswiftbusserviceproxy.cpp index 94e4876b6..e319267c1 100644 --- a/src/plugins/simulator/xplane/xswiftbusserviceproxy.cpp +++ b/src/plugins/simulator/xplane/xswiftbusserviceproxy.cpp @@ -319,6 +319,15 @@ namespace BlackSimPlugin m_dbusInterface->callDBusAsync(QLatin1String("isUsingRealTime"), setterCallback(o_isRealTime)); } + double CXSwiftBusServiceProxy::getAverageFPS() const + { + return m_dbusInterface->callDBusRet(QLatin1String("getAverageFPS")); + } + void CXSwiftBusServiceProxy::getAverageFPSAsync(double *o_frameRate) + { + m_dbusInterface->callDBusAsync(QLatin1String("getAverageFPS"), setterCallback(o_frameRate)); + } + double CXSwiftBusServiceProxy::getLatitudeDeg() const { return m_dbusInterface->callDBusRet(QLatin1String("getLatitudeDeg")); diff --git a/src/plugins/simulator/xplane/xswiftbusserviceproxy.h b/src/plugins/simulator/xplane/xswiftbusserviceproxy.h index 6963ee664..718cf13eb 100644 --- a/src/plugins/simulator/xplane/xswiftbusserviceproxy.h +++ b/src/plugins/simulator/xplane/xswiftbusserviceproxy.h @@ -208,6 +208,12 @@ namespace BlackSimPlugin void isUsingRealTimeAsync(bool *o_isRealTime); //! @} + //! \copydoc XSwiftBus::CService::getAverageFPS + //! @{ + double getAverageFPS() const; + void getAverageFPSAsync(double *o_frameRate); + //! @} + //! \copydoc XSwiftBus::CService::getLatitudeDeg //! @{ double getLatitudeDeg() const; diff --git a/src/xswiftbus/datarefs.h b/src/xswiftbus/datarefs.h index 9bfd80a3e..16c226b16 100644 --- a/src/xswiftbus/datarefs.h +++ b/src/xswiftbus/datarefs.h @@ -36,6 +36,8 @@ namespace XSwiftBus } } + bool isValid() const { return m_ref; } + template void implSet(T); @@ -60,6 +62,8 @@ namespace XSwiftBus } } + bool isValid() const { return m_ref; } + template void implSetAll(std::vector const &); @@ -108,6 +112,8 @@ namespace XSwiftBus //! Get the value of the dataref DataRefType get() const { return DataRefImpl::implGet(); } + + using DataRefImpl::isValid; }; /*! @@ -141,6 +147,8 @@ namespace XSwiftBus //! Get the value of a single element DataRefType getAt(int index) const { return ArrayDataRefImpl::implGetAt(index); } + + using ArrayDataRefImpl::isValid; }; /*! @@ -165,6 +173,9 @@ namespace XSwiftBus } } + //! True if the dataref exists + bool isValid() const { return m_ref; } + //! Set the value of the whole string (if it is writable) void set(std::string const &s) { setSubstr(0, s); } diff --git a/src/xswiftbus/service.cpp b/src/xswiftbus/service.cpp index d115791f3..d2c6e3f6b 100644 --- a/src/xswiftbus/service.cpp +++ b/src/xswiftbus/service.cpp @@ -23,12 +23,54 @@ using namespace BlackMisc::Simulation::XPlane::QtFreeUtils; namespace XSwiftBus { - CService::CService(CSettingsProvider *settingsProvider) : CDBusObject(settingsProvider) + //! \private + struct CService::FramePeriodSampler : public CDrawable + { + DataRef m_thisFramePeriod; + DataRef m_thisFramePeriodXP11; + std::vector m_samples; + float m_total = 0; + size_t m_lastSampleIndex = 0; + static constexpr size_t c_maxSampleCount = 500; + + FramePeriodSampler() : CDrawable(xplm_Phase_LastCockpit, false) {} + + float getAverageFPS() + { + if (m_total == 0) { return 0; } + const float fps = m_samples.size() / m_total; + m_total = 0; + m_samples.clear(); + m_lastSampleIndex = 0; + return fps; + } + + protected: + virtual void draw() override // called once per frame + { + float current = m_thisFramePeriodXP11.isValid() ? m_thisFramePeriodXP11.get() : m_thisFramePeriod.get(); + ++m_lastSampleIndex %= c_maxSampleCount; + if (m_samples.size() == c_maxSampleCount) + { + m_total -= m_samples[m_lastSampleIndex]; + m_samples[m_lastSampleIndex] = current; + } + else { m_samples.push_back(current); } + m_total += m_samples[m_lastSampleIndex]; + } + }; + + CService::CService(CSettingsProvider *settingsProvider) : + CDBusObject(settingsProvider), + m_framePeriodSampler(std::make_unique()) { this->updateAirportsInRange(); this->updateMessageBoxFromSettings(); + m_framePeriodSampler->show(); } + CService::~CService() = default; + void CService::onAircraftModelChanged() { char filename[256]; @@ -63,6 +105,12 @@ namespace XSwiftBus return XSWIFTBUS_COMMIT; } + double CService::getAverageFPS() + { + if (!m_framePeriodSampler) { return 0; } + return static_cast(m_framePeriodSampler->getAverageFPS()); + } + void CService::addTextMessage(const std::string &text, double red, double green, double blue) { if (text.empty()) { return; } diff --git a/src/xswiftbus/service.h b/src/xswiftbus/service.h index e247dd6be..03e21a1a2 100644 --- a/src/xswiftbus/service.h +++ b/src/xswiftbus/service.h @@ -40,7 +40,7 @@ namespace XSwiftBus CService(CSettingsProvider *settingsProvider); //! Destructor - virtual ~CService() override = default; + virtual ~CService() override; //! DBus interface name static const std::string &InterfaceName() @@ -110,6 +110,11 @@ namespace XSwiftBus //! True if sim time is tracking operating system time bool isUsingRealTime() const { return m_useSystemTime.get(); } + //! Frames-per-second, averaged over the last 500 frames, + //! or since this function was last called, whichever is later. + //! \return Zero if no samples were collected since this function was last called. + double getAverageFPS(); + //! Get aircraft latitude in degrees double getLatitudeDeg() const { return m_latitude.get(); } @@ -309,6 +314,9 @@ namespace XSwiftBus //! Redraw message box after reading from the settings void updateMessageBoxFromSettings(); + struct FramePeriodSampler; + std::unique_ptr m_framePeriodSampler; + StringDataRef m_liveryPath; StringDataRef m_icao; StringDataRef m_descrip;