Merge pull request #17475 from hrydgard/opengl-basic-profiler

Add a trivial profiling tool to the OpenGL backend
This commit is contained in:
Henrik Rydgård 2023-05-17 15:01:16 +02:00 committed by GitHub
commit 5d7a0516cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 60 additions and 7 deletions

View file

@ -35,6 +35,13 @@ public:
std::vector<GLPushBuffer *> pushBuffers;
};
struct GLQueueProfileContext {
bool enabled;
double cpuStartTime;
double cpuEndTime;
};
// Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
struct GLFrameData {
bool skipSwap = false;
@ -49,4 +56,6 @@ struct GLFrameData {
GLDeleter deleter;
GLDeleter deleter_prev;
std::set<GLPushBuffer *> activePushBuffers;
GLQueueProfileContext profile;
};

View file

@ -8,6 +8,7 @@
#include "Common/Log.h"
#include "Common/TimeUtil.h"
#include "Common/MemoryUtil.h"
#include "Common/StringUtils.h"
#include "Common/Math/math_util.h"
#if 0 // def _DEBUG
@ -187,6 +188,14 @@ void GLRenderManager::StopThread() {
}
}
std::string GLRenderManager::GetGpuProfileString() const {
int curFrame = GetCurFrame();
const GLQueueProfileContext &profile = frameData_[curFrame].profile;
float cputime_ms = 1000.0f * (profile.cpuEndTime - profile.cpuStartTime);
return StringFromFormat("CPU time to run the list: %0.2f ms", cputime_ms);
}
void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
_assert_(insideFrame_);
#ifdef _DEBUG
@ -341,7 +350,7 @@ void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, i
queueRunner_.CopyFromReadbackBuffer(nullptr, w, h, Draw::DataFormat::R8G8B8A8_UNORM, destFormat, pixelStride, pixels);
}
void GLRenderManager::BeginFrame() {
void GLRenderManager::BeginFrame(bool enableProfiling) {
#ifdef _DEBUG
curProgram_ = nullptr;
#endif
@ -349,6 +358,7 @@ void GLRenderManager::BeginFrame() {
int curFrame = GetCurFrame();
GLFrameData &frameData = frameData_[curFrame];
frameData.profile.enabled = enableProfiling;
{
VLOG("PUSH: BeginFrame (curFrame = %d, readyForFence = %d, time=%0.3f)", curFrame, (int)frameData.readyForFence, time_now_d());
std::unique_lock<std::mutex> lock(frameData.fenceMutex);
@ -417,6 +427,10 @@ bool GLRenderManager::Run(GLRRenderThreadTask &task) {
}
}
if (frameData.profile.enabled) {
frameData.profile.cpuStartTime = time_now_d();
}
if (IsVREnabled()) {
int passes = GetVRPassesCount();
for (int i = 0; i < passes; i++) {
@ -428,6 +442,10 @@ bool GLRenderManager::Run(GLRRenderThreadTask &task) {
queueRunner_.RunSteps(task.steps, skipGLCalls_, false, false);
}
if (frameData.profile.enabled) {
frameData.profile.cpuEndTime = time_now_d();
}
if (!skipGLCalls_) {
for (auto iter : frameData.activePushBuffers) {
iter->MapDevice(bufferStrategy_);

View file

@ -409,8 +409,10 @@ public:
caps_ = caps;
}
std::string GetGpuProfileString() const;
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
void BeginFrame();
void BeginFrame(bool enableProfiling);
// Can run on a different thread!
void Finish();

View file

@ -328,6 +328,9 @@ public:
DrawContext::SetTargetSize(w, h);
renderManager_.Resize(w, h);
}
void SetDebugFlags(DebugFlags flags) override {
debugFlags_ = flags;
}
const DeviceCaps &GetDeviceCaps() const override {
return caps_;
@ -514,6 +517,8 @@ private:
GLPushBuffer *push;
};
FrameData frameData_[GLRenderManager::MAX_INFLIGHT_FRAMES]{};
DebugFlags debugFlags_ = DebugFlags::NONE;
};
static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) {
@ -778,7 +783,7 @@ OpenGLContext::~OpenGLContext() {
}
void OpenGLContext::BeginFrame() {
renderManager_.BeginFrame();
renderManager_.BeginFrame(debugFlags_ & DebugFlags::PROFILE_TIMESTAMPS);
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
renderManager_.BeginPushBuffer(frameData.push);
}

View file

@ -257,6 +257,9 @@ public:
// cached framebuffers / textures / vertices?
// get content of specific framebuffer / texture?
// vertex / texture decoding?
// Note: Wanted to name it GetProfileString but clashes with a Windows API.
virtual std::string GetGpuProfileString() { return ""; }
};
bool GPUDebugInitExpression(GPUDebugInterface *g, const char *str, PostfixExpression &exp);

View file

@ -305,3 +305,8 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
shaderManagerGL_->GetNumPrograms()
);
}
std::string GPU_GLES::GetGpuProfileString() {
GLRenderManager *rm = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
return rm->GetGpuProfileString();
}

View file

@ -51,6 +51,8 @@ public:
void BeginHostFrame() override;
void EndHostFrame() override;
std::string GetGpuProfileString() override;
protected:
void FinishDeferred() override;

View file

@ -37,6 +37,8 @@
#include "GPU/Vulkan/VulkanUtil.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "Core/Config.h"
#undef DrawText
bool comparePushBufferNames(const VulkanMemoryManager *a, const VulkanMemoryManager *b) {
@ -107,9 +109,14 @@ void DrawGPUProfilerVis(UIContext *ui, GPUInterface *gpu) {
ui->Begin();
GPU_Vulkan *gpuVulkan = static_cast<GPU_Vulkan *>(gpu);
float scale = 0.4f;
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
// Don't have as much info, let's go bigger.
scale = 0.7f;
}
std::string text = gpuVulkan->GetGpuProfileString();
GPUCommon *gpuCommon = static_cast<GPUCommon *>(gpu);
std::string text = gpuCommon->GetGpuProfileString();
ui->SetFontScale(0.4f, 0.4f);
ui->DrawTextShadow(text.c_str(), x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);

View file

@ -59,7 +59,7 @@ public:
return textureCacheVulkan_;
}
std::string GetGpuProfileString();
std::string GetGpuProfileString() override;
protected:
void FinishDeferred() override;

View file

@ -102,6 +102,8 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) {
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.bShowGpuProfile, dev->T("GPU Profile")));
}
items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenuScreen::OnFreezeFrame);

View file

@ -1616,7 +1616,7 @@ void EmuScreen::renderUI() {
DrawAllocatorVis(ctx, gpu);
}
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowGpuProfile) {
if ((g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) && g_Config.bShowGpuProfile) {
DrawGPUProfilerVis(ctx, gpu);
}