Allow other backends than Vulkan to have GPU memory stats. Implement for GL.

This commit is contained in:
Henrik Rydgård 2023-05-24 14:32:38 +02:00
parent 62b41c6640
commit dfb446f89d
15 changed files with 116 additions and 79 deletions

View File

@ -631,6 +631,8 @@ add_library(Common STATIC
Common/File/FileDescriptor.h
Common/GPU/DataFormat.h
Common/GPU/MiscTypes.h
Common/GPU/GPUBackendCommon.cpp
Common/GPU/GPUBackendCommon.h
Common/GPU/thin3d.cpp
Common/GPU/thin3d.h
Common/GPU/thin3d_create.h

View File

@ -450,6 +450,7 @@
<ClInclude Include="GPU\D3D9\D3D9ShaderCompiler.h" />
<ClInclude Include="GPU\D3D9\D3D9StateCache.h" />
<ClInclude Include="GPU\DataFormat.h" />
<ClInclude Include="GPU\GPUBackendCommon.h" />
<ClInclude Include="GPU\MiscTypes.h" />
<ClInclude Include="GPU\OpenGL\DataFormatGL.h" />
<ClInclude Include="GPU\OpenGL\gl3stub.h" />
@ -894,6 +895,7 @@
<ClCompile Include="GPU\D3D9\D3D9ShaderCompiler.cpp" />
<ClCompile Include="GPU\D3D9\D3D9StateCache.cpp" />
<ClCompile Include="GPU\D3D9\thin3d_d3d9.cpp" />
<ClCompile Include="GPU\GPUBackendCommon.cpp" />
<ClCompile Include="GPU\OpenGL\DataFormatGL.cpp" />
<ClCompile Include="GPU\OpenGL\gl3stub.c" />
<ClCompile Include="GPU\OpenGL\GLFeatures.cpp" />

View File

@ -449,9 +449,6 @@
<ClInclude Include="Render\ManagedTexture.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="GPU\MiscTypes.h">
<Filter>GPU</Filter>
</ClInclude>
<ClInclude Include="GPU\Vulkan\VulkanFramebuffer.h">
<Filter>GPU\Vulkan</Filter>
</ClInclude>
@ -503,6 +500,12 @@
<ClInclude Include="GPU\OpenGL\GLMemory.h">
<Filter>GPU\OpenGL</Filter>
</ClInclude>
<ClInclude Include="GPU\GPUBackendCommon.h">
<Filter>GPU</Filter>
</ClInclude>
<ClInclude Include="GPU\MiscTypes.h">
<Filter>GPU</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
@ -941,6 +944,9 @@
<ClCompile Include="Data\Collections\FastVec.h">
<Filter>Data\Collections</Filter>
</ClCompile>
<ClCompile Include="GPU\GPUBackendCommon.cpp">
<Filter>GPU</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Crypto">
@ -1089,4 +1095,4 @@
<Filter>ext\basis_universal</Filter>
</None>
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,28 @@
#include <mutex>
#include <set>
#include "Common/GPU/GPUBackendCommon.h"
// Global push buffer tracker for GPU memory profiling.
// Don't want to manually dig up all the active push buffers.
static std::mutex g_pushBufferListMutex;
static std::set<GPUMemoryManager *> g_pushBuffers;
std::vector<GPUMemoryManager *> GetActiveGPUMemoryManagers() {
std::vector<GPUMemoryManager *> buffers;
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
for (auto iter : g_pushBuffers) {
buffers.push_back(iter);
}
return buffers;
}
void RegisterGPUMemoryManager(GPUMemoryManager *manager) {
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.insert(manager);
}
void UnregisterGPUMemoryManager(GPUMemoryManager *manager) {
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.erase(manager);
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <vector>
// Just an abstract thing to get debug information.
class GPUMemoryManager {
public:
virtual ~GPUMemoryManager() {}
virtual void GetDebugString(char *buffer, size_t bufSize) const = 0;
virtual const char *Name() const = 0; // for sorting
};
std::vector<GPUMemoryManager *> GetActiveGPUMemoryManagers();
void RegisterGPUMemoryManager(GPUMemoryManager *manager);
void UnregisterGPUMemoryManager(GPUMemoryManager *manager);

View File

@ -2,6 +2,7 @@
#include "Common/GPU/OpenGL/GLMemory.h"
#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/Data/Text/Parsers.h"
extern std::thread::id renderThreadId;
#if MAX_LOGLEVEL >= DEBUG_LEVEL
@ -64,9 +65,11 @@ bool GLRBuffer::Unmap() {
GLPushBuffer::GLPushBuffer(GLRenderManager *render, GLuint target, size_t size, const char *tag) : render_(render), size_(size), target_(target), tag_(tag) {
bool res = AddBuffer();
_assert_(res);
RegisterGPUMemoryManager(this);
}
GLPushBuffer::~GLPushBuffer() {
UnregisterGPUMemoryManager(this);
Destroy(true);
}
@ -279,3 +282,7 @@ void GLPushBuffer::UnmapDevice() {
}
}
}
void GLPushBuffer::GetDebugString(char *buffer, size_t bufSize) const {
snprintf(buffer, bufSize, "%s: %d/%d", tag_, NiceSizeFormat(this->offset_).c_str(), NiceSizeFormat(this->size_).c_str());
}

View File

@ -4,6 +4,7 @@
#include <cstdint>
#include <cstring>
#include "Common/GPU/GPUBackendCommon.h"
#include "Common/GPU/OpenGL/GLCommon.h"
#include "Common/Log.h"
@ -61,7 +62,7 @@ class GLRenderManager;
// trouble.
// We need to manage the lifetime of this together with the other resources so its destructor
// runs on the render thread.
class GLPushBuffer {
class GLPushBuffer : public GPUMemoryManager {
public:
friend class GLRenderManager;
@ -78,6 +79,10 @@ public:
void Reset() { offset_ = 0; }
void GetDebugString(char *buffer, size_t bufSize) const override;
const char *Name() const override { return tag_; }; // for sorting
// Utility for users of this class, not used internally.
const uint32_t INVALID_OFFSET = 0xFFFFFFFF;

View File

@ -35,37 +35,15 @@ using namespace PPSSPP_VK;
// Always keep around push buffers at least this long (seconds).
static const double PUSH_GARBAGE_COLLECTION_DELAY = 10.0;
// Global push buffer tracker for vulkan memory profiling.
// Don't want to manually dig up all the active push buffers.
static std::mutex g_pushBufferListMutex;
static std::set<VulkanMemoryManager *> g_pushBuffers;
std::vector<VulkanMemoryManager *> GetActiveVulkanMemoryManagers() {
std::vector<VulkanMemoryManager *> buffers;
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
for (auto iter : g_pushBuffers) {
buffers.push_back(iter);
}
return buffers;
}
VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, const char *name, size_t size, VkBufferUsageFlags usage)
: vulkan_(vulkan), name_(name), size_(size), usage_(usage) {
{
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.insert(this);
}
RegisterGPUMemoryManager(this);
bool res = AddBuffer();
_assert_(res);
}
VulkanPushBuffer::~VulkanPushBuffer() {
{
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.erase(this);
}
UnregisterGPUMemoryManager(this);
_dbg_assert_(!writePtr_);
_assert_(buffers_.empty());
}
@ -276,11 +254,7 @@ VkResult VulkanDescSetPool::Recreate(bool grow) {
VulkanPushPool::VulkanPushPool(VulkanContext *vulkan, const char *name, size_t originalBlockSize, VkBufferUsageFlags usage)
: vulkan_(vulkan), name_(name), originalBlockSize_(originalBlockSize), usage_(usage) {
{
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.insert(this);
}
RegisterGPUMemoryManager(this);
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
blocks_.push_back(CreateBlock(originalBlockSize));
blocks_.back().original = true;
@ -289,11 +263,7 @@ VulkanPushPool::VulkanPushPool(VulkanContext *vulkan, const char *name, size_t o
}
VulkanPushPool::~VulkanPushPool() {
{
std::lock_guard<std::mutex> guard(g_pushBufferListMutex);
g_pushBuffers.erase(this);
}
UnregisterGPUMemoryManager(this);
_dbg_assert_(blocks_.empty());
}

View File

@ -6,6 +6,7 @@
#include <vector>
#include "Common/GPU/Vulkan/VulkanContext.h"
#include "Common/GPU/GPUBackendCommon.h"
// Forward declaration
VK_DEFINE_HANDLE(VmaAllocation);
@ -14,22 +15,13 @@ VK_DEFINE_HANDLE(VmaAllocation);
//
// Vulkan memory management utils.
// Just an abstract thing to get debug information.
class VulkanMemoryManager {
public:
virtual ~VulkanMemoryManager() {}
virtual void GetDebugString(char *buffer, size_t bufSize) const = 0;
virtual const char *Name() const = 0; // for sorting
};
// VulkanPushBuffer
// Simple incrementing allocator.
// Use these to push vertex, index and uniform data. Generally you'll have two or three of these
// and alternate on each frame. Make sure not to reset until the fence from the last time you used it
// has completed.
// NOTE: This has now been replaced with VulkanPushPool for all uses except the vertex cache.
class VulkanPushBuffer : public VulkanMemoryManager {
class VulkanPushBuffer : public GPUMemoryManager {
struct BufInfo {
VkBuffer buffer;
VmaAllocation allocation;
@ -108,7 +100,7 @@ private:
// Simple memory pushbuffer pool that can share blocks between the "frames", to reduce the impact of push memory spikes -
// a later frame can gobble up redundant buffers from an earlier frame even if they don't share frame index.
// NOT thread safe! Can only be used from one thread (our main thread).
class VulkanPushPool : public VulkanMemoryManager {
class VulkanPushPool : public GPUMemoryManager {
public:
VulkanPushPool(VulkanContext *vulkan, const char *name, size_t originalBlockSize, VkBufferUsageFlags usage);
~VulkanPushPool();
@ -212,5 +204,3 @@ private:
bool grow_;
};
std::vector<VulkanMemoryManager *> GetActiveVulkanMemoryManagers();

View File

@ -30,6 +30,7 @@
#include "ext/vma/vk_mem_alloc.h"
#include "DebugVisVulkan.h"
#include "Common/GPU/GPUBackendCommon.h"
#include "Common/GPU/Vulkan/VulkanMemory.h"
#include "Common/GPU/Vulkan/VulkanImage.h"
#include "Common/Data/Text/Parsers.h"
@ -41,7 +42,7 @@
#undef DrawText
bool comparePushBufferNames(const VulkanMemoryManager *a, const VulkanMemoryManager *b) {
bool comparePushBufferNames(const GPUMemoryManager *a, const GPUMemoryManager *b) {
return strcmp(a->Name(), b->Name()) < 0;
}
@ -49,35 +50,34 @@ void DrawGPUMemoryVis(UIContext *ui, GPUInterface *gpu) {
// This one will simply display stats.
Draw::DrawContext *draw = ui->GetDrawContext();
VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
if (!vulkan) {
return;
}
VmaTotalStatistics vmaStats;
vmaCalculateStatistics(vulkan->Allocator(), &vmaStats);
std::vector<VmaBudget> budgets;
budgets.resize(vulkan->GetMemoryProperties().memoryHeapCount);
vmaGetHeapBudgets(vulkan->Allocator(), &budgets[0]);
size_t totalBudget = 0;
size_t totalUsedBytes = 0;
for (auto &budget : budgets) {
totalBudget += budget.budget;
totalUsedBytes += budget.usage;
}
std::stringstream str;
str << vulkan->GetPhysicalDeviceProperties().properties.deviceName << std::endl;
str << "Allocated " << NiceSizeFormat(vmaStats.total.statistics.allocationBytes) << " in " << vmaStats.total.statistics.allocationCount << " allocs" << std::endl;
// Note: The overall number includes stuff like descriptor sets pools and other things that are not directly visible as allocations.
str << "Overall " << NiceSizeFormat(totalUsedBytes) << " used out of " << NiceSizeFormat(totalBudget) << " available" << std::endl;
VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
if (vulkan) {
VmaTotalStatistics vmaStats;
vmaCalculateStatistics(vulkan->Allocator(), &vmaStats);
std::vector<VmaBudget> budgets;
budgets.resize(vulkan->GetMemoryProperties().memoryHeapCount);
vmaGetHeapBudgets(vulkan->Allocator(), &budgets[0]);
size_t totalBudget = 0;
size_t totalUsedBytes = 0;
for (auto &budget : budgets) {
totalBudget += budget.budget;
totalUsedBytes += budget.usage;
}
str << vulkan->GetPhysicalDeviceProperties().properties.deviceName << std::endl;
str << "Allocated " << NiceSizeFormat(vmaStats.total.statistics.allocationBytes) << " in " << vmaStats.total.statistics.allocationCount << " allocs" << std::endl;
// Note: The overall number includes stuff like descriptor sets pools and other things that are not directly visible as allocations.
str << "Overall " << NiceSizeFormat(totalUsedBytes) << " used out of " << NiceSizeFormat(totalBudget) << " available" << std::endl;
}
str << "Push buffers:" << std::endl;
// Now list the various push buffers.
auto managers = GetActiveVulkanMemoryManagers();
auto managers = GetActiveGPUMemoryManagers();
std::sort(managers.begin(), managers.end(), comparePushBufferNames);
char buffer[512];

View File

@ -100,8 +100,8 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) {
items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenuScreen::OnDeveloperTools);
items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenuScreen::OnJitCompare);
items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenuScreen::OnShaderView);
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer")));
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("GPU Allocator Viewer")));
}
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
items->Add(new CheckBox(&g_Config.bShowGpuProfile, dev->T("GPU Profile")));

View File

@ -287,6 +287,7 @@
<ClInclude Include="..\..\Common\Data\Format\DDSLoad.h" />
<ClInclude Include="..\..\Common\File\AndroidContentURI.h" />
<ClInclude Include="..\..\Common\File\AndroidStorage.h" />
<ClInclude Include="..\..\Common\GPU\GPUBackendCommon.h" />
<ClInclude Include="..\..\Common\GPU\Vulkan\VulkanLoader.h" />
<ClInclude Include="..\..\Common\Math\Statistics.h" />
<ClInclude Include="..\..\Common\Net\NetBuffer.h" />
@ -443,6 +444,7 @@
<ClCompile Include="..\..\Common\Data\Format\DDSLoad.cpp" />
<ClCompile Include="..\..\Common\File\AndroidContentURI.cpp" />
<ClCompile Include="..\..\Common\File\AndroidStorage.cpp" />
<ClCompile Include="..\..\Common\GPU\GPUBackendCommon.cpp" />
<ClCompile Include="..\..\Common\GPU\Vulkan\VulkanLoader.cpp" />
<ClCompile Include="..\..\Common\Math\Statistics.cpp" />
<ClCompile Include="..\..\Common\Net\NetBuffer.cpp" />

View File

@ -435,6 +435,9 @@
<ClCompile Include="..\..\Common\File\AndroidContentURI.cpp">
<Filter>File</Filter>
</ClCompile>
<ClCompile Include="..\..\Common\GPU\GPUBackendCommon.cpp">
<Filter>GPU</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="targetver.h" />
@ -823,6 +826,9 @@
<ClInclude Include="..\..\Common\File\AndroidContentURI.h">
<Filter>File</Filter>
</ClInclude>
<ClInclude Include="..\..\Common\GPU\GPUBackendCommon.h">
<Filter>GPU</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Common\Math\fast\fast_matrix_neon.S">

View File

@ -189,6 +189,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Common/File/DirListing.cpp \
$(SRC)/Common/File/FileDescriptor.cpp \
$(SRC)/Common/GPU/thin3d.cpp \
$(SRC)/Common/GPU/GPUBackendCommon.cpp \
$(SRC)/Common/GPU/Shader.cpp \
$(SRC)/Common/GPU/ShaderWriter.cpp \
$(SRC)/Common/GPU/ShaderTranslation.cpp \

View File

@ -286,6 +286,7 @@ SOURCES_CXX += \
$(COMMONDIR)/File/DirListing.cpp \
$(COMMONDIR)/GPU/thin3d.cpp \
$(COMMONDIR)/GPU/Shader.cpp \
$(COMMONDIR)/GPU/GPUBackendCommon.cpp \
$(COMMONDIR)/GPU/ShaderWriter.cpp \
$(COMMONDIR)/GPU/ShaderTranslation.cpp \
$(COMMONDIR)/GPU/OpenGL/thin3d_gl.cpp \