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
)
set(IMGUI src/imgui_renderer/imgui_core.cpp
src/imgui_renderer/imgui_core.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(IMGUI src/imgui/imgui_layer.h
src/imgui/layer/video_info.cpp
src/imgui/layer/video_info.h
src/imgui/renderer/imgui_core.cpp
src/imgui/renderer/imgui_core.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

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 <imgui.h>
#include "common/config.h"
#include "imgui/imgui_layer.h"
#include "imgui_core.h"
#include "imgui_impl_sdl3.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));
}
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,
const u32 image_count, vk::Format surface_format,
const vk::AllocationCallbacks* allocator) {
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
CreateContext();
ImGuiIO& io = GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.DisplaySize = ImVec2((float)window.getWidth(), (float)window.getHeight());
ImGui::StyleColorsDark();
StyleColorsDark();
Sdl::Init(window.GetSdlWindow());
Vulkan::InitInfo vk_info{
const Vulkan::InitInfo vk_info{
.instance = instance.GetInstance(),
.physical_device = instance.GetPhysicalDevice(),
.device = instance.GetDevice(),
@ -48,7 +59,6 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
}
void OnResize() {
ImGuiIO& io = ImGui::GetIO();
Sdl::OnResize();
}
@ -57,11 +67,11 @@ void Shutdown(const vk::Device& device) {
Vulkan::Shutdown();
Sdl::Shutdown();
ImGui::DestroyContext();
DestroyContext();
}
bool ProcessEvent(SDL_Event* event) {
bool used = Sdl::ProcessEvent(event);
const bool used = Sdl::ProcessEvent(event);
if (!used) {
return false;
}
@ -70,34 +80,43 @@ bool ProcessEvent(SDL_Event* event) {
case SDL_EVENT_MOUSE_WHEEL:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
return ImGui::GetIO().WantCaptureMouse;
return GetIO().WantCaptureMouse;
case SDL_EVENT_TEXT_INPUT:
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
return ImGui::GetIO().WantCaptureKeyboard;
return GetIO().WantCaptureKeyboard;
default:
return false;
}
}
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();
Sdl::NewFrame();
const auto& io = ImGui::GetIO();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
if (ImGui::Begin("Frame timings")) {
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate,
io.Framerate);
ImGui::End();
for (auto* layer : layers) {
layer->Draw();
}
}
void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
ImDrawData* draw_data = GetDrawData();
if (draw_data->CmdListsCount == 0) {
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;
}
namespace ImGui::Emulator {
namespace ImGui::Core {
void Initialize(const Vulkan::Instance& instance, const Frontend::WindowSDL& window,
u32 image_count, vk::Format surface_format,
@ -28,4 +28,4 @@ void NewFrame();
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
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <Windows.h>
#endif
namespace ImGui::Sdl {

View file

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

View file

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

View file

@ -6,7 +6,7 @@
#include "common/singleton.h"
#include "core/file_format/splash.h"
#include "core/libraries/system/systemservice.h"
#include "imgui_renderer/imgui_core.h"
#include "imgui/renderer/imgui_core.h"
#include "sdl_window.h"
#include "video_core/renderer_vulkan/renderer_vulkan.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},
swapchain{instance, window},
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 vk::Device device = instance.GetDevice();
@ -87,10 +87,12 @@ RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool*
}
// 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() {
ImGui::Layer::RemoveLayer(&video_info_ui);
draw_scheduler.Finish();
const vk::Device device = instance.GetDevice();
for (auto& frame : present_frames) {
@ -98,7 +100,7 @@ RendererVulkan::~RendererVulkan() {
device.destroyImageView(frame.image_view);
device.destroyFence(frame.present_done);
}
ImGui::Emulator::Shutdown(device);
ImGui::Core::Shutdown(device);
}
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) {
ImGui::Emulator::NewFrame();
ImGui::Core::NewFrame();
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,
vk::PipelineStageFlagBits::eTransfer,

View file

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