Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/GameEngine/Include/GameClient/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class Display : public SubsystemInterface
virtual void setCinematicTextFrames( Int frames ) { m_cinematicTextFrames = frames; }

virtual Real getAverageFPS() = 0; ///< returns the average FPS.
virtual Real getLow1PercentFPS() = 0; ///< returns the 1% low FPS.
virtual Real getCurrentFPS() = 0; ///< returns the current FPS.
virtual Int getLastFrameDrawCalls() = 0; ///< returns the number of draw calls issued in the previous frame

Expand Down
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Include/GameClient/InGameUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,16 +755,19 @@ friend class Drawable; // for selection/deselection transactions

// Render FPS Counter
DisplayString * m_renderFpsString;
DisplayString * m_renderFpsLowString;
DisplayString * m_renderFpsLimitString;
AsciiString m_renderFpsFont;
Int m_renderFpsPointSize;
Bool m_renderFpsBold;
Coord2D m_renderFpsPosition;
Color m_renderFpsColor;
Color m_renderFpsLowColor;
Color m_renderFpsLimitColor;
Color m_renderFpsDropColor;
UnsignedInt m_renderFpsRefreshMs;
UnsignedInt m_lastRenderFps;
UnsignedInt m_lastRenderFpsLow;
UnsignedInt m_lastRenderFpsLimit;
UnsignedInt m_lastRenderFpsUpdateMs;

Expand Down
49 changes: 40 additions & 9 deletions Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ const FieldParse InGameUI::s_fieldParseTable[] =
{ "RenderFpsBold", INI::parseBool, nullptr, offsetof( InGameUI, m_renderFpsBold ) },
{ "RenderFpsPosition", INI::parseCoord2D, nullptr, offsetof( InGameUI, m_renderFpsPosition ) },
{ "RenderFpsColor", INI::parseColorInt, nullptr, offsetof( InGameUI, m_renderFpsColor ) },
{ "RenderFpsLowColor", INI::parseColorInt, nullptr, offsetof( InGameUI, m_renderFpsLowColor ) },
{ "RenderFpsLimitColor", INI::parseColorInt, nullptr, offsetof( InGameUI, m_renderFpsLimitColor ) },
{ "RenderFpsDropColor", INI::parseColorInt, nullptr, offsetof( InGameUI, m_renderFpsDropColor ) },
{ "RenderFpsRefreshMs", INI::parseUnsignedInt, nullptr, offsetof( InGameUI, m_renderFpsRefreshMs ) },
Expand Down Expand Up @@ -1136,17 +1137,20 @@ InGameUI::InGameUI()
m_lastNetworkLatencyFrames = ~0u;

m_renderFpsString = nullptr;
m_renderFpsLowString = nullptr;
m_renderFpsLimitString = nullptr;
m_renderFpsFont = "Tahoma";
m_renderFpsPointSize = TheGlobalData->m_renderFpsFontSize;
m_renderFpsBold = TRUE;
m_renderFpsPosition.x = kHudAnchorX;
m_renderFpsPosition.y = kHudAnchorY;
m_renderFpsColor = GameMakeColor( 255, 255, 0, 255 );
m_renderFpsLowColor = GameMakeColor( 190, 180, 130, 255 );
m_renderFpsLimitColor = GameMakeColor(119, 119, 119, 255);
m_renderFpsDropColor = GameMakeColor( 0, 0, 0, 255 );
m_renderFpsRefreshMs = 1000;
m_lastRenderFps = ~0u;
m_lastRenderFpsLow = ~0u;
m_lastRenderFpsLimit = ~0u;
m_lastRenderFpsUpdateMs = 0u;

Expand Down Expand Up @@ -2248,6 +2252,8 @@ void InGameUI::freeCustomUiResources()
m_networkLatencyString = nullptr;
TheDisplayStringManager->freeDisplayString(m_renderFpsString);
m_renderFpsString = nullptr;
TheDisplayStringManager->freeDisplayString(m_renderFpsLowString);
m_renderFpsLowString = nullptr;
TheDisplayStringManager->freeDisplayString(m_renderFpsLimitString);
m_renderFpsLimitString = nullptr;
TheDisplayStringManager->freeDisplayString(m_systemTimeString);
Expand Down Expand Up @@ -5912,6 +5918,12 @@ void InGameUI::refreshRenderFpsResources()
m_lastRenderFpsUpdateMs = 0u;
}

if (!m_renderFpsLowString)
{
m_renderFpsLowString = TheDisplayStringManager->newDisplayString();
m_lastRenderFpsLow = ~0u;
}

if (!m_renderFpsLimitString)
{
m_renderFpsLimitString = TheDisplayStringManager->newDisplayString();
Expand All @@ -5922,6 +5934,7 @@ void InGameUI::refreshRenderFpsResources()
Int adjustedRenderFpsFontSize = TheGlobalLanguageData->adjustFontSize(m_renderFpsPointSize);
GameFont *fpsFont = TheWindowManager->winFindFont(m_renderFpsFont, adjustedRenderFpsFontSize, m_renderFpsBold);
m_renderFpsString->setFont(fpsFont);
m_renderFpsLowString->setFont(fpsFont);
m_renderFpsLimitString->setFont(fpsFont);

if (m_renderFpsPointSize > 0)
Expand Down Expand Up @@ -6034,6 +6047,15 @@ void InGameUI::updateRenderFpsString()
m_renderFpsString->setText(fpsStr);
m_lastRenderFps = renderFps;
}

const UnsignedInt renderFpsLow = (UnsignedInt)(TheDisplay->getLow1PercentFPS() + 0.5f);
if (renderFpsLow != m_lastRenderFpsLow)
{
UnicodeString lowStr;
lowStr.format(L"\x25BC%u", renderFpsLow);
m_renderFpsLowString->setText(lowStr);
m_lastRenderFpsLow = renderFpsLow;
}
}

void InGameUI::drawNetworkLatency(Int &x, Int &y)
Expand Down Expand Up @@ -6077,19 +6099,22 @@ void InGameUI::drawRenderFps(Int &x, Int &y)
updateRenderFpsString();
}

UnsignedInt renderFpsLimit = 0u;
UnsignedInt renderFpsLimit = RenderFpsPreset::UncappedFpsValue;
if (TheGlobalData->m_useFpsLimit)
{
renderFpsLimit = (UnsignedInt)TheFramePacer->getFramesPerSecondLimit();
if (renderFpsLimit == RenderFpsPreset::UncappedFpsValue)
{
renderFpsLimit = 0u;
}
}
if (renderFpsLimit != m_lastRenderFpsLimit)
{
UnicodeString fpsLimitStr;
fpsLimitStr.format(L"[%u]", renderFpsLimit);
if (renderFpsLimit == RenderFpsPreset::UncappedFpsValue)
{
fpsLimitStr.format(L"\x25B2X");
}
else
{
fpsLimitStr.format(L"\x25B2%u", renderFpsLimit);
}
m_renderFpsLimitString->setText(fpsLimitStr);
m_lastRenderFpsLimit = renderFpsLimit;
}
Expand All @@ -6100,14 +6125,20 @@ void InGameUI::drawRenderFps(Int &x, Int &y)
const Int drawY = kHudAnchorY + y;

m_renderFpsString->draw(kHudAnchorX + x, drawY, m_renderFpsColor, m_renderFpsDropColor);
x += m_renderFpsString->getWidth();
x += m_renderFpsString->getWidth() + kHudGapPx / 2;
m_renderFpsLowString->draw(kHudAnchorX + x, drawY, m_renderFpsLowColor, m_renderFpsDropColor);
x += m_renderFpsLowString->getWidth() + kHudGapPx / 2;
m_renderFpsLimitString->draw(kHudAnchorX + x, drawY, m_renderFpsLimitColor, m_renderFpsDropColor);
x += m_renderFpsLimitString->getWidth() + kHudGapPx;
}
else
{
m_renderFpsString->draw(m_renderFpsPosition.x, m_renderFpsPosition.y, m_renderFpsColor, m_renderFpsDropColor);
m_renderFpsLimitString->draw(m_renderFpsPosition.x + m_renderFpsString->getWidth(), m_renderFpsPosition.y, m_renderFpsLimitColor, m_renderFpsDropColor);
Int currentX = m_renderFpsPosition.x;
m_renderFpsString->draw(currentX, m_renderFpsPosition.y, m_renderFpsColor, m_renderFpsDropColor);
currentX += m_renderFpsString->getWidth() + kHudGapPx / 2;
m_renderFpsLowString->draw(currentX, m_renderFpsPosition.y, m_renderFpsLowColor, m_renderFpsDropColor);
currentX += m_renderFpsLowString->getWidth() + kHudGapPx / 2;
m_renderFpsLimitString->draw(currentX, m_renderFpsPosition.y, m_renderFpsLimitColor, m_renderFpsDropColor);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,40 @@ class RTS2DScene;
class RTS3DInterfaceScene;
class TextureClass;

constexpr const Real TICKS_PER_SECOND = 62500.0f;

class QuantizedUnsignedShort
{
public:
QuantizedUnsignedShort() : m_value(2083) {}
explicit QuantizedUnsignedShort(UnsignedShort val) : m_value(val) {}

static QuantizedUnsignedShort fromSeconds(Real seconds)
{
Int64 ticks = (Int64)(seconds * TICKS_PER_SECOND + 0.5f);
if (ticks >= 65535)
{
return QuantizedUnsignedShort(65535);
}
if (ticks <= 0)
{
return QuantizedUnsignedShort(1);
}
return QuantizedUnsignedShort((UnsignedShort)ticks);
}

UnsignedShort getValue() const { return m_value; }
void setValue(UnsignedShort val) { m_value = val; }

Real toFPS() const { return TICKS_PER_SECOND / (Real)m_value; }
Real toSeconds() const { return (Real)m_value / TICKS_PER_SECOND; }

operator UnsignedShort() const { return m_value; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove this operator and call getValue() explicitly. Makes for less sneaky code.


private:
UnsignedShort m_value;
};


//=============================================================================
/** W3D implementation of the game display which is responsible for creating
Expand Down Expand Up @@ -148,6 +182,7 @@ class W3DDisplay : public Display

void drawFPSStats(); ///< draw the fps on the screen
virtual Real getAverageFPS() override; ///< return the average FPS.
virtual Real getLow1PercentFPS() override; ///< return the 1% low FPS.
virtual Real getCurrentFPS() override; ///< return the current FPS.
virtual Int getLastFrameDrawCalls() override; ///< returns the number of draw calls issued in the previous frame

Expand All @@ -161,7 +196,10 @@ class W3DDisplay : public Display
void drawCurrentDebugDisplay(); ///< draws current debug display
void calculateTerrainLOD(); ///< Calculate terrain LOD.
void renderLetterBox(UnsignedInt time); ///< draw letter box border
void updateAverageFPS(); ///< calculate the average fps over the last 30 frames.
void updatePerformanceMetrics(); ///< update the average and 1% low fps metrics.
void addFpsSample(Real elapsedSeconds); ///< add a new sample to the history buffer.
Real calculateAverageFPS(Real windowSeconds); ///< calculate average FPS over a time window.
Real calculateLow1PercentFPS(Real windowSeconds); ///< calculate 1% low FPS over a time window.
void setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale);
virtual void onBeginBatch() override;
virtual void onEndBatch() override;
Expand All @@ -172,9 +210,17 @@ class W3DDisplay : public Display
Render2DClass *m_2DRender; ///< interface for common 2D functions
IRegion2D m_clipRegion; ///< the clipping region for images
Bool m_isClippedEnabled; ///<used by 2D drawing operations to define clip re
Real m_averageFPS; ///<average fps over the last 30 frames.
Real m_averageFPS; ///< average fps over the last 1.0s.
Real m_low1PercentFPS; ///<1% low fps.
Real m_currentFPS; ///<current fps value.

enum { FPS_HISTORY_SIZE = 4096 }; // degrades gracefully beyond this size
QuantizedUnsignedShort m_durationHistory[FPS_HISTORY_SIZE];
Int m_historyOffset;
Int m_historyCount;
Int64 m_lastUpdateTime64;
UnsignedInt m_lastLow1PercentUpdateMs;

TextureClass *m_batchTexture;
DrawImageMode m_batchMode;
Bool m_batchGrayscale;
Expand Down
Loading
Loading