imgui: add layers system

Add video info layer to show fps. Press F10 to toggle it.
This commit is contained in:
Vinicius Rangel 2024-09-02 18:43:08 -03:00
parent de08bbc75d
commit 60d8f41181
No known key found for this signature in database
GPG Key ID: A5B154D904B761D9
13 changed files with 134 additions and 38 deletions

View File

@ -561,12 +561,15 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderdoc.h src/video_core/renderdoc.h
) )
set(IMGUI src/imgui_renderer/imgui_core.cpp set(IMGUI src/imgui/imgui_layer.h
src/imgui_renderer/imgui_core.h src/imgui/layer/video_info.cpp
src/imgui_renderer/imgui_impl_sdl3.cpp src/imgui/layer/video_info.h
src/imgui_renderer/imgui_impl_sdl3.h src/imgui/renderer/imgui_core.cpp
src/imgui_renderer/imgui_impl_vulkan.cpp src/imgui/renderer/imgui_core.h
src/imgui_renderer/imgui_impl_vulkan.h src/imgui/renderer/imgui_impl_sdl3.cpp
src/imgui/renderer/imgui_impl_sdl3.h
src/imgui/renderer/imgui_impl_vulkan.cpp
src/imgui/renderer/imgui_impl_vulkan.h
) )
set(INPUT src/input/controller.cpp set(INPUT src/input/controller.cpp

17
src/imgui/imgui_layer.h Normal file
View File

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace ImGui {
class Layer {
public:
virtual ~Layer() = default;
static void AddLayer(Layer* layer);
static void RemoveLayer(Layer* layer);
virtual void Draw() = 0;
};
} // namespace ImGui

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <imgui.h>
#include "video_info.h"
void ImGui::Layers::VideoInfo::Draw() {
const ImGuiIO& io = GetIO();
m_show = IsKeyPressed(ImGuiKey_F10, false) ^ m_show;
if (m_show && Begin("Video Info")) {
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
End();
}
}

View File

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "imgui/imgui_layer.h"
namespace Vulkan {
class RendererVulkan;
}
namespace ImGui::Layers {
class VideoInfo : public Layer {
bool m_show = false;
::Vulkan::RendererVulkan* renderer{};
public:
explicit VideoInfo(::Vulkan::RendererVulkan* renderer) : renderer(renderer) {}
void Draw() override;
};
} // namespace ImGui::Layers

View File

@ -4,6 +4,7 @@
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <imgui.h> #include <imgui.h>
#include "common/config.h" #include "common/config.h"
#include "imgui/imgui_layer.h"
#include "imgui_core.h" #include "imgui_core.h"
#include "imgui_impl_sdl3.h" #include "imgui_impl_sdl3.h"
#include "imgui_impl_vulkan.h" #include "imgui_impl_vulkan.h"
@ -14,22 +15,32 @@ static void CheckVkResult(const vk::Result err) {
LOG_ERROR(ImGui, "Vulkan error {}", vk::to_string(err)); LOG_ERROR(ImGui, "Vulkan error {}", vk::to_string(err));
} }
namespace ImGui::Emulator { static std::vector<ImGui::Layer*> layers;
// Update layers before rendering to allow layer changes to be applied during rendering.
// Using deque to keep the order of changes in case a Layer is removed then added again between
// frames.
static std::deque<std::pair<bool, ImGui::Layer*>> change_layers;
static std::mutex change_layers_mutex{};
namespace ImGui {
namespace Core {
void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& window, void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& window,
const u32 image_count, vk::Format surface_format, const u32 image_count, vk::Format surface_format,
const vk::AllocationCallbacks* allocator) { const vk::AllocationCallbacks* allocator) {
ImGui::CreateContext(); CreateContext();
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.DisplaySize = ImVec2((float)window.getWidth(), (float)window.getHeight()); io.DisplaySize = ImVec2((float)window.getWidth(), (float)window.getHeight());
ImGui::StyleColorsDark(); StyleColorsDark();
Sdl::Init(window.GetSdlWindow()); Sdl::Init(window.GetSdlWindow());
Vulkan::InitInfo vk_info{ const Vulkan::InitInfo vk_info{
.instance = instance.GetInstance(), .instance = instance.GetInstance(),
.physical_device = instance.GetPhysicalDevice(), .physical_device = instance.GetPhysicalDevice(),
.device = instance.GetDevice(), .device = instance.GetDevice(),
@ -48,7 +59,6 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
} }
void OnResize() { void OnResize() {
ImGuiIO& io = ImGui::GetIO();
Sdl::OnResize(); Sdl::OnResize();
} }
@ -57,11 +67,11 @@ void Shutdown(const vk::Device& device) {
Vulkan::Shutdown(); Vulkan::Shutdown();
Sdl::Shutdown(); Sdl::Shutdown();
ImGui::DestroyContext(); DestroyContext();
} }
bool ProcessEvent(SDL_Event* event) { bool ProcessEvent(SDL_Event* event) {
bool used = Sdl::ProcessEvent(event); const bool used = Sdl::ProcessEvent(event);
if (!used) { if (!used) {
return false; return false;
} }
@ -70,34 +80,43 @@ bool ProcessEvent(SDL_Event* event) {
case SDL_EVENT_MOUSE_WHEEL: case SDL_EVENT_MOUSE_WHEEL:
case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_UP:
return ImGui::GetIO().WantCaptureMouse; return GetIO().WantCaptureMouse;
case SDL_EVENT_TEXT_INPUT: case SDL_EVENT_TEXT_INPUT:
case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP: case SDL_EVENT_KEY_UP:
return ImGui::GetIO().WantCaptureKeyboard; return GetIO().WantCaptureKeyboard;
default: default:
return false; return false;
} }
} }
void NewFrame() { void NewFrame() {
{
std::scoped_lock lock{change_layers_mutex};
while (!change_layers.empty()) {
const auto [to_be_added, layer] = change_layers.front();
if (to_be_added) {
layers.push_back(layer);
} else {
const auto [begin, end] = std::ranges::remove(layers, layer);
layers.erase(begin, end);
}
change_layers.pop_front();
}
}
Vulkan::NewFrame(); Vulkan::NewFrame();
Sdl::NewFrame(); Sdl::NewFrame();
const auto& io = ImGui::GetIO();
ImGui::NewFrame(); ImGui::NewFrame();
ImGui::ShowDemoWindow(); for (auto* layer : layers) {
if (ImGui::Begin("Frame timings")) { layer->Draw();
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate,
io.Framerate);
ImGui::End();
} }
} }
void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) { void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
ImGui::Render(); ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData(); ImDrawData* draw_data = GetDrawData();
if (draw_data->CmdListsCount == 0) { if (draw_data->CmdListsCount == 0) {
return; return;
} }
@ -150,4 +169,16 @@ void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
} }
} }
} // namespace ImGui::Emulator } // namespace Core
void Layer::AddLayer(Layer* layer) {
std::scoped_lock lock{change_layers_mutex};
change_layers.emplace_back(true, layer);
}
void Layer::RemoveLayer(Layer* layer) {
std::scoped_lock lock{change_layers_mutex};
change_layers.emplace_back(false, layer);
}
} // namespace ImGui

View File

@ -12,7 +12,7 @@ namespace Vulkan {
struct Frame; struct Frame;
} }
namespace ImGui::Emulator { namespace ImGui::Core {
void Initialize(const Vulkan::Instance& instance, const Frontend::WindowSDL& window, void Initialize(const Vulkan::Instance& instance, const Frontend::WindowSDL& window,
u32 image_count, vk::Format surface_format, u32 image_count, vk::Format surface_format,
@ -28,4 +28,4 @@ void NewFrame();
void Render(const vk::CommandBuffer& cmdbuf, Vulkan::Frame* frame); void Render(const vk::CommandBuffer& cmdbuf, Vulkan::Frame* frame);
} // namespace ImGui::Emulator } // namespace ImGui::Core

View File

@ -15,7 +15,7 @@
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <Windows.h>
#endif #endif
namespace ImGui::Sdl { namespace ImGui::Sdl {

View File

@ -6,7 +6,7 @@
#pragma once #pragma once
#define VULKAN_HPP_NO_EXCEPTIONS #define VULKAN_HPP_NO_EXCEPTIONS
#include <video_core/renderer_vulkan/vk_common.h> #include "video_core/renderer_vulkan/vk_common.h"
struct ImDrawData; struct ImDrawData;

View File

@ -9,7 +9,7 @@
#include "common/config.h" #include "common/config.h"
#include "common/version.h" #include "common/version.h"
#include "core/libraries/pad/pad.h" #include "core/libraries/pad/pad.h"
#include "imgui_renderer/imgui_core.h" #include "imgui/renderer/imgui_core.h"
#include "input/controller.h" #include "input/controller.h"
#include "sdl_window.h" #include "sdl_window.h"
#include "video_core/renderdoc.h" #include "video_core/renderdoc.h"
@ -81,7 +81,7 @@ void WindowSDL::waitEvent() {
return; return;
} }
if (ImGui::Emulator::ProcessEvent(&event)) { if (ImGui::Core::ProcessEvent(&event)) {
return; return;
} }
@ -120,7 +120,7 @@ void WindowSDL::waitEvent() {
void WindowSDL::onResize() { void WindowSDL::onResize() {
SDL_GetWindowSizeInPixels(window, &width, &height); SDL_GetWindowSizeInPixels(window, &width, &height);
ImGui::Emulator::OnResize(); ImGui::Core::OnResize();
} }
void WindowSDL::onKeyPress(const SDL_Event* event) { void WindowSDL::onKeyPress(const SDL_Event* event) {

View File

@ -6,7 +6,7 @@
#include "common/singleton.h" #include "common/singleton.h"
#include "core/file_format/splash.h" #include "core/file_format/splash.h"
#include "core/libraries/system/systemservice.h" #include "core/libraries/system/systemservice.h"
#include "imgui_renderer/imgui_core.h" #include "imgui/renderer/imgui_core.h"
#include "sdl_window.h" #include "sdl_window.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_rasterizer.h"
@ -74,7 +74,7 @@ RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool*
draw_scheduler{instance}, present_scheduler{instance}, flip_scheduler{instance}, draw_scheduler{instance}, present_scheduler{instance}, flip_scheduler{instance},
swapchain{instance, window}, swapchain{instance, window},
rasterizer{std::make_unique<Rasterizer>(instance, draw_scheduler, liverpool)}, rasterizer{std::make_unique<Rasterizer>(instance, draw_scheduler, liverpool)},
texture_cache{rasterizer->GetTextureCache()} { texture_cache{rasterizer->GetTextureCache()}, video_info_ui{this} {
const u32 num_images = swapchain.GetImageCount(); const u32 num_images = swapchain.GetImageCount();
const vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
@ -87,10 +87,12 @@ RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool*
} }
// Setup ImGui // Setup ImGui
ImGui::Emulator::Initialize(instance, window, num_images, swapchain.GetSurfaceFormat().format); ImGui::Core::Initialize(instance, window, num_images, swapchain.GetSurfaceFormat().format);
ImGui::Layer::AddLayer(&video_info_ui);
} }
RendererVulkan::~RendererVulkan() { RendererVulkan::~RendererVulkan() {
ImGui::Layer::RemoveLayer(&video_info_ui);
draw_scheduler.Finish(); draw_scheduler.Finish();
const vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
for (auto& frame : present_frames) { for (auto& frame : present_frames) {
@ -98,7 +100,7 @@ RendererVulkan::~RendererVulkan() {
device.destroyImageView(frame.image_view); device.destroyImageView(frame.image_view);
device.destroyFence(frame.present_done); device.destroyFence(frame.present_done);
} }
ImGui::Emulator::Shutdown(device); ImGui::Core::Shutdown(device);
} }
void RendererVulkan::RecreateFrame(Frame* frame, u32 width, u32 height) { void RendererVulkan::RecreateFrame(Frame* frame, u32 width, u32 height) {
@ -259,7 +261,7 @@ Frame* RendererVulkan::PrepareFrameInternal(VideoCore::Image& image, bool is_eop
} }
void RendererVulkan::Present(Frame* frame) { void RendererVulkan::Present(Frame* frame) {
ImGui::Emulator::NewFrame(); ImGui::Core::NewFrame();
swapchain.AcquireNextImage(); swapchain.AcquireNextImage();
@ -324,7 +326,7 @@ void RendererVulkan::Present(Frame* frame) {
}, },
}; };
ImGui::Emulator::Render(cmdbuf, frame); ImGui::Core::Render(cmdbuf, frame);
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,

View File

@ -4,6 +4,8 @@
#pragma once #pragma once
#include <condition_variable> #include <condition_variable>
#include "imgui/layer/video_info.h"
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -103,6 +105,8 @@ private:
std::condition_variable_any frame_cv; std::condition_variable_any frame_cv;
std::optional<VideoCore::Image> splash_img; std::optional<VideoCore::Image> splash_img;
std::vector<VAddr> vo_buffers_addr; std::vector<VAddr> vo_buffers_addr;
ImGui::Layers::VideoInfo video_info_ui;
}; };
} // namespace Vulkan } // namespace Vulkan