mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added stats overlay
This commit is contained in:
parent
ab443a1ac2
commit
07d77d09dc
@ -1,6 +1,41 @@
|
|||||||
|
#include <Common/Time.h>
|
||||||
#include <D3dDdi/ScopedCriticalSection.h>
|
#include <D3dDdi/ScopedCriticalSection.h>
|
||||||
|
#include <Gdi/GuiThread.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
unsigned g_depth = 0;
|
||||||
|
Overlay::StatsWindow* g_statsWindow = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
namespace D3dDdi
|
namespace D3dDdi
|
||||||
{
|
{
|
||||||
Compat::CriticalSection ScopedCriticalSection::s_cs;
|
Compat::CriticalSection ScopedCriticalSection::s_cs;
|
||||||
|
|
||||||
|
ScopedCriticalSection::ScopedCriticalSection()
|
||||||
|
: Compat::ScopedCriticalSection(s_cs)
|
||||||
|
{
|
||||||
|
if (0 == g_depth)
|
||||||
|
{
|
||||||
|
g_statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (g_statsWindow)
|
||||||
|
{
|
||||||
|
g_statsWindow->m_ddiUsage.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++g_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedCriticalSection::~ScopedCriticalSection()
|
||||||
|
{
|
||||||
|
--g_depth;
|
||||||
|
if (0 == g_depth)
|
||||||
|
{
|
||||||
|
if (g_statsWindow)
|
||||||
|
{
|
||||||
|
g_statsWindow->m_ddiUsage.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ namespace D3dDdi
|
|||||||
class ScopedCriticalSection : public Compat::ScopedCriticalSection
|
class ScopedCriticalSection : public Compat::ScopedCriticalSection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopedCriticalSection() : Compat::ScopedCriticalSection(s_cs) {}
|
ScopedCriticalSection();
|
||||||
|
~ScopedCriticalSection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Compat::CriticalSection s_cs;
|
static Compat::CriticalSection s_cs;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <Gdi/Window.h>
|
#include <Gdi/Window.h>
|
||||||
#include <Gdi/WinProc.h>
|
#include <Gdi/WinProc.h>
|
||||||
#include <Overlay/ConfigWindow.h>
|
#include <Overlay/ConfigWindow.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
#include <Win32/DisplayMode.h>
|
#include <Win32/DisplayMode.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -319,6 +320,13 @@ namespace
|
|||||||
|
|
||||||
Gdi::GuiThread::execute([]()
|
Gdi::GuiThread::execute([]()
|
||||||
{
|
{
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_present.add();
|
||||||
|
statsWindow->update();
|
||||||
|
}
|
||||||
|
|
||||||
auto configWindow = Gdi::GuiThread::getConfigWindow();
|
auto configWindow = Gdi::GuiThread::getConfigWindow();
|
||||||
if (configWindow)
|
if (configWindow)
|
||||||
{
|
{
|
||||||
@ -531,6 +539,11 @@ namespace DDraw
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow && statsWindow->isVisible())
|
||||||
|
{
|
||||||
|
statsWindow->updateStats();
|
||||||
|
}
|
||||||
updateNow(PrimarySurface::getPrimary());
|
updateNow(PrimarySurface::getPrimary());
|
||||||
}
|
}
|
||||||
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
|
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
|
||||||
@ -557,6 +570,12 @@ namespace DDraw
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow && statsWindow->isVisible())
|
||||||
|
{
|
||||||
|
statsWindow->updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||||
if (!g_isUpdateReady)
|
if (!g_isUpdateReady)
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
#include <DDraw/Surfaces/PrimarySurfaceImpl.h>
|
#include <DDraw/Surfaces/PrimarySurfaceImpl.h>
|
||||||
#include <Dll/Dll.h>
|
#include <Dll/Dll.h>
|
||||||
#include <Gdi/Gdi.h>
|
#include <Gdi/Gdi.h>
|
||||||
|
#include <Gdi/GuiThread.h>
|
||||||
#include <Gdi/Region.h>
|
#include <Gdi/Region.h>
|
||||||
#include <Gdi/VirtualScreen.h>
|
#include <Gdi/VirtualScreen.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -97,6 +99,11 @@ namespace DDraw
|
|||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
bltToGdi(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
bltToGdi(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_blit.add();
|
||||||
|
}
|
||||||
RealPrimarySurface::scheduleUpdate();
|
RealPrimarySurface::scheduleUpdate();
|
||||||
PrimarySurface::waitForIdle();
|
PrimarySurface::waitForIdle();
|
||||||
}
|
}
|
||||||
@ -116,6 +123,11 @@ namespace DDraw
|
|||||||
HRESULT result = SurfaceImpl::BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
HRESULT result = SurfaceImpl::BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_blit.add();
|
||||||
|
}
|
||||||
RealPrimarySurface::scheduleUpdate();
|
RealPrimarySurface::scheduleUpdate();
|
||||||
PrimarySurface::waitForIdle();
|
PrimarySurface::waitForIdle();
|
||||||
}
|
}
|
||||||
@ -158,6 +170,12 @@ namespace DDraw
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_flip.add();
|
||||||
|
}
|
||||||
|
|
||||||
PrimarySurface::updateFrontResource();
|
PrimarySurface::updateFrontResource();
|
||||||
result = RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
|
result = RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
|
||||||
if (SUCCEEDED(result) && Config::Settings::FpsLimiter::FLIPEND == Config::fpsLimiter.get())
|
if (SUCCEEDED(result) && Config::Settings::FpsLimiter::FLIPEND == Config::fpsLimiter.get())
|
||||||
@ -233,6 +251,11 @@ namespace DDraw
|
|||||||
HRESULT result = SurfaceImpl::ReleaseDC(This, hDC);
|
HRESULT result = SurfaceImpl::ReleaseDC(This, hDC);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_lock.add();
|
||||||
|
}
|
||||||
RealPrimarySurface::scheduleUpdate();
|
RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -277,6 +300,11 @@ namespace DDraw
|
|||||||
HRESULT result = SurfaceImpl::Unlock(This, lpRect);
|
HRESULT result = SurfaceImpl::Unlock(This, lpRect);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->m_lock.add();
|
||||||
|
}
|
||||||
RealPrimarySurface::scheduleUpdate();
|
RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -291,6 +291,14 @@
|
|||||||
<ClInclude Include="Overlay\LabelControl.h" />
|
<ClInclude Include="Overlay\LabelControl.h" />
|
||||||
<ClInclude Include="Overlay\ScrollBarControl.h" />
|
<ClInclude Include="Overlay\ScrollBarControl.h" />
|
||||||
<ClInclude Include="Overlay\SettingControl.h" />
|
<ClInclude Include="Overlay\SettingControl.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsControl.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsEventCount.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsEventGroup.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsEventTime.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsQueue.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsEventRate.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsTimer.h" />
|
||||||
|
<ClInclude Include="Overlay\StatsWindow.h" />
|
||||||
<ClInclude Include="Overlay\Window.h" />
|
<ClInclude Include="Overlay\Window.h" />
|
||||||
<ClInclude Include="Win32\DisplayMode.h" />
|
<ClInclude Include="Win32\DisplayMode.h" />
|
||||||
<ClInclude Include="Win32\Log.h" />
|
<ClInclude Include="Win32\Log.h" />
|
||||||
@ -406,6 +414,14 @@
|
|||||||
<ClCompile Include="Overlay\LabelControl.cpp" />
|
<ClCompile Include="Overlay\LabelControl.cpp" />
|
||||||
<ClCompile Include="Overlay\ScrollBarControl.cpp" />
|
<ClCompile Include="Overlay\ScrollBarControl.cpp" />
|
||||||
<ClCompile Include="Overlay\SettingControl.cpp" />
|
<ClCompile Include="Overlay\SettingControl.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsControl.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsEventCount.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsEventGroup.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsEventTime.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsQueue.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsEventRate.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsTimer.cpp" />
|
||||||
|
<ClCompile Include="Overlay\StatsWindow.cpp" />
|
||||||
<ClCompile Include="Overlay\Window.cpp" />
|
<ClCompile Include="Overlay\Window.cpp" />
|
||||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||||
<ClCompile Include="Win32\Log.cpp" />
|
<ClCompile Include="Win32\Log.cpp" />
|
||||||
|
@ -603,6 +603,30 @@
|
|||||||
<ClInclude Include="Config\Settings\ResolutionScaleFilter.h">
|
<ClInclude Include="Config\Settings\ResolutionScaleFilter.h">
|
||||||
<Filter>Header Files\Config\Settings</Filter>
|
<Filter>Header Files\Config\Settings</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsWindow.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsControl.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsQueue.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsTimer.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsEventRate.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsEventTime.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsEventCount.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Overlay\StatsEventGroup.h">
|
||||||
|
<Filter>Header Files\Overlay</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Gdi\Gdi.cpp">
|
<ClCompile Include="Gdi\Gdi.cpp">
|
||||||
@ -944,6 +968,30 @@
|
|||||||
<ClCompile Include="DDraw\Surfaces\PalettizedTextureImpl.cpp">
|
<ClCompile Include="DDraw\Surfaces\PalettizedTextureImpl.cpp">
|
||||||
<Filter>Source Files\DDraw\Surfaces</Filter>
|
<Filter>Source Files\DDraw\Surfaces</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsWindow.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsControl.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsQueue.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsTimer.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsEventRate.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsEventTime.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsEventCount.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Overlay\StatsEventGroup.cpp">
|
||||||
|
<Filter>Source Files\Overlay</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="DDrawCompat.rc">
|
<ResourceCompile Include="DDrawCompat.rc">
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <Gdi/Region.h>
|
#include <Gdi/Region.h>
|
||||||
#include <Gdi/WinProc.h>
|
#include <Gdi/WinProc.h>
|
||||||
#include <Overlay/ConfigWindow.h>
|
#include <Overlay/ConfigWindow.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
#include <Win32/DisplayMode.h>
|
#include <Win32/DisplayMode.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -20,6 +21,7 @@ namespace
|
|||||||
|
|
||||||
unsigned g_threadId = 0;
|
unsigned g_threadId = 0;
|
||||||
Overlay::ConfigWindow* g_configWindow = nullptr;
|
Overlay::ConfigWindow* g_configWindow = nullptr;
|
||||||
|
Overlay::StatsWindow* g_statsWindow = nullptr;
|
||||||
HWND g_messageWindow = nullptr;
|
HWND g_messageWindow = nullptr;
|
||||||
bool g_isReady = false;
|
bool g_isReady = false;
|
||||||
|
|
||||||
@ -78,6 +80,9 @@ namespace
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Overlay::StatsWindow statsWindow;
|
||||||
|
g_statsWindow = &statsWindow;
|
||||||
|
|
||||||
Overlay::ConfigWindow configWindow;
|
Overlay::ConfigWindow configWindow;
|
||||||
g_configWindow = &configWindow;
|
g_configWindow = &configWindow;
|
||||||
|
|
||||||
@ -160,6 +165,11 @@ namespace Gdi
|
|||||||
return g_configWindow;
|
return g_configWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Overlay::StatsWindow* getStatsWindow()
|
||||||
|
{
|
||||||
|
return g_statsWindow;
|
||||||
|
}
|
||||||
|
|
||||||
bool isGuiThreadWindow(HWND hwnd)
|
bool isGuiThreadWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
return GetWindowThreadProcessId(hwnd, nullptr) == g_threadId;
|
return GetWindowThreadProcessId(hwnd, nullptr) == g_threadId;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
namespace Overlay
|
namespace Overlay
|
||||||
{
|
{
|
||||||
class ConfigWindow;
|
class ConfigWindow;
|
||||||
|
class StatsWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
@ -22,6 +23,7 @@ namespace Gdi
|
|||||||
void setWindowRgn(HWND hwnd, Gdi::Region rgn);
|
void setWindowRgn(HWND hwnd, Gdi::Region rgn);
|
||||||
|
|
||||||
Overlay::ConfigWindow* getConfigWindow();
|
Overlay::ConfigWindow* getConfigWindow();
|
||||||
|
Overlay::StatsWindow* getStatsWindow();
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
void execute(const Func& func) { executeFunc(std::cref(func)); }
|
void execute(const Func& func) { executeFunc(std::cref(func)); }
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <Gdi/Window.h>
|
#include <Gdi/Window.h>
|
||||||
#include <Gdi/WinProc.h>
|
#include <Gdi/WinProc.h>
|
||||||
#include <Overlay/ConfigWindow.h>
|
#include <Overlay/ConfigWindow.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
#include <Win32/DisplayMode.h>
|
#include <Win32/DisplayMode.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -141,18 +142,39 @@ namespace
|
|||||||
switch (uMsg)
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
case WM_ACTIVATEAPP:
|
case WM_ACTIVATEAPP:
|
||||||
if (!wParam)
|
Gdi::GuiThread::execute([&]()
|
||||||
{
|
{
|
||||||
Gdi::GuiThread::execute([&]()
|
static bool hidden = false;
|
||||||
|
static bool configVisible = false;
|
||||||
|
static bool statsVisible = false;
|
||||||
|
|
||||||
|
auto configWindow = Gdi::GuiThread::getConfigWindow();
|
||||||
|
auto statsWindow = Gdi::GuiThread::getStatsWindow();
|
||||||
|
if (!wParam && !hidden)
|
||||||
|
{
|
||||||
|
configVisible = configWindow ? configWindow->isVisible() : false;
|
||||||
|
statsVisible = statsWindow ? statsWindow->isVisible() : false;
|
||||||
|
hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configWindow)
|
||||||
|
{
|
||||||
|
configWindow->setVisible(wParam ? configVisible : false);
|
||||||
|
}
|
||||||
|
if (statsWindow)
|
||||||
|
{
|
||||||
|
statsWindow->setVisible(wParam ? statsVisible : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wParam)
|
||||||
|
{
|
||||||
|
hidden = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
auto configWindow = Gdi::GuiThread::getConfigWindow();
|
|
||||||
if (configWindow)
|
|
||||||
{
|
|
||||||
configWindow->setVisible(false);
|
|
||||||
}
|
|
||||||
CALL_ORIG_FUNC(ClipCursor)(nullptr);
|
CALL_ORIG_FUNC(ClipCursor)(nullptr);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_CTLCOLORSCROLLBAR:
|
case WM_CTLCOLORSCROLLBAR:
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <Gdi/Window.h>
|
#include <Gdi/Window.h>
|
||||||
#include <Input/Input.h>
|
#include <Input/Input.h>
|
||||||
#include <Overlay/ConfigWindow.h>
|
#include <Overlay/ConfigWindow.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -395,6 +396,15 @@ namespace Gdi
|
|||||||
}
|
}
|
||||||
|
|
||||||
RECT wr = {};
|
RECT wr = {};
|
||||||
|
auto statsWindow = GuiThread::getStatsWindow();
|
||||||
|
if (statsWindow && statsWindow->isVisible())
|
||||||
|
{
|
||||||
|
GetWindowRect(statsWindow->getWindow(), &wr);
|
||||||
|
auto visibleRegion(getWindowRegion(statsWindow->getWindow()));
|
||||||
|
visibleRegion.offset(wr.left, wr.top);
|
||||||
|
layeredWindows.push_back({ statsWindow->getWindow(), wr, visibleRegion });
|
||||||
|
}
|
||||||
|
|
||||||
auto configWindow = GuiThread::getConfigWindow();
|
auto configWindow = GuiThread::getConfigWindow();
|
||||||
if (configWindow && configWindow->isVisible())
|
if (configWindow && configWindow->isVisible())
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
namespace Overlay
|
namespace Overlay
|
||||||
{
|
{
|
||||||
ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent, const std::vector<std::string>& values)
|
ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent, const std::vector<std::string>& values)
|
||||||
: Window(&static_cast<Window&>(parent.getRoot()), calculateRect(parent, values.size()))
|
: Window(&static_cast<Window&>(parent.getRoot()), calculateRect(parent, values.size()), WS_BORDER)
|
||||||
, m_parent(parent)
|
, m_parent(parent)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < static_cast<int>(values.size()); ++i)
|
for (int i = 0; i < static_cast<int>(values.size()); ++i)
|
||||||
@ -83,5 +83,6 @@ namespace Overlay
|
|||||||
{
|
{
|
||||||
m_highlightedChild = nullptr;
|
m_highlightedChild = nullptr;
|
||||||
Window::setVisible(visible);
|
Window::setVisible(visible);
|
||||||
|
Input::setCapture(visible ? this : m_parentWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <Common/Hook.h>
|
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
#include <Config/Config.h>
|
#include <Config/Config.h>
|
||||||
#include <Gdi/GuiThread.h>
|
#include <Gdi/GuiThread.h>
|
||||||
@ -17,7 +16,7 @@ namespace
|
|||||||
namespace Overlay
|
namespace Overlay
|
||||||
{
|
{
|
||||||
ConfigWindow::ConfigWindow()
|
ConfigWindow::ConfigWindow()
|
||||||
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 430 }, Config::configHotKey.get())
|
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 430 }, WS_BORDER, Config::configHotKey.get())
|
||||||
, m_buttonCount(0)
|
, m_buttonCount(0)
|
||||||
, m_focus(nullptr)
|
, m_focus(nullptr)
|
||||||
{
|
{
|
||||||
@ -186,6 +185,7 @@ namespace Overlay
|
|||||||
if (isVisible != Window::isVisible())
|
if (isVisible != Window::isVisible())
|
||||||
{
|
{
|
||||||
Window::setVisible(isVisible);
|
Window::setVisible(isVisible);
|
||||||
|
Input::setCapture(isVisible ? this : nullptr);
|
||||||
setFocus(nullptr);
|
setFocus(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,4 +33,13 @@ namespace Overlay
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LabelControl::setLabel(const std::string label)
|
||||||
|
{
|
||||||
|
if (m_label != label)
|
||||||
|
{
|
||||||
|
m_label = label;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace Overlay
|
|||||||
virtual void onLButtonDown(POINT pos) override;
|
virtual void onLButtonDown(POINT pos) override;
|
||||||
|
|
||||||
const std::string& getLabel() const { return m_label; }
|
const std::string& getLabel() const { return m_label; }
|
||||||
void setLabel(const std::string label) { m_label = label; }
|
void setLabel(const std::string label);
|
||||||
void setColor(COLORREF color);
|
void setColor(COLORREF color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
30
DDrawCompat/Overlay/StatsControl.cpp
Normal file
30
DDrawCompat/Overlay/StatsControl.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
|
#include <Overlay/StatsControl.h>
|
||||||
|
|
||||||
|
namespace Overlay
|
||||||
|
{
|
||||||
|
StatsControl::StatsControl(StatsWindow& parent, const RECT& rect, const std::string& caption, UpdateFunc updateFunc, DWORD style)
|
||||||
|
: Control(&parent, rect, style)
|
||||||
|
, m_captionLabel(*this, { rect.left, rect.top,
|
||||||
|
rect.left + NAME_LABEL_WIDTH, rect.bottom }, caption, 0, WS_DISABLED | WS_VISIBLE)
|
||||||
|
, m_curLabel(*this, { m_captionLabel.getRect().right, rect.top,
|
||||||
|
m_captionLabel.getRect().right + VALUE_LABEL_WIDTH, rect.bottom}, std::string(), DT_RIGHT)
|
||||||
|
, m_avgLabel(*this, { m_curLabel.getRect().right, rect.top,
|
||||||
|
m_curLabel.getRect().right + VALUE_LABEL_WIDTH, rect.bottom }, std::string(), DT_RIGHT)
|
||||||
|
, m_minLabel(*this, { m_avgLabel.getRect().right, rect.top,
|
||||||
|
m_avgLabel.getRect().right + VALUE_LABEL_WIDTH, rect.bottom }, std::string(), DT_RIGHT)
|
||||||
|
, m_maxLabel(*this, { m_minLabel.getRect().right, rect.top,
|
||||||
|
m_minLabel.getRect().right + VALUE_LABEL_WIDTH, rect.bottom }, std::string(), DT_RIGHT)
|
||||||
|
, m_updateFunc(updateFunc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsControl::update(StatsQueue::TickCount tickCount)
|
||||||
|
{
|
||||||
|
auto stats = m_updateFunc(tickCount);
|
||||||
|
m_curLabel.setLabel(stats[0]);
|
||||||
|
m_avgLabel.setLabel(stats[1]);
|
||||||
|
m_minLabel.setLabel(stats[2]);
|
||||||
|
m_maxLabel.setLabel(stats[3]);
|
||||||
|
}
|
||||||
|
}
|
33
DDrawCompat/Overlay/StatsControl.h
Normal file
33
DDrawCompat/Overlay/StatsControl.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <Overlay/LabelControl.h>
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
namespace Overlay
|
||||||
|
{
|
||||||
|
class StatsWindow;
|
||||||
|
|
||||||
|
class StatsControl : public Control
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int NAME_LABEL_WIDTH = 70;
|
||||||
|
static const int VALUE_LABEL_WIDTH = 40;
|
||||||
|
|
||||||
|
typedef std::function<std::array<std::string, 4>(StatsQueue::TickCount)> UpdateFunc;
|
||||||
|
|
||||||
|
StatsControl(StatsWindow& parent, const RECT& rect, const std::string& caption, UpdateFunc updateFunc, DWORD style);
|
||||||
|
|
||||||
|
void update(StatsQueue::TickCount tickCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LabelControl m_captionLabel;
|
||||||
|
LabelControl m_curLabel;
|
||||||
|
LabelControl m_avgLabel;
|
||||||
|
LabelControl m_minLabel;
|
||||||
|
LabelControl m_maxLabel;
|
||||||
|
UpdateFunc m_updateFunc;
|
||||||
|
};
|
||||||
|
}
|
37
DDrawCompat/Overlay/StatsEventCount.cpp
Normal file
37
DDrawCompat/Overlay/StatsEventCount.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsEventCount.h>
|
||||||
|
|
||||||
|
StatsEventCount::StatsEventCount()
|
||||||
|
: m_sampleCounts(TICKS_PER_SEC)
|
||||||
|
, m_sampleCount(0)
|
||||||
|
, m_totalSampleCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsEventCount::add(TickCount tickCount)
|
||||||
|
{
|
||||||
|
setTickCount(tickCount);
|
||||||
|
m_sampleCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsEventCount::finalize(SampleCount& sampleCount, Stat& sum, Stat& min, Stat& max)
|
||||||
|
{
|
||||||
|
const uint32_t index = getCurrentTickCount() % TICKS_PER_SEC;
|
||||||
|
m_totalSampleCount += m_sampleCount;
|
||||||
|
m_totalSampleCount -= m_sampleCounts[index];
|
||||||
|
m_sampleCounts[index] = m_sampleCount;
|
||||||
|
m_sampleCount = 0;
|
||||||
|
|
||||||
|
sum = m_totalSampleCount;
|
||||||
|
min = m_totalSampleCount;
|
||||||
|
max = m_totalSampleCount;
|
||||||
|
sampleCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsEventCount::resetTickCount()
|
||||||
|
{
|
||||||
|
std::fill(m_sampleCounts.begin(), m_sampleCounts.end(), 0);
|
||||||
|
m_sampleCount = 0;
|
||||||
|
m_totalSampleCount = 0;
|
||||||
|
}
|
19
DDrawCompat/Overlay/StatsEventCount.h
Normal file
19
DDrawCompat/Overlay/StatsEventCount.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
class StatsEventCount : public StatsQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsEventCount();
|
||||||
|
|
||||||
|
void add(TickCount tickCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void finalize(SampleCount& sampleCount, Stat& sum, Stat& min, Stat& max) override;
|
||||||
|
virtual void resetTickCount() override;
|
||||||
|
|
||||||
|
std::vector<SampleCount> m_sampleCounts;
|
||||||
|
SampleCount m_sampleCount;
|
||||||
|
SampleCount m_totalSampleCount;
|
||||||
|
};
|
15
DDrawCompat/Overlay/StatsEventGroup.cpp
Normal file
15
DDrawCompat/Overlay/StatsEventGroup.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <Overlay/StatsEventGroup.h>
|
||||||
|
|
||||||
|
StatsEventGroup::StatsEventGroup()
|
||||||
|
: m_rate(m_time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsEventGroup::add()
|
||||||
|
{
|
||||||
|
auto qpcNow = Time::queryPerformanceCounter();
|
||||||
|
auto tickCount = StatsQueue::getTickCount(qpcNow);
|
||||||
|
|
||||||
|
m_count.add(tickCount);
|
||||||
|
m_time.add(tickCount, qpcNow);
|
||||||
|
}
|
17
DDrawCompat/Overlay/StatsEventGroup.h
Normal file
17
DDrawCompat/Overlay/StatsEventGroup.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsEventCount.h>
|
||||||
|
#include <Overlay/StatsEventRate.h>
|
||||||
|
#include <Overlay/StatsEventTime.h>
|
||||||
|
|
||||||
|
class StatsEventGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsEventGroup();
|
||||||
|
|
||||||
|
void add();
|
||||||
|
|
||||||
|
StatsEventCount m_count;
|
||||||
|
StatsEventTime m_time;
|
||||||
|
StatsEventRate m_rate;
|
||||||
|
};
|
22
DDrawCompat/Overlay/StatsEventRate.cpp
Normal file
22
DDrawCompat/Overlay/StatsEventRate.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsEventRate.h>
|
||||||
|
#include <Overlay/StatsEventTime.h>
|
||||||
|
|
||||||
|
StatsEventRate::StatsEventRate(StatsEventTime& parent)
|
||||||
|
: m_parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StatsQueue::Stats StatsEventRate::getRawStats(TickCount tickCount)
|
||||||
|
{
|
||||||
|
auto stats = m_parent.getRawStats(tickCount);
|
||||||
|
std::swap(stats.min, stats.max);
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
double StatsEventRate::convert(double stat)
|
||||||
|
{
|
||||||
|
return Time::g_qpcFrequency / stat;
|
||||||
|
}
|
17
DDrawCompat/Overlay/StatsEventRate.h
Normal file
17
DDrawCompat/Overlay/StatsEventRate.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
class StatsEventTime;
|
||||||
|
|
||||||
|
class StatsEventRate : public StatsQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsEventRate(StatsEventTime& parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual double convert(double stat) override;
|
||||||
|
virtual Stats getRawStats(TickCount tickCount) override;
|
||||||
|
|
||||||
|
StatsEventTime& m_parent;
|
||||||
|
};
|
22
DDrawCompat/Overlay/StatsEventTime.cpp
Normal file
22
DDrawCompat/Overlay/StatsEventTime.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsEventTime.h>
|
||||||
|
|
||||||
|
StatsEventTime::StatsEventTime()
|
||||||
|
: m_qpcLast(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsEventTime::add(TickCount tickCount, long long qpcNow)
|
||||||
|
{
|
||||||
|
if (0 != m_qpcLast && qpcNow - m_qpcLast < HISTORY_TIME * Time::g_qpcFrequency)
|
||||||
|
{
|
||||||
|
addSample(tickCount, qpcNow - m_qpcLast);
|
||||||
|
}
|
||||||
|
m_qpcLast = qpcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
double StatsEventTime::convert(double stat)
|
||||||
|
{
|
||||||
|
return 1000 * stat / Time::g_qpcFrequency;
|
||||||
|
}
|
18
DDrawCompat/Overlay/StatsEventTime.h
Normal file
18
DDrawCompat/Overlay/StatsEventTime.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
class StatsEventTime : public StatsQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsEventTime();
|
||||||
|
|
||||||
|
void add(TickCount tickCount, long long qpcNow);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class StatsEventRate;
|
||||||
|
|
||||||
|
virtual double convert(double stat) override;
|
||||||
|
|
||||||
|
long long m_qpcLast;
|
||||||
|
};
|
138
DDrawCompat/Overlay/StatsQueue.cpp
Normal file
138
DDrawCompat/Overlay/StatsQueue.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool greaterEqual(StatsQueue::Stat a, StatsQueue::Stat b)
|
||||||
|
{
|
||||||
|
return a >= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lessEqual(StatsQueue::Stat a, StatsQueue::Stat b)
|
||||||
|
{
|
||||||
|
return a <= b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsQueue::StatsQueue()
|
||||||
|
: m_sums(HISTORY_SIZE)
|
||||||
|
, m_sampleCounts(HISTORY_SIZE)
|
||||||
|
, m_currentTickCount(0)
|
||||||
|
, m_sampleCount(0)
|
||||||
|
, m_sum(0)
|
||||||
|
, m_min(0)
|
||||||
|
, m_max(0)
|
||||||
|
, m_totalSampleCount(0)
|
||||||
|
, m_totalSum(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsQueue::addSample(TickCount tickCount, Stat stat)
|
||||||
|
{
|
||||||
|
setTickCount(tickCount);
|
||||||
|
|
||||||
|
if (0 == m_sampleCount)
|
||||||
|
{
|
||||||
|
m_min = stat;
|
||||||
|
m_max = stat;
|
||||||
|
}
|
||||||
|
else if (stat < m_min)
|
||||||
|
{
|
||||||
|
m_min = stat;
|
||||||
|
}
|
||||||
|
else if (stat > m_max)
|
||||||
|
{
|
||||||
|
m_max = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
++m_sampleCount;
|
||||||
|
m_sum += stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
double StatsQueue::getAvg(Stat sum, SampleCount sampleCount) const
|
||||||
|
{
|
||||||
|
return 0 == sampleCount ? NAN : (static_cast<double>(sum) / sampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsQueue::Stats StatsQueue::getRawStats(TickCount tickCount)
|
||||||
|
{
|
||||||
|
setTickCount(tickCount);
|
||||||
|
Stats stats = {};
|
||||||
|
const uint32_t index = (m_currentTickCount - 1) % HISTORY_SIZE;
|
||||||
|
stats.cur = getAvg(m_sums[index], m_sampleCounts[index]);
|
||||||
|
stats.avg = getAvg(m_totalSum, m_totalSampleCount);
|
||||||
|
stats.min = m_minQueue.empty() ? NAN : m_minQueue.front().stat;
|
||||||
|
stats.max = m_maxQueue.empty() ? NAN : m_maxQueue.front().stat;
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsQueue::SampleCount StatsQueue::getSampleCount(TickCount tickCount) const
|
||||||
|
{
|
||||||
|
return m_sampleCounts[tickCount % HISTORY_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsQueue::Stats StatsQueue::getStats(TickCount tickCount)
|
||||||
|
{
|
||||||
|
Stats stats = getRawStats(tickCount);
|
||||||
|
stats.cur = convert(stats.cur);
|
||||||
|
stats.avg = convert(stats.avg);
|
||||||
|
stats.min = convert(stats.min);
|
||||||
|
stats.max = convert(stats.max);
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsQueue::push()
|
||||||
|
{
|
||||||
|
finalize(m_sampleCount, m_sum, m_min, m_max);
|
||||||
|
|
||||||
|
uint32_t index = m_currentTickCount % HISTORY_SIZE;
|
||||||
|
m_totalSampleCount -= m_sampleCounts[index];
|
||||||
|
m_totalSampleCount += m_sampleCount;
|
||||||
|
m_totalSum -= m_sums[index];
|
||||||
|
m_totalSum += m_sum;
|
||||||
|
m_sampleCounts[index] = m_sampleCount;
|
||||||
|
m_sums[index] = m_sum;
|
||||||
|
|
||||||
|
pushToMinMaxQueue(m_minQueue, m_min, lessEqual);
|
||||||
|
pushToMinMaxQueue(m_maxQueue, m_max, greaterEqual);
|
||||||
|
|
||||||
|
m_sampleCount = 0;
|
||||||
|
m_sum = 0;
|
||||||
|
m_min = 0;
|
||||||
|
m_max = 0;
|
||||||
|
++m_currentTickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsQueue::pushToMinMaxQueue(std::deque<TimestampedStat>& queue, Stat stat, bool compare(Stat, Stat))
|
||||||
|
{
|
||||||
|
if (0 != m_sampleCount)
|
||||||
|
{
|
||||||
|
while (!queue.empty() && compare(stat, queue.back().stat))
|
||||||
|
{
|
||||||
|
queue.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!queue.empty() && m_currentTickCount - queue.front().tickCount >= HISTORY_SIZE)
|
||||||
|
{
|
||||||
|
queue.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != m_sampleCount)
|
||||||
|
{
|
||||||
|
queue.push_back({ m_currentTickCount, stat });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsQueue::setTickCount(TickCount tickCount)
|
||||||
|
{
|
||||||
|
if (tickCount - m_currentTickCount > HISTORY_SIZE)
|
||||||
|
{
|
||||||
|
m_currentTickCount = tickCount - HISTORY_SIZE;
|
||||||
|
resetTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_currentTickCount < tickCount)
|
||||||
|
{
|
||||||
|
push();
|
||||||
|
}
|
||||||
|
}
|
76
DDrawCompat/Overlay/StatsQueue.h
Normal file
76
DDrawCompat/Overlay/StatsQueue.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Common/Time.h>
|
||||||
|
|
||||||
|
class StatsQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint32_t TICKS_PER_SEC = 5;
|
||||||
|
static const uint32_t HISTORY_TIME = 3;
|
||||||
|
static const uint32_t HISTORY_SIZE = HISTORY_TIME * TICKS_PER_SEC;
|
||||||
|
|
||||||
|
typedef uint32_t SampleCount;
|
||||||
|
typedef uint64_t Stat;
|
||||||
|
typedef uint64_t TickCount;
|
||||||
|
|
||||||
|
struct Stats
|
||||||
|
{
|
||||||
|
double cur;
|
||||||
|
double avg;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
};
|
||||||
|
|
||||||
|
StatsQueue();
|
||||||
|
|
||||||
|
void addSample(TickCount tickCount, Stat stat);
|
||||||
|
Stats getStats(TickCount tickCount);
|
||||||
|
|
||||||
|
TickCount getCurrentTickCount() const { return m_currentTickCount; }
|
||||||
|
|
||||||
|
static long long getQpc(TickCount tickCount)
|
||||||
|
{
|
||||||
|
return tickCount * Time::g_qpcFrequency / TICKS_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TickCount getTickCount(long long qpc = Time::queryPerformanceCounter())
|
||||||
|
{
|
||||||
|
return qpc * TICKS_PER_SEC / Time::g_qpcFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual Stats getRawStats(TickCount tickCount);
|
||||||
|
SampleCount getSampleCount(TickCount tickCount) const;
|
||||||
|
void setTickCount(TickCount tickCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct TimestampedStat
|
||||||
|
{
|
||||||
|
TickCount tickCount;
|
||||||
|
Stat stat;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual double convert(double stat) { return stat; }
|
||||||
|
virtual void finalize(SampleCount& /*sampleCount*/, Stat& /*sum*/, Stat& /*min*/, Stat& /*max*/) {}
|
||||||
|
virtual void resetTickCount() {}
|
||||||
|
|
||||||
|
double getAvg(Stat sum, SampleCount sampleCount) const;
|
||||||
|
|
||||||
|
void push();
|
||||||
|
void pushToMinMaxQueue(std::deque<TimestampedStat>& queue, Stat stat, bool compare(Stat, Stat));
|
||||||
|
|
||||||
|
std::vector<Stat> m_sums;
|
||||||
|
std::vector<SampleCount> m_sampleCounts;
|
||||||
|
std::deque<TimestampedStat> m_minQueue;
|
||||||
|
std::deque<TimestampedStat> m_maxQueue;
|
||||||
|
TickCount m_currentTickCount;
|
||||||
|
SampleCount m_sampleCount;
|
||||||
|
Stat m_sum;
|
||||||
|
Stat m_min;
|
||||||
|
Stat m_max;
|
||||||
|
SampleCount m_totalSampleCount;
|
||||||
|
Stat m_totalSum;
|
||||||
|
};
|
52
DDrawCompat/Overlay/StatsTimer.cpp
Normal file
52
DDrawCompat/Overlay/StatsTimer.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <Overlay/StatsTimer.h>
|
||||||
|
|
||||||
|
StatsTimer::StatsTimer()
|
||||||
|
: m_qpcStart(0)
|
||||||
|
, m_qpcSum(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
double StatsTimer::convert(double stat)
|
||||||
|
{
|
||||||
|
return 100 * stat * StatsQueue::TICKS_PER_SEC / Time::g_qpcFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsTimer::finalize(SampleCount& sampleCount, Stat& sum, Stat& min, Stat& max)
|
||||||
|
{
|
||||||
|
if (0 != m_qpcStart)
|
||||||
|
{
|
||||||
|
auto qpcTickEnd = getQpc(getCurrentTickCount() + 1);
|
||||||
|
m_qpcSum += qpcTickEnd - m_qpcStart;
|
||||||
|
m_qpcStart = qpcTickEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleCount = 1;
|
||||||
|
sum = m_qpcSum;
|
||||||
|
min = m_qpcSum;
|
||||||
|
max = m_qpcSum;
|
||||||
|
m_qpcSum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsTimer::resetTickCount()
|
||||||
|
{
|
||||||
|
if (0 != m_qpcStart)
|
||||||
|
{
|
||||||
|
m_qpcStart = getQpc(getCurrentTickCount());
|
||||||
|
}
|
||||||
|
m_qpcSum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsTimer::start()
|
||||||
|
{
|
||||||
|
auto qpcStart = Time::queryPerformanceCounter();
|
||||||
|
setTickCount(getTickCount(qpcStart));
|
||||||
|
m_qpcStart = qpcStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsTimer::stop()
|
||||||
|
{
|
||||||
|
auto qpcEnd = Time::queryPerformanceCounter();
|
||||||
|
setTickCount(getTickCount(qpcEnd));
|
||||||
|
m_qpcSum += qpcEnd - m_qpcStart;
|
||||||
|
m_qpcStart = 0;
|
||||||
|
}
|
20
DDrawCompat/Overlay/StatsTimer.h
Normal file
20
DDrawCompat/Overlay/StatsTimer.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
|
||||||
|
class StatsTimer : public StatsQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsTimer();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual double convert(double stat) override;
|
||||||
|
virtual void finalize(SampleCount& sampleCount, Stat& sum, Stat& min, Stat& max) override;
|
||||||
|
virtual void resetTickCount() override;
|
||||||
|
|
||||||
|
long long m_qpcStart;
|
||||||
|
long long m_qpcSum;
|
||||||
|
};
|
122
DDrawCompat/Overlay/StatsWindow.cpp
Normal file
122
DDrawCompat/Overlay/StatsWindow.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <Common/Time.h>
|
||||||
|
#include <Gdi/GuiThread.h>
|
||||||
|
#include <Input/Input.h>
|
||||||
|
#include <Overlay/ConfigWindow.h>
|
||||||
|
#include <Overlay/StatsWindow.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class UpdateStats
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UpdateStats(StatsQueue& statsQueue)
|
||||||
|
: m_statsQueue(statsQueue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<std::string, 4> operator()(StatsQueue::TickCount tickCount) const
|
||||||
|
{
|
||||||
|
auto stats = m_statsQueue.getStats(tickCount);
|
||||||
|
return { toString(stats.cur), toString(stats.avg), toString(stats.min), toString(stats.max) };
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string toString(double stat) const
|
||||||
|
{
|
||||||
|
if (std::isnan(stat))
|
||||||
|
{
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char unitLetter[] = { 0, 'k', 'm', 'b' };
|
||||||
|
std::size_t unitIndex = 0;
|
||||||
|
while (stat >= 1000 && unitIndex + 1 < sizeof(unitLetter))
|
||||||
|
{
|
||||||
|
++unitIndex;
|
||||||
|
stat /= 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[20] = {};
|
||||||
|
if (0 == unitIndex)
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), "%.0f", stat);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto len = snprintf(buf, sizeof(buf), "%.2f", stat);
|
||||||
|
const auto decimalPoint = strchr(buf, '.');
|
||||||
|
const auto intLen = decimalPoint ? decimalPoint - buf : len;
|
||||||
|
if (len > 4)
|
||||||
|
{
|
||||||
|
len = intLen >= 3 ? intLen : 4;
|
||||||
|
}
|
||||||
|
buf[len] = unitLetter[unitIndex];
|
||||||
|
buf[len + 1] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsQueue& m_statsQueue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Overlay
|
||||||
|
{
|
||||||
|
StatsWindow::StatsWindow()
|
||||||
|
: Window(nullptr, { 0, 0, StatsControl::NAME_LABEL_WIDTH + 4 * StatsControl::VALUE_LABEL_WIDTH, 105 + BORDER },
|
||||||
|
0, Input::parseHotKey("shift+f12"))
|
||||||
|
{
|
||||||
|
addControl("", [](StatsQueue::TickCount) { return std::array<std::string, 4>{ "cur", "avg", "min", "max" }; },
|
||||||
|
WS_VISIBLE | WS_DISABLED).update(0);
|
||||||
|
addControl("Present rate", UpdateStats(m_present.m_rate));
|
||||||
|
addControl("Flip rate", UpdateStats(m_flip.m_rate));
|
||||||
|
addControl("Blit count", UpdateStats(m_blit.m_count));
|
||||||
|
addControl("Lock count", UpdateStats(m_lock.m_count));
|
||||||
|
addControl("DDI usage", UpdateStats(m_ddiUsage));
|
||||||
|
addControl("GDI objects", UpdateStats(m_gdiObjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsControl& StatsWindow::addControl(const std::string& name, StatsControl::UpdateFunc updateFunc, DWORD style)
|
||||||
|
{
|
||||||
|
const int index = m_statsControls.size();
|
||||||
|
const int rowHeight = 15;
|
||||||
|
|
||||||
|
RECT rect = { 0, index * rowHeight + BORDER / 2, m_rect.right, (index + 1) * rowHeight + BORDER / 2 };
|
||||||
|
return m_statsControls.emplace_back(*this, rect, name, updateFunc, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT StatsWindow::calculateRect(const RECT& monitorRect) const
|
||||||
|
{
|
||||||
|
RECT r = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top };
|
||||||
|
OffsetRect(&r, monitorRect.left + monitorRect.right - r.right, monitorRect.top);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND StatsWindow::getTopmost() const
|
||||||
|
{
|
||||||
|
auto configWindow = Gdi::GuiThread::getConfigWindow();
|
||||||
|
return (configWindow && configWindow->isVisible()) ? configWindow->getWindow() : Window::getTopmost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWindow::updateStats()
|
||||||
|
{
|
||||||
|
static auto prevTickCount = StatsQueue::getTickCount() - 1;
|
||||||
|
m_tickCount = StatsQueue::getTickCount();
|
||||||
|
if (m_tickCount == prevTickCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_gdiObjects.addSample(m_tickCount, GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS));
|
||||||
|
for (auto& statsControl : m_statsControls)
|
||||||
|
{
|
||||||
|
if (statsControl.isEnabled())
|
||||||
|
{
|
||||||
|
statsControl.update(m_tickCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevTickCount = m_tickCount;
|
||||||
|
}
|
||||||
|
}
|
38
DDrawCompat/Overlay/StatsWindow.h
Normal file
38
DDrawCompat/Overlay/StatsWindow.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <Overlay/StatsControl.h>
|
||||||
|
#include <Overlay/StatsEventGroup.h>
|
||||||
|
#include <Overlay/StatsQueue.h>
|
||||||
|
#include <Overlay/StatsTimer.h>
|
||||||
|
#include <Overlay/Window.h>
|
||||||
|
|
||||||
|
namespace Overlay
|
||||||
|
{
|
||||||
|
class StatsWindow : public Window
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatsWindow();
|
||||||
|
|
||||||
|
void updateStats();
|
||||||
|
|
||||||
|
StatsEventGroup m_present;
|
||||||
|
StatsEventGroup m_flip;
|
||||||
|
StatsEventGroup m_blit;
|
||||||
|
StatsEventGroup m_lock;
|
||||||
|
StatsTimer m_ddiUsage;
|
||||||
|
StatsQueue m_gdiObjects;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StatsControl& addControl(const std::string& name, StatsControl::UpdateFunc updateFunc, DWORD style = WS_VISIBLE);
|
||||||
|
|
||||||
|
virtual RECT calculateRect(const RECT& monitorRect) const override;
|
||||||
|
virtual HWND getTopmost() const override;
|
||||||
|
|
||||||
|
std::list<StatsControl> m_statsControls;
|
||||||
|
uint64_t m_tickCount;
|
||||||
|
};
|
||||||
|
}
|
@ -45,8 +45,8 @@ namespace
|
|||||||
|
|
||||||
namespace Overlay
|
namespace Overlay
|
||||||
{
|
{
|
||||||
Window::Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey)
|
Window::Window(Window* parentWindow, const RECT& rect, DWORD style, const Input::HotKey& hotKey)
|
||||||
: Control(nullptr, rect, WS_BORDER)
|
: Control(nullptr, rect, style)
|
||||||
, m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr))
|
, m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr))
|
||||||
, m_parentWindow(parentWindow)
|
, m_parentWindow(parentWindow)
|
||||||
, m_transparency(25)
|
, m_transparency(25)
|
||||||
@ -99,6 +99,11 @@ namespace Overlay
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HWND Window::getTopmost() const
|
||||||
|
{
|
||||||
|
return DDraw::RealPrimarySurface::getTopmost();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::invalidate()
|
void Window::invalidate()
|
||||||
{
|
{
|
||||||
m_invalid = true;
|
m_invalid = true;
|
||||||
@ -122,7 +127,6 @@ namespace Overlay
|
|||||||
if (m_style & WS_VISIBLE)
|
if (m_style & WS_VISIBLE)
|
||||||
{
|
{
|
||||||
updatePos();
|
updatePos();
|
||||||
Input::setCapture(this);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -132,8 +136,8 @@ namespace Overlay
|
|||||||
capture->setVisible(false);
|
capture->setVisible(false);
|
||||||
}
|
}
|
||||||
ShowWindow(m_hwnd, SW_HIDE);
|
ShowWindow(m_hwnd, SW_HIDE);
|
||||||
Input::setCapture(m_parentWindow);
|
|
||||||
}
|
}
|
||||||
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK Window::staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK Window::staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
@ -213,7 +217,7 @@ namespace Overlay
|
|||||||
m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor,
|
m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor,
|
||||||
monitorRect.right / m_scaleFactor, monitorRect.bottom / m_scaleFactor });
|
monitorRect.right / m_scaleFactor, monitorRect.bottom / m_scaleFactor });
|
||||||
|
|
||||||
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, DDraw::RealPrimarySurface::getTopmost(),
|
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(),
|
||||||
m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
|
m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
|
||||||
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor,
|
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor,
|
||||||
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
|
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
|
||||||
|
@ -13,7 +13,7 @@ namespace Overlay
|
|||||||
class Window : public Control
|
class Window : public Control
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey = {});
|
Window(Window* parentWindow, const RECT& rect, DWORD style, const Input::HotKey& hotKey = {});
|
||||||
virtual ~Window() override;
|
virtual ~Window() override;
|
||||||
|
|
||||||
virtual RECT calculateRect(const RECT& monitorRect) const = 0;
|
virtual RECT calculateRect(const RECT& monitorRect) const = 0;
|
||||||
@ -30,6 +30,8 @@ namespace Overlay
|
|||||||
Window* m_parentWindow;
|
Window* m_parentWindow;
|
||||||
int m_transparency;
|
int m_transparency;
|
||||||
|
|
||||||
|
virtual HWND getTopmost() const;
|
||||||
|
|
||||||
void updatePos();
|
void updatePos();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user