summarylogtreecommitdiffstats
path: root/dxvk-mangohud.patch
diff options
context:
space:
mode:
Diffstat (limited to 'dxvk-mangohud.patch')
-rw-r--r--dxvk-mangohud.patch665
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(