From 8cefcaa94cd02c3bd6d735b620c1e7797597c204 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 4 Oct 2012 05:41:02 +0200 Subject: [PATCH] Implement a simple benchmarking mode which logs FPS to a file Very useful to compare performance between two builds, check the impact of a configuration option, etc. FPS log is stored in User/Logs/fps.txt and is reset each time you launch a game. Only enabled if you check the "Log FPS to file" option in your graphics settings. Could be improved a bit: currently logs only every 1s (so you can't really see small variations), maybe output more infos to the fps.txt like average/stddev (but Excel/Libreoffice/Google Docs can compute that easily too). --- Source/Core/DolphinWX/Src/VideoConfigDiag.cpp | 2 + Source/Core/VideoCommon/CMakeLists.txt | 1 + Source/Core/VideoCommon/Src/FPSCounter.cpp | 64 +++++++++++++++++++ Source/Core/VideoCommon/Src/FPSCounter.h | 28 ++++++++ Source/Core/VideoCommon/Src/VideoConfig.cpp | 2 + Source/Core/VideoCommon/Src/VideoConfig.h | 1 + Source/Core/VideoCommon/VideoCommon.vcxproj | 2 + .../VideoCommon/VideoCommon.vcxproj.filters | 6 ++ .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 13 ++-- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 19 ++---- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 17 ++--- 11 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 Source/Core/VideoCommon/Src/FPSCounter.cpp create mode 100644 Source/Core/VideoCommon/Src/FPSCounter.h diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp index f5a488a7e8..20bd4dfb38 100644 --- a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp @@ -98,6 +98,7 @@ wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf un wxString disable_fog_desc = wxTRANSLATE("Improves performance but causes glitches in most games which rely on proper fog emulation.\n\nIf unsure, leave this unchecked."); wxString disable_alphapass_desc = wxTRANSLATE("Skip the destination alpha pass used in many games for various graphical effects.\n\nIf unsure, leave this unchecked."); wxString show_fps_desc = wxTRANSLATE("Show the number of frames rendered per second as a measure of emulation speed.\n\nIf unsure, leave this unchecked."); +wxString log_fps_to_file_desc = wxTRANSLATE("Log the number of frames rendered per second to User/Logs/fps.txt. Use this feature when you want to measure the performance of Dolphin.\n\nIf unsure, leave this unchecked."); wxString show_input_display_desc = wxTRANSLATE("Display the inputs read by the emulator.\n\nIf unsure, leave this unchecked."); wxString show_stats_desc = wxTRANSLATE("Show various statistics.\n\nIf unsure, leave this unchecked."); wxString texfmt_desc = wxTRANSLATE("Modify textures to show the format they're encoded in. Needs an emulation reset in most cases.\n\nIf unsure, leave this unchecked."); @@ -296,6 +297,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con { SettingCheckBox* render_to_main_cb; szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc), vconfig.bShowFPS)); + szr_other->Add(CreateCheckBox(page_general, _("Log FPS to file"), wxGetTranslation(log_fps_to_file_desc), vconfig.bLogFPSToFile)); szr_other->Add(CreateCheckBox(page_general, _("Auto adjust Window Size"), wxGetTranslation(auto_window_size_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderWindowAutoSize)); szr_other->Add(CreateCheckBox(page_general, _("Keep window on top"), wxGetTranslation(keep_window_on_top_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bKeepWindowOnTop)); szr_other->Add(CreateCheckBox(page_general, _("Hide Mouse Cursor"), wxGetTranslation(hide_mouse_cursor_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)); diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index d0e28f571c..6ed8e29c6b 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRCS Src/BPFunctions.cpp Src/DLCache.cpp Src/Debugger.cpp Src/Fifo.cpp + Src/FPSCounter.cpp Src/FramebufferManagerBase.cpp Src/HiresTextures.cpp Src/ImageWrite.cpp diff --git a/Source/Core/VideoCommon/Src/FPSCounter.cpp b/Source/Core/VideoCommon/Src/FPSCounter.cpp new file mode 100644 index 0000000000..ea3f624c73 --- /dev/null +++ b/Source/Core/VideoCommon/Src/FPSCounter.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "FPSCounter.h" +#include "FileUtil.h" +#include "Timer.h" +#include "VideoConfig.h" + +#define FPS_REFRESH_INTERVAL 1000 + +static unsigned int s_counter = 0; +static unsigned int s_fps = 0; +static unsigned int s_fps_last_counter = 0; +static unsigned long s_last_update_time = 0; +static File::IOFile s_bench_file; + +void InitFPSCounter() +{ + s_counter = s_fps_last_counter = 0; + s_fps = 0; + s_last_update_time = Common::Timer::GetTimeMs(); + + if (s_bench_file.IsOpen()) + s_bench_file.Close(); +} + +static void LogFPSToFile(unsigned long val) +{ + if (!s_bench_file.IsOpen()) + s_bench_file.Open(File::GetUserPath(D_LOGS_IDX) + "fps.txt", "w"); + + char buffer[256]; + snprintf(buffer, 256, "%ld\n", val); + s_bench_file.WriteArray(buffer, strlen(buffer)); +} + +int UpdateFPSCounter() +{ + if (Common::Timer::GetTimeMs() - s_last_update_time >= FPS_REFRESH_INTERVAL) + { + s_last_update_time = Common::Timer::GetTimeMs(); + s_fps = s_counter - s_fps_last_counter; + s_fps_last_counter = s_counter; + if (g_ActiveConfig.bLogFPSToFile) + LogFPSToFile(s_fps); + } + + s_counter++; + return s_fps; +} \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/FPSCounter.h b/Source/Core/VideoCommon/Src/FPSCounter.h new file mode 100644 index 0000000000..314f4b0fc7 --- /dev/null +++ b/Source/Core/VideoCommon/Src/FPSCounter.h @@ -0,0 +1,28 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _FPS_COUNTER_H_ +#define _FPS_COUNTER_H_ + +// Initializes the FPS counter. +void InitFPSCounter(); + +// Called when a frame is rendered. Returns the value to be displayed on +// screen as the FPS counter (updated every second). +int UpdateFPSCounter(); + +#endif // _FPS_COUNTER_H_ \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index c5628c19a1..6d240ba357 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -59,6 +59,7 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0); iniFile.Get("Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples,128); iniFile.Get("Settings", "ShowFPS", &bShowFPS, false); // Settings + iniFile.Get("Settings", "LogFPSToFile", &bLogFPSToFile, false); iniFile.Get("Settings", "ShowInputDisplay", &bShowInputDisplay, false); iniFile.Get("Settings", "OverlayStats", &bOverlayStats, false); iniFile.Get("Settings", "OverlayProjStats", &bOverlayProjStats, false); @@ -186,6 +187,7 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "UseRealXFB", bUseRealXFB); iniFile.Set("Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples); iniFile.Set("Settings", "ShowFPS", bShowFPS); + iniFile.Set("Settings", "LogFPSToFile", bLogFPSToFile); iniFile.Set("Settings", "ShowInputDisplay", bShowInputDisplay); iniFile.Set("Settings", "OverlayStats", bOverlayStats); iniFile.Set("Settings", "OverlayProjStats", bOverlayProjStats); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 7653972ec8..e71c7356a9 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -97,6 +97,7 @@ struct VideoConfig bool bTexFmtOverlayEnable; bool bTexFmtOverlayCenter; bool bShowEFBCopyRegions; + bool bLogFPSToFile; // Render bool bWireFrame; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index f53c18cb37..0869f33ff4 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -183,6 +183,7 @@ + @@ -228,6 +229,7 @@ + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index c933fbc939..e7019f17ed 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -119,6 +119,9 @@ Shader Generators + + Util + @@ -246,6 +249,9 @@ Shader Generators + + Util + diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 1b7cfb25bb..81efa3623f 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -44,6 +44,7 @@ #include "Host.h" #include "BPFunctions.h" #include "AVIDump.h" +#include "FPSCounter.h" namespace DX11 { @@ -338,6 +339,8 @@ Renderer::Renderer() int x, y, w_temp, h_temp; s_blendMode = 0; + InitFPSCounter(); + Host_GetRenderWindowSize(x, y, w_temp, h_temp); D3D::Create(EmuWindow::GetWnd()); @@ -1143,16 +1146,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons } // update FPS counter - static int fpscount = 0; - static unsigned long lasttime = 0; - if (Common::Timer::GetTimeMs() - lasttime >= 1000) - { - lasttime = Common::Timer::GetTimeMs(); - s_fps = fpscount; - fpscount = 0; - } if (XFBWrited) - ++fpscount; + s_fps = UpdateFPSCounter(); // Begin new frame // Set default viewport and scissor, for the clear to work correctly diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index fda9a02d25..45030c48df 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -54,6 +54,7 @@ #include "Core.h" #include "Movie.h" #include "BPFunctions.h" +#include "FPSCounter.h" namespace DX9 { @@ -247,6 +248,8 @@ void TeardownDeviceObjects() // Init functions Renderer::Renderer() { + InitFPSCounter(); + st = new char[32768]; int fullScreenRes, x, y, w_temp, h_temp; @@ -1107,7 +1110,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons OSD::DrawMessages(); D3D::EndFrame(); - frameCount++; + ++frameCount; GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true); @@ -1168,20 +1171,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); } - // Place messages on the picture, then copy it to the screen - // --------------------------------------------------------------------- - // Count FPS. - // ------------- - static int fpscount = 0; - static unsigned long lasttime = 0; - if (Common::Timer::GetTimeMs() - lasttime >= 1000) - { - lasttime = Common::Timer::GetTimeMs(); - s_fps = fpscount; - fpscount = 0; - } if (XFBWrited) - ++fpscount; + s_fps = UpdateFPSCounter(); // Begin new frame // Set default viewport and scissor, for the clear to work correctly diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 19e4002b7e..a6121e1436 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -61,6 +61,7 @@ #include "Movie.h" #include "Host.h" #include "BPFunctions.h" +#include "FPSCounter.h" #include "main.h" // Local #ifdef _WIN32 @@ -251,6 +252,8 @@ Renderer::Renderer() s_fps=0; s_blendMode = 0; + InitFPSCounter(); + #if defined HAVE_CG && HAVE_CG g_cgcontext = cgCreateContext(); cgGetError(); @@ -1330,20 +1333,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons } } - // Place messages on the picture, then copy it to the screen - // --------------------------------------------------------------------- - // Count FPS. - // ------------- - static int fpscount = 0; - static unsigned long lasttime = 0; - if (Common::Timer::GetTimeMs() - lasttime >= 1000) - { - lasttime = Common::Timer::GetTimeMs(); - s_fps = fpscount; - fpscount = 0; - } if (XFBWrited) - ++fpscount; + s_fps = UpdateFPSCounter(); // --------------------------------------------------------------------- GL_REPORT_ERRORD();