1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00
OpenDX/src/dxvk/hud/dxvk_hud_item.cpp
2019-12-13 13:05:49 +01:00

587 lines
15 KiB
C++

#include "dxvk_hud_item.h"
#include <iomanip>
#include <version.h>
namespace dxvk::hud {
HudItem::~HudItem() {
}
void HudItem::update(dxvk::high_resolution_clock::time_point time) {
// Do nothing by default. Some items won't need this.
}
HudItemSet::HudItemSet() {
std::string configStr = env::getEnvVar("DXVK_HUD");
if (configStr == "full") {
// Just enable everything
m_enableFull = true;
} else if (configStr == "1") {
m_enabled.insert("devinfo");
m_enabled.insert("fps");
} else {
std::string::size_type pos = 0;
std::string::size_type end = 0;
while (pos < configStr.size()) {
end = configStr.find(',', pos);
if (end == std::string::npos)
end = configStr.size();
m_enabled.insert(configStr.substr(pos, end - pos));
pos = end + 1;
}
}
}
HudItemSet::~HudItemSet() {
}
void HudItemSet::update() {
auto time = dxvk::high_resolution_clock::now();
for (const auto& item : m_items)
item->update(time);
}
void HudItemSet::render(HudRenderer& renderer) {
HudPos position = { 8.0f, 8.0f };
for (const auto& item : m_items)
position = item->render(renderer, position);
}
HudPos HudVersionItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
"DXVK " DXVK_VERSION);
position.y += 8.0f;
return position;
}
HudClientApiItem::HudClientApiItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudClientApiItem::~HudClientApiItem() {
}
HudPos HudClientApiItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_device->clientApi());
position.y += 8.0f;
return position;
}
HudDeviceInfoItem::HudDeviceInfoItem(const Rc<DxvkDevice>& device) {
VkPhysicalDeviceProperties props = device->adapter()->deviceProperties();
m_deviceName = props.deviceName;
m_driverVer = str::format("Driver: ",
VK_VERSION_MAJOR(props.driverVersion), ".",
VK_VERSION_MINOR(props.driverVersion), ".",
VK_VERSION_PATCH(props.driverVersion));
m_vulkanVer = str::format("Vulkan: ",
VK_VERSION_MAJOR(props.apiVersion), ".",
VK_VERSION_MINOR(props.apiVersion), ".",
VK_VERSION_PATCH(props.apiVersion));
}
HudDeviceInfoItem::~HudDeviceInfoItem() {
}
HudPos HudDeviceInfoItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_deviceName);
position.y += 24.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_driverVer);
position.y += 20.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_vulkanVer);
position.y += 8.0f;
return position;
}
HudFpsItem::HudFpsItem() { }
HudFpsItem::~HudFpsItem() { }
void HudFpsItem::update(dxvk::high_resolution_clock::time_point time) {
m_frameCount += 1;
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
if (elapsed.count() >= UpdateInterval) {
int64_t fps = (10'000'000ll * m_frameCount) / elapsed.count();
m_frameRate = str::format(fps / 10, ".", fps % 10);
m_frameCount = 0;
m_lastUpdate = time;
}
}
HudPos HudFpsItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 0.25f, 0.25f, 1.0f },
"FPS:");
renderer.drawText(16.0f,
{ position.x + 60.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_frameRate);
position.y += 8.0f;
return position;
}
HudFrameTimeItem::HudFrameTimeItem() { }
HudFrameTimeItem::~HudFrameTimeItem() { }
void HudFrameTimeItem::update(dxvk::high_resolution_clock::time_point time) {
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
m_dataPoints[m_dataPointId] = float(elapsed.count());
m_dataPointId = (m_dataPointId + 1) % NumDataPoints;
m_lastUpdate = time;
}
HudPos HudFrameTimeItem::render(
HudRenderer& renderer,
HudPos position) {
std::array<HudLineVertex, NumDataPoints * 2> vData;
position.y += 40.0f;
// 60 FPS = optimal, 10 FPS = worst
const float targetUs = 16'666.6f;
const float minUs = 5'000.0f;
const float maxUs = 100'000.0f;
// Ten times the maximum/minimum number
// of milliseconds for a single frame
uint32_t minMs = 0xFFFFFFFFu;
uint32_t maxMs = 0x00000000u;
// Paint the time points
for (uint32_t i = 0; i < NumDataPoints; i++) {
float us = m_dataPoints[(m_dataPointId + i) % NumDataPoints];
minMs = std::min(minMs, uint32_t(us / 100.0f));
maxMs = std::max(maxMs, uint32_t(us / 100.0f));
float r = std::min(std::max(-1.0f + us / targetUs, 0.0f), 1.0f);
float g = std::min(std::max( 3.0f - us / targetUs, 0.0f), 1.0f);
float l = std::sqrt(r * r + g * g);
HudNormColor color = {
uint8_t(255.0f * (r / l)),
uint8_t(255.0f * (g / l)),
uint8_t(0), uint8_t(255) };
float x = position.x + float(i);
float y = position.y;
float hVal = std::log2(std::max((us - minUs) / targetUs + 1.0f, 1.0f))
/ std::log2((maxUs - minUs) / targetUs);
float h = std::min(std::max(40.0f * hVal, 2.0f), 40.0f);
vData[2 * i + 0] = HudLineVertex { { x, y }, color };
vData[2 * i + 1] = HudLineVertex { { x, y - h }, color };
}
renderer.drawLines(vData.size(), vData.data());
// Paint min/max frame times in the entire window
position.y += 18.0f;
renderer.drawText(12.0f,
{ position.x, position.y },
{ 1.0f, 0.25f, 0.25f, 1.0f },
"min:");
renderer.drawText(12.0f,
{ position.x + 45.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(minMs / 10, ".", minMs % 10));
renderer.drawText(12.0f,
{ position.x + 150.0f, position.y },
{ 1.0f, 0.25f, 0.25f, 1.0f },
"max:");
renderer.drawText(12.0f,
{ position.x + 195.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(maxMs / 10, ".", maxMs % 10));
position.y += 4.0f;
return position;
}
HudSubmissionStatsItem::HudSubmissionStatsItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudSubmissionStatsItem::~HudSubmissionStatsItem() {
}
void HudSubmissionStatsItem::update(dxvk::high_resolution_clock::time_point time) {
DxvkStatCounters counters = m_device->getStatCounters();
uint32_t currCounter = counters.getCtr(DxvkStatCounter::QueueSubmitCount);
m_diffCounter = std::max(m_diffCounter, currCounter - m_prevCounter);
m_prevCounter = currCounter;
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
if (elapsed.count() >= UpdateInterval) {
m_showCounter = m_diffCounter;
m_diffCounter = 0;
m_lastUpdate = time;
}
}
HudPos HudSubmissionStatsItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 0.5f, 0.25f, 1.0f },
"Queue submissions: ");
renderer.drawText(16.0f,
{ position.x + 228.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_showCounter));
position.y += 8.0f;
return position;
}
HudDrawCallStatsItem::HudDrawCallStatsItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudDrawCallStatsItem::~HudDrawCallStatsItem() {
}
void HudDrawCallStatsItem::update(dxvk::high_resolution_clock::time_point time) {
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
m_frameCount += 1;
if (elapsed.count() >= UpdateInterval) {
DxvkStatCounters counters = m_device->getStatCounters();
auto diffCounters = counters.diff(m_prevCounters);
m_gpCount = diffCounters.getCtr(DxvkStatCounter::CmdDrawCalls) / m_frameCount;
m_cpCount = diffCounters.getCtr(DxvkStatCounter::CmdDispatchCalls) / m_frameCount;
m_rpCount = diffCounters.getCtr(DxvkStatCounter::CmdRenderPassCount) / m_frameCount;
m_prevCounters = counters;
m_lastUpdate = time;
m_frameCount = 0;
}
}
HudPos HudDrawCallStatsItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 0.25f, 0.5f, 1.0f, 1.0f },
"Draw calls:");
renderer.drawText(16.0f,
{ position.x + 192.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_gpCount));
position.y += 20.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 0.25f, 0.5f, 1.0f, 1.0f },
"Dispatch calls:");
renderer.drawText(16.0f,
{ position.x + 192.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_cpCount));
position.y += 20.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 0.25f, 0.5f, 1.0f, 1.0f },
"Render passes:");
renderer.drawText(16.0f,
{ position.x + 192.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_rpCount));
position.y += 8.0f;
return position;
}
HudPipelineStatsItem::HudPipelineStatsItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudPipelineStatsItem::~HudPipelineStatsItem() {
}
void HudPipelineStatsItem::update(dxvk::high_resolution_clock::time_point time) {
DxvkStatCounters counters = m_device->getStatCounters();
m_graphicsPipelines = counters.getCtr(DxvkStatCounter::PipeCountGraphics);
m_computePipelines = counters.getCtr(DxvkStatCounter::PipeCountCompute);
}
HudPos HudPipelineStatsItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 0.25f, 1.0f, 1.0f },
"Graphics pipelines:");
renderer.drawText(16.0f,
{ position.x + 240.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_graphicsPipelines));
position.y += 20.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 0.25f, 1.0f, 1.0f },
"Compute pipelines:");
renderer.drawText(16.0f,
{ position.x + 240.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
str::format(m_computePipelines));
position.y += 8.0f;
return position;
}
HudMemoryStatsItem::HudMemoryStatsItem(const Rc<DxvkDevice>& device)
: m_device(device), m_memory(device->adapter()->memoryProperties()) {
}
HudMemoryStatsItem::~HudMemoryStatsItem() {
}
void HudMemoryStatsItem::update(dxvk::high_resolution_clock::time_point time) {
for (uint32_t i = 0; i < m_memory.memoryHeapCount; i++)
m_heaps[i] = m_device->getMemoryStats(i);
}
HudPos HudMemoryStatsItem::render(
HudRenderer& renderer,
HudPos position) {
for (uint32_t i = 0; i < m_memory.memoryHeapCount; i++) {
bool isDeviceLocal = m_memory.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
uint64_t memUsedMib = m_heaps[i].memoryUsed >> 20;
uint64_t percentage = (100 * m_heaps[i].memoryUsed) / m_memory.memoryHeaps[i].size;
std::string label = str::format(isDeviceLocal ? "Vidmem" : "Sysmem", " heap ", i, ":");
std::string text = str::format(std::setfill(' '), std::setw(5), memUsedMib, " MB (", percentage, "%)");
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 1.0f, 1.0f, 0.25f, 1.0f },
label);
renderer.drawText(16.0f,
{ position.x + 168.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
text);
position.y += 4.0f;
}
position.y += 4.0f;
return position;
}
HudGpuLoadItem::HudGpuLoadItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudGpuLoadItem::~HudGpuLoadItem() {
}
void HudGpuLoadItem::update(dxvk::high_resolution_clock::time_point time) {
uint64_t ticks = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate).count();
if (ticks >= UpdateInterval) {
DxvkStatCounters counters = m_device->getStatCounters();
uint64_t currGpuIdleTicks = counters.getCtr(DxvkStatCounter::GpuIdleTicks);
m_diffGpuIdleTicks = currGpuIdleTicks - m_prevGpuIdleTicks;
m_prevGpuIdleTicks = currGpuIdleTicks;
uint64_t busyTicks = ticks > m_diffGpuIdleTicks
? uint64_t(ticks - m_diffGpuIdleTicks)
: uint64_t(0);
m_gpuLoadString = str::format((100 * busyTicks) / ticks, "%");
m_lastUpdate = time;
}
}
HudPos HudGpuLoadItem::render(
HudRenderer& renderer,
HudPos position) {
position.y += 16.0f;
renderer.drawText(16.0f,
{ position.x, position.y },
{ 0.25f, 0.5f, 0.25f, 1.0f },
"GPU:");
renderer.drawText(16.0f,
{ position.x + 60.0f, position.y },
{ 1.0f, 1.0f, 1.0f, 1.0f },
m_gpuLoadString);
position.y += 8.0f;
return position;
}
HudCompilerActivityItem::HudCompilerActivityItem(const Rc<DxvkDevice>& device)
: m_device(device) {
}
HudCompilerActivityItem::~HudCompilerActivityItem() {
}
void HudCompilerActivityItem::update(dxvk::high_resolution_clock::time_point time) {
DxvkStatCounters counters = m_device->getStatCounters();
bool doShow = counters.getCtr(DxvkStatCounter::PipeCompilerBusy);
if (!doShow) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(time - m_timeShown);
doShow = elapsed.count() <= MinShowDuration;
}
if (doShow && !m_show)
m_timeShown = time;
m_show = doShow;
}
HudPos HudCompilerActivityItem::render(
HudRenderer& renderer,
HudPos position) {
if (m_show) {
renderer.drawText(16.0f,
{ position.x, renderer.surfaceSize().height - 20.0f },
{ 1.0f, 1.0f, 1.0f, 1.0f },
"Compiling shaders...");
}
return position;
}
}