mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-21 04:45:31 +08:00
[xplane] Added display of simulation time ratio in simulator component
This commit is contained in:
@@ -260,6 +260,7 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
this->clearAllRemoteAircraftData(); // reset
|
this->clearAllRemoteAircraftData(); // reset
|
||||||
m_averageFps = -1.0;
|
m_averageFps = -1.0;
|
||||||
|
m_simTimeRatio = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ISimulator::isUpdateAllRemoteAircraft(qint64 currentTimestamp) const
|
bool ISimulator::isUpdateAllRemoteAircraft(qint64 currentTimestamp) const
|
||||||
@@ -1034,6 +1035,7 @@ namespace BlackCore
|
|||||||
bool ISimulator::disconnectFrom()
|
bool ISimulator::disconnectFrom()
|
||||||
{
|
{
|
||||||
m_averageFps = -1.0;
|
m_averageFps = -1.0;
|
||||||
|
m_simTimeRatio = 1.0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,9 @@ namespace BlackCore
|
|||||||
//! Average FPS (frames per second)
|
//! Average FPS (frames per second)
|
||||||
double getAverageFPS() const { return m_averageFps; }
|
double getAverageFPS() const { return m_averageFps; }
|
||||||
|
|
||||||
|
//! Ratio of simulation time to real time, due to low FPS
|
||||||
|
double getSimTimeRatio() const { return m_simTimeRatio; }
|
||||||
|
|
||||||
//! Send situation/parts for testing
|
//! Send situation/parts for testing
|
||||||
virtual bool testSendSituationAndParts(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CAircraftParts &parts) = 0;
|
virtual bool testSendSituationAndParts(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CAircraftParts &parts) = 0;
|
||||||
|
|
||||||
@@ -579,6 +582,7 @@ namespace BlackCore
|
|||||||
int m_statsUpdateAircraftLimited = 0; //!< skipped because of max.update limitations
|
int m_statsUpdateAircraftLimited = 0; //!< skipped because of max.update limitations
|
||||||
double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time
|
double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time
|
||||||
double m_averageFps = -1.0; //!< FPS
|
double m_averageFps = -1.0; //!< FPS
|
||||||
|
double m_simTimeRatio = 1.0; //!< ratio of simulation time to real time, due to low FPS (X-Plane)
|
||||||
qint64 m_updateAllRemoteAircraftUntil = 0; //!< force an update of all remote aircraft, used when own aircraft is moved, paused to make sure all remote aircraft are updated
|
qint64 m_updateAllRemoteAircraftUntil = 0; //!< force an update of all remote aircraft, used when own aircraft is moved, paused to make sure all remote aircraft are updated
|
||||||
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time
|
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time
|
||||||
qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time
|
qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ namespace BlackGui
|
|||||||
{
|
{
|
||||||
const double fps = sGui->getISimulator()->getAverageFPS();
|
const double fps = sGui->getISimulator()->getAverageFPS();
|
||||||
this->addOrUpdateLiveDataByName(QStringLiteral("FPS"), fps < 0 ? QStringLiteral("N/A") : QString::number(fps, 'g', 1), CIconList::allIcons().findByIndex(CIcons::ApplicationSimulator));
|
this->addOrUpdateLiveDataByName(QStringLiteral("FPS"), fps < 0 ? QStringLiteral("N/A") : QString::number(fps, 'g', 1), CIconList::allIcons().findByIndex(CIcons::ApplicationSimulator));
|
||||||
|
|
||||||
|
const double ratio = sGui->getISimulator()->getSimTimeRatio();
|
||||||
|
this->addOrUpdateLiveDataByName(QStringLiteral("Time Ratio"), QString::number(ratio), CIconList::allIcons().findByIndex(CIcons::ApplicationSimulator));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,12 +93,13 @@ namespace BlackMisc
|
|||||||
//! Call DBus with asynchronous return value
|
//! Call DBus with asynchronous return value
|
||||||
//! Callback can be any callable object taking a single argument of type QDBusPendingCallWatcher*.
|
//! Callback can be any callable object taking a single argument of type QDBusPendingCallWatcher*.
|
||||||
template <typename Func, typename... Args>
|
template <typename Func, typename... Args>
|
||||||
void callDBusAsync(QLatin1String method, Func callback, Args &&... args)
|
QDBusPendingCallWatcher *callDBusAsync(QLatin1String method, Func callback, Args &&... args)
|
||||||
{
|
{
|
||||||
QList<QVariant> argumentList { QVariant::fromValue(std::forward<Args>(args))... };
|
QList<QVariant> argumentList { QVariant::fromValue(std::forward<Args>(args))... };
|
||||||
QDBusPendingCall pc = this->asyncCallWithArgumentList(method, argumentList);
|
QDBusPendingCall pc = this->asyncCallWithArgumentList(method, argumentList);
|
||||||
auto pcw = new QDBusPendingCallWatcher(pc, this);
|
auto pcw = new QDBusPendingCallWatcher(pc, this);
|
||||||
connect(pcw, &QDBusPendingCallWatcher::finished, callback);
|
connect(pcw, &QDBusPendingCallWatcher::finished, callback);
|
||||||
|
return pcw;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Cancel all asynchronous DBus calls which are currently pending
|
//! Cancel all asynchronous DBus calls which are currently pending
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ namespace BlackSimPlugin
|
|||||||
if ((m_slowTimerCalls % 5) == 0)
|
if ((m_slowTimerCalls % 5) == 0)
|
||||||
{
|
{
|
||||||
// reading FPS resets average, so we only monitor over some time
|
// reading FPS resets average, so we only monitor over some time
|
||||||
m_averageFps = m_serviceProxy->getAverageFPS();
|
m_serviceProxy->getFrameStats(&m_averageFps, &m_simTimeRatio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,13 +319,34 @@ namespace BlackSimPlugin
|
|||||||
m_dbusInterface->callDBusAsync(QLatin1String("isUsingRealTime"), setterCallback(o_isRealTime));
|
m_dbusInterface->callDBusAsync(QLatin1String("isUsingRealTime"), setterCallback(o_isRealTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
double CXSwiftBusServiceProxy::getAverageFPS() const
|
void CXSwiftBusServiceProxy::getFrameStats(double *o_averageFps, double *o_simTimeRatio) const
|
||||||
{
|
{
|
||||||
return m_dbusInterface->callDBusRet<double>(QLatin1String("getAverageFPS"));
|
std::function<void(QDBusPendingCallWatcher *)> callback = [ = ](QDBusPendingCallWatcher * watcher)
|
||||||
|
{
|
||||||
|
QDBusPendingReply<double, double> reply = *watcher;
|
||||||
|
if (!reply.isError())
|
||||||
|
{
|
||||||
|
*o_averageFps = reply.argumentAt<0>();
|
||||||
|
*o_simTimeRatio = reply.argumentAt<1>();
|
||||||
|
}
|
||||||
|
watcher->deleteLater();
|
||||||
|
};
|
||||||
|
m_dbusInterface->callDBusAsync(QLatin1String("getFrameStats"), callback)->waitForFinished();
|
||||||
}
|
}
|
||||||
void CXSwiftBusServiceProxy::getAverageFPSAsync(double *o_frameRate)
|
|
||||||
|
void CXSwiftBusServiceProxy::getFrameStatsAsync(double *o_averageFps, double *o_simTimeRatio)
|
||||||
{
|
{
|
||||||
m_dbusInterface->callDBusAsync(QLatin1String("getAverageFPS"), setterCallback(o_frameRate));
|
std::function<void(QDBusPendingCallWatcher *)> callback = [ = ](QDBusPendingCallWatcher * watcher)
|
||||||
|
{
|
||||||
|
QDBusPendingReply<double, double> reply = *watcher;
|
||||||
|
if (!reply.isError())
|
||||||
|
{
|
||||||
|
*o_averageFps = reply.argumentAt<0>();
|
||||||
|
*o_simTimeRatio = reply.argumentAt<1>();
|
||||||
|
}
|
||||||
|
watcher->deleteLater();
|
||||||
|
};
|
||||||
|
m_dbusInterface->callDBusAsync(QLatin1String("getFrameStats"), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
double CXSwiftBusServiceProxy::getLatitudeDeg() const
|
double CXSwiftBusServiceProxy::getLatitudeDeg() const
|
||||||
|
|||||||
@@ -208,10 +208,10 @@ namespace BlackSimPlugin
|
|||||||
void isUsingRealTimeAsync(bool *o_isRealTime);
|
void isUsingRealTimeAsync(bool *o_isRealTime);
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! \copydoc XSwiftBus::CService::getAverageFPS
|
//! \copydoc XSwiftBus::CService::getFrameStats
|
||||||
//! @{
|
//! @{
|
||||||
double getAverageFPS() const;
|
void getFrameStats(double *o_averageFps, double *o_simTimeRatio) const;
|
||||||
void getAverageFPSAsync(double *o_frameRate);
|
void getFrameStatsAsync(double *o_averageFps, double *o_simTimeRatio);
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! \copydoc XSwiftBus::CService::getLatitudeDeg
|
//! \copydoc XSwiftBus::CService::getLatitudeDeg
|
||||||
|
|||||||
@@ -30,33 +30,48 @@ namespace XSwiftBus
|
|||||||
DataRef<xplane::data::sim::time::framerate_period> m_thisFramePeriodXP11;
|
DataRef<xplane::data::sim::time::framerate_period> m_thisFramePeriodXP11;
|
||||||
std::vector<float> m_samples;
|
std::vector<float> m_samples;
|
||||||
float m_total = 0;
|
float m_total = 0;
|
||||||
|
float m_totalOverBudget = 0;
|
||||||
size_t m_lastSampleIndex = 0;
|
size_t m_lastSampleIndex = 0;
|
||||||
static constexpr size_t c_maxSampleCount = 500;
|
static constexpr size_t c_maxSampleCount = 500;
|
||||||
|
static constexpr float c_framePeriodBudget = 0.05f;
|
||||||
|
|
||||||
FramePeriodSampler() : CDrawable(xplm_Phase_LastCockpit, false) {}
|
FramePeriodSampler() : CDrawable(xplm_Phase_LastCockpit, false) {}
|
||||||
|
|
||||||
float getAverageFPS()
|
std::pair<float, float> getFrameStats()
|
||||||
{
|
{
|
||||||
if (m_total == 0) { return 0; }
|
if (m_total == 0) { return {}; }
|
||||||
const float fps = m_samples.size() / m_total;
|
const float fps = m_samples.size() / m_total;
|
||||||
|
const float ratio = 1 - m_totalOverBudget / m_total;
|
||||||
m_total = 0;
|
m_total = 0;
|
||||||
|
m_totalOverBudget = 0;
|
||||||
m_samples.clear();
|
m_samples.clear();
|
||||||
m_lastSampleIndex = 0;
|
m_lastSampleIndex = 0;
|
||||||
return fps;
|
return { fps, ratio };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void draw() override // called once per frame
|
virtual void draw() override // called once per frame
|
||||||
{
|
{
|
||||||
float current = m_thisFramePeriodXP11.isValid() ? m_thisFramePeriodXP11.get() : m_thisFramePeriod.get();
|
float current = m_thisFramePeriodXP11.isValid() ? m_thisFramePeriodXP11.get() : m_thisFramePeriod.get();
|
||||||
|
|
||||||
++m_lastSampleIndex %= c_maxSampleCount;
|
++m_lastSampleIndex %= c_maxSampleCount;
|
||||||
if (m_samples.size() == c_maxSampleCount)
|
if (m_samples.size() == c_maxSampleCount)
|
||||||
{
|
{
|
||||||
m_total -= m_samples[m_lastSampleIndex];
|
auto& oldSample = m_samples[m_lastSampleIndex];
|
||||||
m_samples[m_lastSampleIndex] = current;
|
m_total -= oldSample;
|
||||||
|
if (oldSample > c_framePeriodBudget)
|
||||||
|
{
|
||||||
|
m_totalOverBudget -= oldSample - c_framePeriodBudget;
|
||||||
|
}
|
||||||
|
oldSample = current;
|
||||||
}
|
}
|
||||||
else { m_samples.push_back(current); }
|
else { m_samples.push_back(current); }
|
||||||
m_total += m_samples[m_lastSampleIndex];
|
|
||||||
|
m_total += current;
|
||||||
|
if (current > c_framePeriodBudget)
|
||||||
|
{
|
||||||
|
m_totalOverBudget += current - c_framePeriodBudget;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,10 +110,11 @@ namespace XSwiftBus
|
|||||||
return XSWIFTBUS_COMMIT;
|
return XSWIFTBUS_COMMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CService::getAverageFPS()
|
std::pair<double, double> CService::getFrameStats()
|
||||||
{
|
{
|
||||||
if (!m_framePeriodSampler) { return 0; }
|
if (!m_framePeriodSampler) { return {}; }
|
||||||
return static_cast<double>(m_framePeriodSampler->getAverageFPS());
|
const auto result = m_framePeriodSampler->getFrameStats();
|
||||||
|
return { static_cast<double>(result.first), static_cast<double>(result.second) };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CService::addTextMessage(const std::string &text, double red, double green, double blue)
|
void CService::addTextMessage(const std::string &text, double red, double green, double blue)
|
||||||
@@ -547,6 +563,18 @@ namespace XSwiftBus
|
|||||||
sendDBusReply(sender, serial, isUsingRealTime());
|
sendDBusReply(sender, serial, isUsingRealTime());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (message.getMethodName() == "getFrameStats")
|
||||||
|
{
|
||||||
|
queueDBusCall([ = ]()
|
||||||
|
{
|
||||||
|
const auto stats = getFrameStats();
|
||||||
|
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
|
||||||
|
reply.beginArgumentWrite();
|
||||||
|
reply.appendArgument(stats.first);
|
||||||
|
reply.appendArgument(stats.second);
|
||||||
|
sendDBusMessage(reply);
|
||||||
|
});
|
||||||
|
}
|
||||||
else if (message.getMethodName() == "getLatitudeDeg")
|
else if (message.getMethodName() == "getLatitudeDeg")
|
||||||
{
|
{
|
||||||
queueDBusCall([ = ]()
|
queueDBusCall([ = ]()
|
||||||
|
|||||||
@@ -112,8 +112,9 @@ namespace XSwiftBus
|
|||||||
|
|
||||||
//! Frames-per-second, averaged over the last 500 frames,
|
//! Frames-per-second, averaged over the last 500 frames,
|
||||||
//! or since this function was last called, whichever is later.
|
//! or since this function was last called, whichever is later.
|
||||||
|
//! Second part is the average simulation time ratio during the same period.
|
||||||
//! \return Zero if no samples were collected since this function was last called.
|
//! \return Zero if no samples were collected since this function was last called.
|
||||||
double getAverageFPS();
|
std::pair<double, double> getFrameStats();
|
||||||
|
|
||||||
//! Get aircraft latitude in degrees
|
//! Get aircraft latitude in degrees
|
||||||
double getLatitudeDeg() const { return m_latitude.get(); }
|
double getLatitudeDeg() const { return m_latitude.get(); }
|
||||||
|
|||||||
Reference in New Issue
Block a user