shadPS4/src/core/devtools/widget/frame_graph.cpp
Vinicius Rangel f663176a5d
FidelityFX FSR implementation (#2624)
* host_shaders: support for includes

* video_core: add a simpler vulkan asserts

* video_core: refactored post processing pipeline to another file

* renderer_vulkan: add define param to compile shader utility

* video_core: fsr implementation

* devtools: show resolution & fsr state
2025-03-12 20:33:30 +02:00

110 lines
3.9 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "frame_graph.h"
#include "common/config.h"
#include "common/singleton.h"
#include "core/debug_state.h"
#include "imgui.h"
#include "imgui_internal.h"
using namespace ImGui;
namespace Core::Devtools::Widget {
constexpr float TARGET_FPS = 60.0f;
constexpr float BAR_WIDTH_MULT = 1.4f;
constexpr float BAR_HEIGHT_MULT = 1.25f;
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
constexpr static float FRAME_GRAPH_HEIGHT = 50.0f;
void FrameGraph::DrawFrameGraph() {
// Frame graph - inspired by
// https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
const float full_width = GetContentRegionAvail().x;
auto pos = GetCursorScreenPos();
const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f};
ItemSize(size);
if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) {
return;
}
float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv());
float cur_pos_x = pos.x + full_width;
pos.y += FRAME_GRAPH_PADDING_Y;
const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT;
auto& draw_list = *GetWindowDrawList();
draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y},
{pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y},
IM_COL32(0x33, 0x33, 0x33, 0xFF));
draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true);
for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) {
const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE];
const float dt_factor = target_dt / frame_info.delta;
const float width = std::ceil(BAR_WIDTH_MULT / dt_factor);
const float height =
std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT;
ImU32 color;
if (dt_factor >= 0.95f) { // BLUE
color = IM_COL32(0x33, 0x33, 0xFF, 0xFF);
} else if (dt_factor >= 0.5f) { // GREEN <> YELLOW
float t = 1.0f - (dt_factor - 0.5f) * 2.0f;
int r = (int)(0xFF * t);
color = IM_COL32(r, 0xFF, 0, 0xFF);
} else { // YELLOW <> RED
float t = dt_factor * 2.0f;
int g = (int)(0xFF * t);
color = IM_COL32(0xFF, g, 0, 0xFF);
}
draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height}, {cur_pos_x, final_pos_y},
color);
cur_pos_x -= width;
if (cur_pos_x < width) {
break;
}
}
draw_list.PopClipRect();
}
void FrameGraph::Draw() {
if (!is_open) {
return;
}
SetNextWindowSize({308.0, 270.0f}, ImGuiCond_FirstUseEver);
if (Begin("Video debug info", &is_open)) {
const auto& ctx = *GImGui;
const auto& io = ctx.IO;
const auto& window = *ctx.CurrentWindow;
auto& draw_list = *window.DrawList;
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
if (!isSystemPaused) {
deltaTime = DebugState.FrameDeltaTime * 1000.0f;
frameRate = 1000.0f / deltaTime;
}
SeparatorText("Frame graph");
DrawFrameGraph();
SeparatorText("Renderer info");
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
Text("Presenter time: %.3f ms (%.1f FPS)", io.DeltaTime * 1000.0f, 1.0f / io.DeltaTime);
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
DebugState.gnm_frame_count.load());
Text("Game Res: %dx%d", DebugState.game_resolution.first,
DebugState.game_resolution.second);
Text("Output Res: %dx%d", DebugState.output_resolution.first,
DebugState.output_resolution.second);
Text("FSR: %s", DebugState.is_using_fsr ? "on" : "off");
}
End();
}
} // namespace Core::Devtools::Widget