diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a6a53a1..1a7e07f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/imgui/imgui_layer.h b/src/imgui/imgui_layer.h new file mode 100644 index 000000000..a6c7e2a4a --- /dev/null +++ b/src/imgui/imgui_layer.h @@ -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 \ No newline at end of file diff --git a/src/imgui/layer/video_info.cpp b/src/imgui/layer/video_info.cpp new file mode 100644 index 000000000..15226cd8c --- /dev/null +++ b/src/imgui/layer/video_info.cpp @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#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(); + } +} diff --git a/src/imgui/layer/video_info.h b/src/imgui/layer/video_info.h new file mode 100644 index 000000000..8eec972a8 --- /dev/null +++ b/src/imgui/layer/video_info.h @@ -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 diff --git a/src/imgui_renderer/imgui_core.cpp b/src/imgui/renderer/imgui_core.cpp similarity index 74% rename from src/imgui_renderer/imgui_core.cpp rename to src/imgui/renderer/imgui_core.cpp index 7ef93db53..41b7add99 100644 --- a/src/imgui_renderer/imgui_core.cpp +++ b/src/imgui/renderer/imgui_core.cpp @@ -4,6 +4,7 @@ #include #include #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 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> 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 diff --git a/src/imgui_renderer/imgui_core.h b/src/imgui/renderer/imgui_core.h similarity index 91% rename from src/imgui_renderer/imgui_core.h rename to src/imgui/renderer/imgui_core.h index 517a7eb49..9ad708f81 100644 --- a/src/imgui_renderer/imgui_core.h +++ b/src/imgui/renderer/imgui_core.h @@ -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 diff --git a/src/imgui_renderer/imgui_impl_sdl3.cpp b/src/imgui/renderer/imgui_impl_sdl3.cpp similarity index 99% rename from src/imgui_renderer/imgui_impl_sdl3.cpp rename to src/imgui/renderer/imgui_impl_sdl3.cpp index 66ad8a347..2a7d801e4 100644 --- a/src/imgui_renderer/imgui_impl_sdl3.cpp +++ b/src/imgui/renderer/imgui_impl_sdl3.cpp @@ -15,7 +15,7 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif -#include +#include #endif namespace ImGui::Sdl { diff --git a/src/imgui_renderer/imgui_impl_sdl3.h b/src/imgui/renderer/imgui_impl_sdl3.h similarity index 100% rename from src/imgui_renderer/imgui_impl_sdl3.h rename to src/imgui/renderer/imgui_impl_sdl3.h diff --git a/src/imgui_renderer/imgui_impl_vulkan.cpp b/src/imgui/renderer/imgui_impl_vulkan.cpp similarity index 100% rename from src/imgui_renderer/imgui_impl_vulkan.cpp rename to src/imgui/renderer/imgui_impl_vulkan.cpp diff --git a/src/imgui_renderer/imgui_impl_vulkan.h b/src/imgui/renderer/imgui_impl_vulkan.h similarity index 96% rename from src/imgui_renderer/imgui_impl_vulkan.h rename to src/imgui/renderer/imgui_impl_vulkan.h index dbde66a80..e68b8723f 100644 --- a/src/imgui_renderer/imgui_impl_vulkan.h +++ b/src/imgui/renderer/imgui_impl_vulkan.h @@ -6,7 +6,7 @@ #pragma once #define VULKAN_HPP_NO_EXCEPTIONS -#include +#include "video_core/renderer_vulkan/vk_common.h" struct ImDrawData; diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 5a5e1c79a..8b73a3980 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -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) { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 91ff9a9c3..6416acfb5 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -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(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, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index eab9d527c..c8e566418 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -4,6 +4,8 @@ #pragma once #include + +#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 splash_img; std::vector vo_buffers_addr; + + ImGui::Layers::VideoInfo video_info_ui; }; } // namespace Vulkan