Adds renderer backend-specific statistics

Different backend have different metrics to watch and debug. So we need
a simple way to collect that.
This commit is contained in:
Vladislav Belov 2026-05-10 17:54:44 +02:00 committed by Vladislav Belov
parent 3549cc1e6c
commit 2e87f6b5aa
12 changed files with 99 additions and 9 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -28,6 +28,7 @@
#include <memory>
#include <span>
#include <string>
#include <variant>
#include <vector>
class CShaderDefines;
@ -217,6 +218,26 @@ public:
virtual uint64_t GetQueryResult(const uint32_t handle) = 0;
virtual const Capabilities& GetCapabilities() const = 0;
/**
* Collects backend-specific statistics.
*/
struct StatisticsItem
{
std::string_view name;
std::string_view unit;
std::variant<float, uint32_t> value;
// clang can't do emplace_back yet because of the aggregate type.
StatisticsItem(
std::string_view name, std::string_view unit,
std::variant<float, uint32_t> value)
: name(name), unit(unit), value(value)
{
}
};
using StatisticsVector = std::vector<StatisticsItem>;
virtual void CollectStatistics(StatisticsVector& statistics) const = 0;
};
} // namespace Backend

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -115,6 +115,8 @@ public:
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
void CollectStatistics(StatisticsVector&) const override {}
protected:
std::string m_Name;

View file

@ -1079,6 +1079,11 @@ void CDevice::InsertTimestampQuery(const uint32_t handle)
#endif
}
void CDevice::CollectStatistics(StatisticsVector& statistics) const
{
statistics.emplace_back("Backbuffer count", "", static_cast<uint32_t>(m_Backbuffers.size()));
}
std::unique_ptr<IDevice> CreateDevice(SDL_Window* window)
{
return GL::CDevice::Create(window);

View file

@ -137,6 +137,8 @@ public:
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
void CollectStatistics(StatisticsVector& statistics) const override;
private:
CDevice();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -464,6 +464,19 @@ void CDescriptorManager::OnDeviceObjectDestroy(const DeviceObjectUID uid)
m_UIDToSingleTypePoolMap.erase(it);
}
void CDescriptorManager::CollectStatistics(IDevice::StatisticsVector& statistics) const
{
const uint32_t descriptorPoolCount{std::transform_reduce(
m_SingleTypePools.begin(), m_SingleTypePools.end(), 0u, std::plus(),
[](const auto& cacheItem)
{
return static_cast<uint32_t>(cacheItem.second.size());
})};
statistics.emplace_back("Cached VkDescriptorPool count", "", descriptorPoolCount);
statistics.emplace_back("Cached VkDescriptorSet count", "", static_cast<uint32_t>(m_SingleTypeSets.size()));
}
} // namespace Vulkan
} // namespace Backend

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -86,6 +86,8 @@ public:
const std::vector<VkDescriptorSetLayout>& GetDescriptorSetLayouts() const { return m_DescriptorSetLayouts; }
void CollectStatistics(IDevice::StatisticsVector& statistics) const;
private:
struct SingleTypePool
{

View file

@ -981,6 +981,30 @@ uint64_t CDevice::GetQueryResult(const uint32_t handle)
return data;
}
void CDevice::CollectStatistics(StatisticsVector& statistics) const
{
VmaBudget heapBudgets[VK_MAX_MEMORY_HEAPS];
vmaGetHeapBudgets(m_VMAAllocator, heapBudgets);
VmaStatistics totalStatistics{};
for (uint32_t index{0}; index < m_ChoosenDevice.memoryProperties.memoryHeapCount; ++index)
{
totalStatistics.blockCount += heapBudgets[index].statistics.blockCount;
totalStatistics.allocationCount += heapBudgets[index].statistics.allocationCount;
totalStatistics.blockBytes += heapBudgets[index].statistics.blockBytes;
totalStatistics.allocationBytes += heapBudgets[index].statistics.allocationBytes;
}
statistics.emplace_back("VMA total blockCount", "", totalStatistics.blockCount);
statistics.emplace_back("VMA total allocationCount", "", totalStatistics.allocationCount);
statistics.emplace_back("VMA total blockBytes", "MiB", static_cast<uint32_t>(totalStatistics.blockBytes / MiB));
statistics.emplace_back("VMA total allocationBytes", "MiB", static_cast<uint32_t>(totalStatistics.allocationBytes / MiB));
m_DescriptorManager->CollectStatistics(statistics);
m_SamplerManager->CollectStatistics(statistics);
m_RenderPassManager->CollectStatistics(statistics);
}
bool CDevice::IsFormatSupportedForUsage(const Format format, const uint32_t usage) const
{
VkFormatProperties formatProperties{};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -145,6 +145,8 @@ public:
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
void CollectStatistics(StatisticsVector& statistics) const override;
VkDevice GetVkDevice() const { return m_Device; }
VmaAllocator GetVMAAllocator() { return m_VMAAllocator; }
@ -188,6 +190,8 @@ public:
DeviceObjectUID GenerateNextDeviceObjectUID();
uint32_t GetFrameID() const { return m_FrameID; }
private:
CDevice();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -198,6 +198,11 @@ VkRenderPass CRenderPassManager::GetOrCreateRenderPass(
return renderPass;
}
void CRenderPassManager::CollectStatistics(IDevice::StatisticsVector& statistics) const
{
statistics.emplace_back("VkRenderPass count", "", static_cast<uint32_t>(m_RenderPassMap.size()));
}
} // namespace Vulkan
} // namespace Backend

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -18,6 +18,8 @@
#ifndef INCLUDED_RENDERER_BACKEND_VULKAN_RENDERPASSMANAGER
#define INCLUDED_RENDERER_BACKEND_VULKAN_RENDERPASSMANAGER
#include "renderer/backend/IDevice.h"
#include <cstddef>
#include <cstdint>
#include <glad/vulkan.h>
@ -57,6 +59,8 @@ public:
SColorAttachment* colorAttachment,
SDepthStencilAttachment* depthStencilAttachment);
void CollectStatistics(IDevice::StatisticsVector& statistics) const;
private:
CDevice* m_Device = nullptr;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -141,6 +141,11 @@ VkSampler CSamplerManager::GetOrCreateSampler(
return sampler;
}
void CSamplerManager::CollectStatistics(IDevice::StatisticsVector& statistics) const
{
statistics.emplace_back("Samplers count", "", static_cast<uint32_t>(m_SamplerMap.size()));
}
} // namespace Vulkan
} // namespace Backend

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -18,6 +18,7 @@
#ifndef INCLUDED_RENDERER_BACKEND_VULKAN_SAMPLERMANAGER
#define INCLUDED_RENDERER_BACKEND_VULKAN_SAMPLERMANAGER
#include "renderer/backend/IDevice.h"
#include "renderer/backend/Sampler.h"
#include <cstddef>
@ -52,6 +53,8 @@ public:
*/
VkSampler GetOrCreateSampler(const Sampler::Desc& samplerDesc);
void CollectStatistics(IDevice::StatisticsVector& statistics) const;
private:
CDevice* m_Device = nullptr;