diff options
Diffstat (limited to 'dxvk-mangohud.patch')
-rw-r--r-- | dxvk-mangohud.patch | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/dxvk-mangohud.patch b/dxvk-mangohud.patch new file mode 100644 index 000000000000..13fbdee8db9a --- /dev/null +++ b/dxvk-mangohud.patch @@ -0,0 +1,665 @@ +diff --git a/README.md b/README.md +index 25d03230..e8a53432 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,29 @@ ++# MangoHud Specific ++ ++- `DXVK_HUD_OFFSET_X` Set X offset of the DVXK Hud. ++- `DXVK_HUD_OFFSET_Y` Set Y offset of the DVXK Hud. ++- `DXVK_LOG_TO_FILE` Turn on logging and select path/filename (Fps,Cpu load,Gpu load) ++- Logging Gpu load requires either mangogpuload or gpuload hud options ++ ++# Hud options ++- `mangogpuload` : Shows current gpu load. ++- `mangocpuload` : Shows current cpu load. ++ ++# Keybinds ++- `F2` : Toggle Logging on/off ++- `F12` : Toggle Hud on/off ++ ++# MangoLog file ++ ++ When you press F2, a file is created with your chosen name + date/time stamp. ++ this file can be uploaded to https://flightlessmango.com/logs/new to create graphs automatically. ++ you can share the created page with others, just link it. ++ ++ #### Multiple log files ++ ++ It's possible to upload multiple files, you can rename them to your preferred names and upload them in a batch. ++ The graphs will then use those names in the data. ++ + # DXVK + + A Vulkan-based translation layer for Direct3D 10/11 which allows running 3D applications on Linux using Wine. +diff --git a/src/dxvk/dxvk_cpu.h b/src/dxvk/dxvk_cpu.h +new file mode 100644 +index 00000000..b2c8736a +--- /dev/null ++++ b/src/dxvk/dxvk_cpu.h +@@ -0,0 +1,172 @@ ++#include <cmath> ++#include <iomanip> ++#include <array> ++#include <vector> ++#include <algorithm> ++#include <iterator> ++#include <thread> ++#include <sstream> ++#include <fstream> ++using namespace std; ++ ++const int NUM_CPU_STATES = 10; ++ ++struct Cpus{ ++ size_t num; ++ string name; ++ float value; ++ string output; ++}; ++ ++size_t numCpuCores = dxvk::thread::hardware_concurrency(); ++size_t arraySize = numCpuCores + 1; ++std::vector<Cpus> cpuArray; ++ ++void coreCounting(){ ++ cpuArray.push_back({0, "CPU:"}); ++ for (size_t i = 0; i < arraySize; i++) { ++ size_t offset = i; ++ stringstream ss; ++ ss << "CPU" << offset << ":"; ++ string cpuNameString = ss.str(); ++ cpuArray.push_back({i+1 , cpuNameString}); ++ } ++} ++ ++std::string m_cpuUtilizationString; ++ ++enum CPUStates ++{ ++ S_USER = 0, ++ S_NICE, ++ S_SYSTEM, ++ S_IDLE, ++ S_IOWAIT, ++ S_IRQ, ++ S_SOFTIRQ, ++ S_STEAL, ++ S_GUEST, ++ S_GUEST_NICE ++}; ++ ++typedef struct CPUData ++{ ++ std::string cpu; ++ size_t times[NUM_CPU_STATES]; ++} CPUData; ++ ++void ReadStatsCPU(std::vector<CPUData> & entries) ++{ ++ std::ifstream fileStat("/proc/stat"); ++ ++ std::string line; ++ ++ const std::string STR_CPU("cpu"); ++ const std::size_t LEN_STR_CPU = STR_CPU.size(); ++ const std::string STR_TOT("tot"); ++ ++ while(std::getline(fileStat, line)) ++ { ++ // cpu stats line found ++ if(!line.compare(0, LEN_STR_CPU, STR_CPU)) ++ { ++ std::istringstream ss(line); ++ ++ // store entry ++ entries.emplace_back(CPUData()); ++ CPUData & entry = entries.back(); ++ ++ // read cpu label ++ ss >> entry.cpu; ++ ++ if(entry.cpu.size() > LEN_STR_CPU) ++ entry.cpu.erase(0, LEN_STR_CPU); ++ else ++ entry.cpu = STR_TOT; ++ ++ // read times ++ for(int i = 0; i < NUM_CPU_STATES; ++i) ++ ss >> entry.times[i]; ++ } ++ } ++} ++ ++size_t GetIdleTime(const CPUData & e) ++{ ++ return e.times[S_IDLE] + ++ e.times[S_IOWAIT]; ++} ++ ++size_t GetActiveTime(const CPUData & e) ++{ ++ return e.times[S_USER] + ++ e.times[S_NICE] + ++ e.times[S_SYSTEM] + ++ e.times[S_IRQ] + ++ e.times[S_SOFTIRQ] + ++ e.times[S_STEAL] + ++ e.times[S_GUEST] + ++ e.times[S_GUEST_NICE]; ++} ++ ++void PrintStats(const std::vector<CPUData> & entries1, const std::vector<CPUData> & entries2) ++{ ++ const size_t NUM_ENTRIES = entries1.size(); ++ ++ for(size_t i = 0; i < NUM_ENTRIES; ++i) ++ { ++ const CPUData & e1 = entries1[i]; ++ const CPUData & e2 = entries2[i]; ++ ++ const float ACTIVE_TIME = static_cast<float>(GetActiveTime(e2) - GetActiveTime(e1)); ++ const float IDLE_TIME = static_cast<float>(GetIdleTime(e2) - GetIdleTime(e1)); ++ const float TOTAL_TIME = ACTIVE_TIME + IDLE_TIME; ++ ++ cpuArray[i].value = (truncf(100.f * ACTIVE_TIME / TOTAL_TIME) * 10 / 10); ++ } ++} ++ ++int getCpuUsage() ++{ ++ std::vector<CPUData> entries1; ++ std::vector<CPUData> entries2; ++ ++ // snapshot 1 ++ ReadStatsCPU(entries1); ++ ++ // 100ms pause ++ std::this_thread::sleep_for(std::chrono::milliseconds(100)); ++ ++ // snapshot 2 ++ ReadStatsCPU(entries2); ++ ++ // print output ++ PrintStats(entries1, entries2); ++ ++ return 0; ++} ++ ++ ++void updateCpuStrings(){ ++ for (size_t i = 0; i < arraySize; i++) { ++ size_t spacing = 10; ++ string value = to_string(cpuArray[i].value); ++ value.erase( value.find_last_not_of('0') + 1, std::string::npos ); ++ size_t correctionValue = (spacing - cpuArray[i].name.length()) - value.length(); ++ string correction = ""; ++ for (size_t i = 0; i < correctionValue; i++) { ++ correction.append(" "); ++ } ++ stringstream ss; ++ if (i < 11) { ++ if (i == 0) { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } else { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } ++ } else { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } ++ cpuArray[i].output = ss.str(); ++ } ++ } +\ No newline at end of file +diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp +index 4fcd3bd2..b6e23c4c 100644 +--- a/src/dxvk/hud/dxvk_hud.cpp ++++ b/src/dxvk/hud/dxvk_hud.cpp +@@ -1,9 +1,13 @@ +-#include <cstring> + #include <version.h> +- + #include "dxvk_hud.h" ++#include <windows.h> ++#include <time.h> + + namespace dxvk::hud { ++ float Hud::offset_x_float = 0; ++ float Hud::offset_y_float = 0; ++ bool show_hud = true; ++ int lastPress; + + Hud::Hud( + const Rc<DxvkDevice>& device, +@@ -60,6 +64,14 @@ namespace dxvk::hud { + + Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) { + std::string hudElements = env::getEnvVar("DXVK_HUD"); ++ std::string offset_x = env::getEnvVar("DXVK_HUD_OFFSET_X"); ++ std::string offset_y = env::getEnvVar("DXVK_HUD_OFFSET_Y"); ++ ++ if (!offset_x.empty()) ++ offset_x_float = stof(offset_x); ++ ++ if (!offset_y.empty()) ++ offset_y_float = stof(offset_y); + + if (hudElements.empty()) + hudElements = device->config().hud; +@@ -82,33 +94,45 @@ namespace dxvk::hud { + m_renderer.beginFrame(ctx, m_uniformData.surfaceSize); + } + +- + void Hud::renderHudElements(const Rc<DxvkContext>& ctx) { +- HudPos position = { 8.0f, 24.0f }; ++ if(GetAsyncKeyState(VK_F12) & 0x8000) ++ { ++ if (GetTickCount() - lastPress > 500){ ++ lastPress = GetTickCount(); ++ if (show_hud){ ++ show_hud = false; ++ } else { ++ show_hud = true; ++ } ++ } ++ } + +- if (m_config.elements.test(HudElement::DxvkVersion)) { +- m_renderer.drawText(ctx, 16.0f, +- { position.x, position.y }, +- { 1.0f, 1.0f, 1.0f, 1.0f }, +- "DXVK " DXVK_VERSION); +- position.y += 24.0f; +- } +- +- if (m_config.elements.test(HudElement::DxvkClientApi)) { +- m_renderer.drawText(ctx, 16.0f, +- { position.x, position.y }, +- { 1.0f, 1.0f, 1.0f, 1.0f }, +- m_device->clientApi()); +- position.y += 24.0f; +- } +- +- if (m_config.elements.test(HudElement::DeviceInfo)) { +- position = m_hudDeviceInfo.render( +- ctx, m_renderer, position); +- } ++ HudPos position = { offset_x_float + 8.0f, offset_y_float + 24.0f }; + +- position = m_hudFramerate.render(ctx, m_renderer, position); +- position = m_hudStats .render(ctx, m_renderer, position); ++ if (show_hud){ ++ if (m_config.elements.test(HudElement::DxvkVersion)) { ++ m_renderer.drawText(ctx, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ "DXVK " DXVK_VERSION); ++ position.y += 24.0f; ++ } ++ ++ if (m_config.elements.test(HudElement::DxvkClientApi)) { ++ m_renderer.drawText(ctx, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_device->clientApi()); ++ position.y += 24.0f; ++ } ++ ++ if (m_config.elements.test(HudElement::DeviceInfo)) { ++ position = m_hudDeviceInfo.render( ++ ctx, m_renderer, position); ++ } ++ position = m_hudFramerate.render(ctx, m_renderer, position); ++ position = m_hudStats .render(ctx, m_renderer, position); ++ } + } + + +diff --git a/src/dxvk/hud/dxvk_hud.h b/src/dxvk/hud/dxvk_hud.h +index 3b702c3b..71779977 100644 +--- a/src/dxvk/hud/dxvk_hud.h ++++ b/src/dxvk/hud/dxvk_hud.h +@@ -29,6 +29,8 @@ namespace dxvk::hud { + class Hud : public RcObject { + + public: ++ static float offset_x_float; ++ static float offset_y_float; + + Hud( + const Rc<DxvkDevice>& device, +diff --git a/src/dxvk/hud/dxvk_hud_config.cpp b/src/dxvk/hud/dxvk_hud_config.cpp +index fe1745bd..020a394b 100644 +--- a/src/dxvk/hud/dxvk_hud_config.cpp ++++ b/src/dxvk/hud/dxvk_hud_config.cpp +@@ -16,6 +16,9 @@ namespace dxvk::hud { + { "version", HudElement::DxvkVersion }, + { "api", HudElement::DxvkClientApi }, + { "compiler", HudElement::CompilerActivity }, ++ { "mangogpuload", HudElement::GpuLoad }, ++ { "mangocpuload", HudElement::CpuLoad }, ++ { "mangocpuload", HudElement::Logging }, + }}; + + +diff --git a/src/dxvk/hud/dxvk_hud_config.h b/src/dxvk/hud/dxvk_hud_config.h +index 05a1e4b6..5d571663 100644 +--- a/src/dxvk/hud/dxvk_hud_config.h ++++ b/src/dxvk/hud/dxvk_hud_config.h +@@ -22,6 +22,9 @@ namespace dxvk::hud { + DxvkVersion = 8, + DxvkClientApi = 9, + CompilerActivity = 10, ++ GpuLoad = 11, ++ CpuLoad = 12, ++ Logging = 13, + }; + + using HudElements = Flags<HudElement>; +diff --git a/src/dxvk/hud/dxvk_hud_fps.cpp b/src/dxvk/hud/dxvk_hud_fps.cpp +index f8cb6e7d..84eb2db6 100644 +--- a/src/dxvk/hud/dxvk_hud_fps.cpp ++++ b/src/dxvk/hud/dxvk_hud_fps.cpp +@@ -1,7 +1,22 @@ + #include "dxvk_hud_fps.h" ++#include "dxvk_hud_stats.h" ++#include "../dxvk_cpu.h" ++#include <time.h> + + #include <cmath> + #include <iomanip> ++using namespace std; ++time_t now_log = time(0); ++tm *log_time = localtime(&now_log); ++fstream f; ++ ++struct logData{ ++ float fps; ++ float cpu; ++ uint64_t gpu; ++}; ++ ++std::vector<logData> logArray; + + namespace dxvk::hud { + +@@ -9,8 +24,8 @@ namespace dxvk::hud { + : m_elements (elements), + m_fpsString ("FPS: "), + m_prevFpsUpdate(Clock::now()), +- m_prevFtgUpdate(Clock::now()) { +- ++ m_prevFtgUpdate(Clock::now()), ++ m_prevLogUpdate(Clock::now()) { + } + + +@@ -25,11 +40,48 @@ namespace dxvk::hud { + TimePoint now = Clock::now(); + TimeDiff elapsedFps = std::chrono::duration_cast<TimeDiff>(now - m_prevFpsUpdate); + TimeDiff elapsedFtg = std::chrono::duration_cast<TimeDiff>(now - m_prevFtgUpdate); ++ TimeDiff elapsedLog = std::chrono::duration_cast<TimeDiff>(now - m_prevLogUpdate); + m_prevFtgUpdate = now; ++ ++ if(GetAsyncKeyState(VK_F2) & 0x8000) ++ { ++ elapsedF2 = std::chrono::duration_cast<TimeDiff>(now - m_prevF2Press); ++ if (elapsedF2.count() > UpdateInterval || elapsedF2.count() == 0) { ++ if (mango_logging){ ++ m_prevF2Press = now; ++ mango_logging = false; ++ for (size_t i = 0; i < logArray.size(); i++) { ++ f << logArray[i].fps << "," << logArray[i].cpu << "," << logArray[i].gpu << endl; ++ } ++ f.close(); ++ logArray.clear(); ++ } else { ++ m_prevF2Press = now; ++ now_log = time(0); ++ log_time = localtime(&now_log); ++ mango_logging = true; ++ string date = to_string(log_time->tm_year + 1900) + "-" + to_string(1 + log_time->tm_mon) + "-" + to_string(log_time->tm_mday) + "_" + to_string(1 + log_time->tm_hour) + "-" + to_string(1 + log_time->tm_min) + "-" + to_string(1 + log_time->tm_sec); ++ f.open(logging + "_" + date, f.out | f.app); ++ } ++ } ++ } ++ ++ if (elapsedLog.count() >= LogUpdateInterval) { ++ fps = (10'000'000ll * m_frameCount) / elapsedFps.count(); ++ if (!logging.empty()){ ++ if (mango_logging){ ++ logArray.push_back({float(fps / 10 + (float(fps % 10) / 10)), cpuArray[0].value, gpuLoad}); ++ } ++ } ++ m_prevLogUpdate = now; ++ } + +- // Update FPS string + if (elapsedFps.count() >= UpdateInterval) { +- const int64_t fps = (10'000'000ll * m_frameCount) / elapsedFps.count(); ++ // Update FPS string ++ coreCounting(); ++ dxvk::thread([this] () { getCpuUsage();}); ++ updateCpuStrings(); ++ m_cpuUtilizationString = str::format(cpuArray[0].output); + m_fpsString = str::format("FPS: ", fps / 10, ".", fps % 10); + + m_prevFpsUpdate = now; +@@ -46,32 +98,81 @@ namespace dxvk::hud { + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position) { ++ if (m_elements.test(HudElement::GpuLoad)) { ++ position = this->renderGpuText( ++ context, renderer, position); ++ } ++ if (m_elements.test(HudElement::CpuLoad)) { ++ position = this->renderCpuText( ++ context, renderer, position); ++ } + if (m_elements.test(HudElement::Framerate)) { + position = this->renderFpsText( + context, renderer, position); +- } ++ } + + if (m_elements.test(HudElement::Frametimes)) { + position = this->renderFrametimeGraph( + context, renderer, position); + } + ++ if (mango_logging && !logging.empty()) { ++ this->renderLogging(context, renderer, ++ { float(renderer.surfaceSize().width) - 250.0f, float(renderer.surfaceSize().height) - 20.0f }); ++ } ++ + return position; + } + + +- HudPos HudFps::renderFpsText( +- const Rc<DxvkContext>& context, +- HudRenderer& renderer, +- HudPos position) { ++ ++ HudPos HudFps::renderGpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++ renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_gpuLoadString); ++ ++ return HudPos { position.x, position.y + 24 }; ++} ++ ++HudPos HudFps::renderCpuText( ++const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_cpuUtilizationString); ++ ++return HudPos { position.x, position.y + 24 }; ++} ++ ++HudPos HudFps::renderFpsText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { + renderer.drawText(context, 16.0f, + { position.x, position.y }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + m_fpsString); ++ ++ return HudPos { position.x, position.y + 24 }; ++ } + +- return HudPos { position.x, position.y + 24 }; +- } +- ++ HudPos HudFps::renderLogging( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++ renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ "Currently Logging..."); ++ ++ return HudPos { position.x, position.y}; ++ } + + HudPos HudFps::renderFrametimeGraph( + const Rc<DxvkContext>& context, +diff --git a/src/dxvk/hud/dxvk_hud_fps.h b/src/dxvk/hud/dxvk_hud_fps.h +index c8c4b984..b1476889 100644 +--- a/src/dxvk/hud/dxvk_hud_fps.h ++++ b/src/dxvk/hud/dxvk_hud_fps.h +@@ -17,8 +17,9 @@ namespace dxvk::hud { + using TimeDiff = std::chrono::microseconds; + using TimePoint = typename Clock::time_point; + +- constexpr static uint32_t NumDataPoints = 300; +- constexpr static int64_t UpdateInterval = 500'000; ++ constexpr static uint32_t NumDataPoints = 300; ++ constexpr static int64_t UpdateInterval = 500'000; ++ constexpr static int64_t LogUpdateInterval = 100'000; + public: + + HudFps(HudElements elements); +@@ -36,23 +37,46 @@ namespace dxvk::hud { + const HudElements m_elements; + + std::string m_fpsString; ++ bool mango_logging = false; ++ time_t lastPress = time(0); ++ std::string logging = env::getEnvVar("DXVK_LOG_TO_FILE"); ++ int64_t fps; + + TimePoint m_prevFpsUpdate; + TimePoint m_prevFtgUpdate; ++ TimePoint m_prevLogUpdate; ++ TimePoint m_prevF2Press; ++ TimeDiff elapsedF2; + int64_t m_frameCount = 0; + + std::array<float, NumDataPoints> m_dataPoints = {}; + uint32_t m_dataPointId = 0; ++ ++ HudPos renderGpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); ++ ++ HudPos renderCpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); + + HudPos renderFpsText( + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position); + ++ + HudPos renderFrametimeGraph( + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position); ++ ++ HudPos renderLogging( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); + + }; + +diff --git a/src/dxvk/hud/dxvk_hud_stats.cpp b/src/dxvk/hud/dxvk_hud_stats.cpp +index 995f186b..be8a5eb7 100644 +--- a/src/dxvk/hud/dxvk_hud_stats.cpp ++++ b/src/dxvk/hud/dxvk_hud_stats.cpp +@@ -1,5 +1,7 @@ + #include "dxvk_hud_stats.h" + ++std::string m_gpuLoadString = "GPU: "; ++uint64_t gpuLoad; + namespace dxvk::hud { + + HudStats::HudStats(HudElements elements) +@@ -24,7 +26,7 @@ namespace dxvk::hud { + + // GPU load is a bit more complex than that since + // we don't want to update this every frame +- if (m_elements.test(HudElement::StatGpuLoad)) ++ if (m_elements.test(HudElement::GpuLoad) || m_elements.test(HudElement::StatGpuLoad)) + this->updateGpuLoad(); + } + +@@ -70,8 +72,8 @@ namespace dxvk::hud { + uint64_t busyTicks = ticks > m_diffGpuIdleTicks + ? uint64_t(ticks - m_diffGpuIdleTicks) + : uint64_t(0); +- +- m_gpuLoadString = str::format("GPU: ", (100 * busyTicks) / ticks, "%"); ++ gpuLoad = 100 * busyTicks / ticks; ++ m_gpuLoadString = str::format("GPU: ", (100 * busyTicks) / ticks, "%"); + } + } + +@@ -224,7 +226,8 @@ namespace dxvk::hud { + HudElement::StatPipelines, + HudElement::StatMemory, + HudElement::StatGpuLoad, +- HudElement::CompilerActivity); ++ HudElement::CompilerActivity, ++ HudElement::GpuLoad); + } + + } +diff --git a/src/dxvk/hud/dxvk_hud_stats.h b/src/dxvk/hud/dxvk_hud_stats.h +index 227f600c..b7d740f1 100644 +--- a/src/dxvk/hud/dxvk_hud_stats.h ++++ b/src/dxvk/hud/dxvk_hud_stats.h +@@ -7,6 +7,8 @@ + #include "dxvk_hud_config.h" + #include "dxvk_hud_renderer.h" + ++extern std::string m_gpuLoadString; ++extern uint64_t gpuLoad; + namespace dxvk::hud { + + /** +@@ -44,8 +46,6 @@ namespace dxvk::hud { + uint64_t m_prevGpuIdleTicks = 0; + uint64_t m_diffGpuIdleTicks = 0; + +- std::string m_gpuLoadString = "GPU: "; +- + void updateGpuLoad(); + + HudPos printDrawCallStats( |