mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 02:52:10 +01:00
[hud] Added stat counters to the HUD
This commit is contained in:
parent
3ed03f7a3d
commit
fc3f45c082
@ -12,10 +12,17 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkStatCounters DxvkStatCounters::diff(const DxvkStatCounters& other) const {
|
||||||
|
DxvkStatCounters result;
|
||||||
|
for (size_t i = 0; i < m_counters.size(); i++)
|
||||||
|
result.m_counters[i] = m_counters[i] - other.m_counters[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkStatCounters::merge(const DxvkStatCounters& other) {
|
void DxvkStatCounters::merge(const DxvkStatCounters& other) {
|
||||||
for (size_t i = 0; i < m_counters.size(); i++) {
|
for (size_t i = 0; i < m_counters.size(); i++)
|
||||||
m_counters[i] += other.m_counters[i];
|
m_counters[i] += other.m_counters[i];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +77,15 @@ namespace dxvk {
|
|||||||
m_counters[uint32_t(ctr)] = 0;
|
m_counters[uint32_t(ctr)] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes difference
|
||||||
|
*
|
||||||
|
* Computes difference between counter values.
|
||||||
|
* \param [in] other Counters to subtract
|
||||||
|
* \returns Difference between counter sets
|
||||||
|
*/
|
||||||
|
DxvkStatCounters diff(const DxvkStatCounters& other) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Merges counters
|
* \brief Merges counters
|
||||||
*
|
*
|
||||||
|
@ -12,7 +12,8 @@ namespace dxvk::hud {
|
|||||||
m_context (m_device->createContext()),
|
m_context (m_device->createContext()),
|
||||||
m_textRenderer (m_device, m_context),
|
m_textRenderer (m_device, m_context),
|
||||||
m_uniformBuffer (createUniformBuffer()),
|
m_uniformBuffer (createUniformBuffer()),
|
||||||
m_hudDeviceInfo (device) {
|
m_hudDeviceInfo (device),
|
||||||
|
m_hudStats (config.elements) {
|
||||||
this->setupConstantState();
|
this->setupConstantState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ namespace dxvk::hud {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_hudFps.update();
|
m_hudFps.update();
|
||||||
|
m_hudStats.update(m_device);
|
||||||
|
|
||||||
this->beginRenderPass(recreateFbo);
|
this->beginRenderPass(recreateFbo);
|
||||||
this->updateUniformBuffer();
|
this->updateUniformBuffer();
|
||||||
@ -42,11 +44,9 @@ namespace dxvk::hud {
|
|||||||
Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) {
|
Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) {
|
||||||
HudConfig config(env::getEnvVar(L"DXVK_HUD"));
|
HudConfig config(env::getEnvVar(L"DXVK_HUD"));
|
||||||
|
|
||||||
if (config.elements.isClear())
|
return !config.elements.isClear()
|
||||||
return nullptr;
|
? new Hud(device, config)
|
||||||
|
: nullptr;
|
||||||
// TODO implement configuration options for the HUD
|
|
||||||
return new Hud(device, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +78,9 @@ namespace dxvk::hud {
|
|||||||
position = m_hudFps.renderText(
|
position = m_hudFps.renderText(
|
||||||
m_context, m_textRenderer, position);
|
m_context, m_textRenderer, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position = m_hudStats.renderText(
|
||||||
|
m_context, m_textRenderer, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "dxvk_hud_devinfo.h"
|
#include "dxvk_hud_devinfo.h"
|
||||||
#include "dxvk_hud_fps.h"
|
#include "dxvk_hud_fps.h"
|
||||||
#include "dxvk_hud_text.h"
|
#include "dxvk_hud_text.h"
|
||||||
|
#include "dxvk_hud_stats.h"
|
||||||
|
|
||||||
namespace dxvk::hud {
|
namespace dxvk::hud {
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ namespace dxvk::hud {
|
|||||||
|
|
||||||
HudDeviceInfo m_hudDeviceInfo;
|
HudDeviceInfo m_hudDeviceInfo;
|
||||||
HudFps m_hudFps;
|
HudFps m_hudFps;
|
||||||
|
HudStats m_hudStats;
|
||||||
|
|
||||||
void renderText();
|
void renderText();
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#include "dxvk_hud_config.h"
|
#include "dxvk_hud_config.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk::hud {
|
||||||
|
|
||||||
const std::unordered_map<std::string, HudElement> g_hudElements = {{
|
const std::unordered_map<std::string, HudElement> g_hudElements = {{
|
||||||
{ "devinfo", HudElement::DeviceInfo },
|
{ "devinfo", HudElement::DeviceInfo },
|
||||||
{ "fps", HudElement::Framerate },
|
{ "fps", HudElement::Framerate },
|
||||||
|
{ "drawcalls", HudElement::StatDrawCalls },
|
||||||
|
{ "submissions", HudElement::StatSubmissions },
|
||||||
|
{ "pipelines", HudElement::StatPipelines },
|
||||||
|
{ "memory", HudElement::StatMemory },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "../dxvk_include.h"
|
#include "../dxvk_include.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk::hud {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief HUD element
|
* \brief HUD element
|
||||||
@ -11,8 +11,12 @@ namespace dxvk {
|
|||||||
* or disable HUD elements on demand.
|
* or disable HUD elements on demand.
|
||||||
*/
|
*/
|
||||||
enum class HudElement {
|
enum class HudElement {
|
||||||
DeviceInfo = 0,
|
DeviceInfo = 0,
|
||||||
Framerate = 1,
|
Framerate = 1,
|
||||||
|
StatDrawCalls = 2,
|
||||||
|
StatSubmissions = 3,
|
||||||
|
StatPipelines = 4,
|
||||||
|
StatMemory = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
using HudElements = Flags<HudElement>;
|
using HudElements = Flags<HudElement>;
|
||||||
|
@ -41,7 +41,7 @@ namespace dxvk::hud {
|
|||||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
m_fpsString);
|
m_fpsString);
|
||||||
|
|
||||||
return HudPos { position.x, position.y + 20 };
|
return HudPos { position.x, position.y + 24 };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
168
src/dxvk/hud/dxvk_hud_stats.cpp
Normal file
168
src/dxvk/hud/dxvk_hud_stats.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "dxvk_hud_stats.h"
|
||||||
|
|
||||||
|
namespace dxvk::hud {
|
||||||
|
|
||||||
|
HudStats::HudStats(HudElements elements)
|
||||||
|
: m_elements(filterElements(elements)) { }
|
||||||
|
|
||||||
|
|
||||||
|
HudStats::~HudStats() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HudStats::update(const Rc<DxvkDevice>& device) {
|
||||||
|
if (m_elements.isClear())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// For some counters, we'll display the absolute value,
|
||||||
|
// for others, the average counter increment per frame.
|
||||||
|
DxvkStatCounters nextCounters = device->getStatCounters();
|
||||||
|
m_diffCounters = nextCounters.diff(m_prevCounters);
|
||||||
|
m_prevCounters = nextCounters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudStats::renderText(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
if (m_elements.test(HudElement::StatSubmissions))
|
||||||
|
position = this->printSubmissionStats(context, renderer, position);
|
||||||
|
|
||||||
|
if (m_elements.test(HudElement::StatDrawCalls))
|
||||||
|
position = this->printDrawCallStats(context, renderer, position);
|
||||||
|
|
||||||
|
if (m_elements.test(HudElement::StatPipelines))
|
||||||
|
position = this->printPipelineStats(context, renderer, position);
|
||||||
|
|
||||||
|
if (m_elements.test(HudElement::StatMemory))
|
||||||
|
position = this->printMemoryStats(context, renderer, position);
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudStats::printDrawCallStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
const uint64_t frameCount = std::max(m_diffCounters.getCtr(DxvkStatCounter::QueuePresentCount), 1u);
|
||||||
|
|
||||||
|
const uint64_t gpCalls = m_diffCounters.getCtr(DxvkStatCounter::CmdDrawCalls) / frameCount;
|
||||||
|
const uint64_t cpCalls = m_diffCounters.getCtr(DxvkStatCounter::CmdDispatchCalls) / frameCount;
|
||||||
|
const uint64_t rpCalls = m_diffCounters.getCtr(DxvkStatCounter::CmdRenderPassCount) / frameCount;
|
||||||
|
|
||||||
|
const std::string strDrawCalls = str::format("Draw calls: ", gpCalls);
|
||||||
|
const std::string strDispatchCalls = str::format("Dispatch calls: ", cpCalls);
|
||||||
|
const std::string strRenderPasses = str::format("Render passes: ", rpCalls);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strDrawCalls);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y + 20.0f },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strDispatchCalls);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y + 40.0f },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strRenderPasses);
|
||||||
|
|
||||||
|
return { position.x, position.y + 64 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudStats::printSubmissionStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
const uint64_t frameCount = std::max(m_diffCounters.getCtr(DxvkStatCounter::QueuePresentCount), 1u);
|
||||||
|
const uint64_t numSubmits = m_diffCounters.getCtr(DxvkStatCounter::QueueSubmitCount) / frameCount;
|
||||||
|
|
||||||
|
const std::string strSubmissions = str::format("Queue submissions: ", numSubmits);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strSubmissions);
|
||||||
|
|
||||||
|
return { position.x, position.y + 24.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudStats::printPipelineStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
constexpr uint64_t kib = 1024;
|
||||||
|
constexpr uint64_t mib = 1024 * 1024;
|
||||||
|
|
||||||
|
const uint64_t gpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountGraphics);
|
||||||
|
const uint64_t cpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountCompute);
|
||||||
|
const uint64_t pcSize = m_prevCounters.getCtr(DxvkStatCounter::PipeCacheSize);
|
||||||
|
|
||||||
|
const std::string strGpCount = str::format("Graphics pipelines: ", gpCount);
|
||||||
|
const std::string strCpCount = str::format("Compute pipelines: ", cpCount);
|
||||||
|
|
||||||
|
const std::string strPcSize = str::format("Pipeline cache: ", pcSize >= mib
|
||||||
|
? str::format(pcSize / mib, ".", ((10 * pcSize) / mib) % 10, " MB")
|
||||||
|
: str::format(pcSize / kib, " kB"));
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strGpCount);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y + 20.0f },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strCpCount);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y + 40.0f },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strPcSize);
|
||||||
|
|
||||||
|
return { position.x, position.y + 64.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudStats::printMemoryStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
constexpr uint64_t mib = 1024 * 1024;
|
||||||
|
|
||||||
|
const uint64_t memAllocated = m_prevCounters.getCtr(DxvkStatCounter::MemoryAllocated);
|
||||||
|
const uint64_t memUsed = m_prevCounters.getCtr(DxvkStatCounter::MemoryUsed);
|
||||||
|
|
||||||
|
const std::string strMemAllocated = str::format("Memory allocated: ", memAllocated / mib, " MB");
|
||||||
|
const std::string strMemUsed = str::format("Memory used: ", memUsed / mib, " MB");
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strMemAllocated);
|
||||||
|
|
||||||
|
renderer.drawText(context, 16.0f,
|
||||||
|
{ position.x, position.y + 20.0f },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
strMemUsed);
|
||||||
|
|
||||||
|
return { position.x, position.y + 44.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudElements HudStats::filterElements(HudElements elements) {
|
||||||
|
return elements & HudElements(
|
||||||
|
HudElement::StatDrawCalls,
|
||||||
|
HudElement::StatSubmissions,
|
||||||
|
HudElement::StatPipelines,
|
||||||
|
HudElement::StatMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
63
src/dxvk/hud/dxvk_hud_stats.h
Normal file
63
src/dxvk/hud/dxvk_hud_stats.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../dxvk_stats.h"
|
||||||
|
|
||||||
|
#include "dxvk_hud_config.h"
|
||||||
|
#include "dxvk_hud_text.h"
|
||||||
|
|
||||||
|
namespace dxvk::hud {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Statistics display for the HUD
|
||||||
|
*
|
||||||
|
* Displays some stat counters for the device
|
||||||
|
* if enabled. Certain groups of counters can
|
||||||
|
* be enabled inidividually.
|
||||||
|
*/
|
||||||
|
class HudStats {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HudStats(HudElements elements);
|
||||||
|
~HudStats();
|
||||||
|
|
||||||
|
void update(
|
||||||
|
const Rc<DxvkDevice>& device);
|
||||||
|
|
||||||
|
HudPos renderText(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const HudElements m_elements;
|
||||||
|
|
||||||
|
DxvkStatCounters m_prevCounters;
|
||||||
|
DxvkStatCounters m_diffCounters;
|
||||||
|
|
||||||
|
HudPos printDrawCallStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
HudPos printSubmissionStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
HudPos printPipelineStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
HudPos printMemoryStats(
|
||||||
|
const Rc<DxvkContext>& context,
|
||||||
|
HudTextRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
static HudElements filterElements(HudElements elements);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -52,6 +52,7 @@ dxvk_src = files([
|
|||||||
'hud/dxvk_hud_devinfo.cpp',
|
'hud/dxvk_hud_devinfo.cpp',
|
||||||
'hud/dxvk_hud_font.cpp',
|
'hud/dxvk_hud_font.cpp',
|
||||||
'hud/dxvk_hud_fps.cpp',
|
'hud/dxvk_hud_fps.cpp',
|
||||||
|
'hud/dxvk_hud_stats.cpp',
|
||||||
'hud/dxvk_hud_text.cpp',
|
'hud/dxvk_hud_text.cpp',
|
||||||
|
|
||||||
'vulkan/dxvk_vulkan_extensions.cpp',
|
'vulkan/dxvk_vulkan_extensions.cpp',
|
||||||
|
@ -68,6 +68,18 @@ namespace dxvk {
|
|||||||
return m_bits;
|
return m_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flags operator & (const Flags& other) const {
|
||||||
|
return Flags(m_bits & other.m_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags operator | (const Flags& other) const {
|
||||||
|
return Flags(m_bits | other.m_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags operator ^ (const Flags& other) const {
|
||||||
|
return Flags(m_bits ^ other.m_bits);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IntType m_bits = 0;
|
IntType m_bits = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user