shadPS4/src/imgui/renderer/imgui_core.cpp
Vinicius Rangel 49ceff71a2
Devtools fixes1 (#1228)
* imgui: fix nav with dock & fps display disabled by default

* devtools: change basic fps scale

* imgui: scale font with display dpi
2024-10-04 06:44:36 +03:00

243 lines
7.7 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <SDL3/SDL_events.h>
#include <imgui.h>
#include "common/config.h"
#include "common/path_util.h"
#include "core/devtools/layer.h"
#include "imgui/imgui_layer.h"
#include "imgui_core.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_vulkan.h"
#include "imgui_internal.h"
#include "sdl_window.h"
#include "texture_manager.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "imgui_fonts/notosansjp_regular.ttf.g.cpp"
#include "imgui_fonts/proggyvector_regular.ttf.g.cpp"
static void CheckVkResult(const vk::Result err) {
LOG_ERROR(ImGui, "Vulkan error {}", vk::to_string(err));
}
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.
std::deque<std::pair<bool, ImGui::Layer*>>& GetChangeLayers() {
static std::deque<std::pair<bool, ImGui::Layer*>>* change_layers =
new std::deque<std::pair<bool, ImGui::Layer*>>;
return *change_layers;
}
static std::mutex change_layers_mutex{};
static ImGuiID dock_id;
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) {
const auto config_path = GetUserPath(Common::FS::PathType::UserDir) / "imgui.ini";
const auto log_path = GetUserPath(Common::FS::PathType::LogDir) / "imgui_log.txt";
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::PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f); // Makes the window edges rounded
auto path = config_path.u8string();
char* config_file_buf = new char[path.size() + 1]();
std::memcpy(config_file_buf, path.c_str(), path.size());
io.IniFilename = config_file_buf;
path = log_path.u8string();
char* log_file_buf = new char[path.size() + 1]();
std::memcpy(log_file_buf, path.c_str(), path.size());
io.LogFilename = log_file_buf;
ImFontGlyphRangesBuilder rb{};
rb.AddRanges(io.Fonts->GetGlyphRangesDefault());
rb.AddRanges(io.Fonts->GetGlyphRangesGreek());
rb.AddRanges(io.Fonts->GetGlyphRangesKorean());
rb.AddRanges(io.Fonts->GetGlyphRangesJapanese());
rb.AddRanges(io.Fonts->GetGlyphRangesCyrillic());
ImVector<ImWchar> ranges{};
rb.BuildRanges(&ranges);
ImFontConfig font_cfg{};
font_cfg.OversampleH = 2;
font_cfg.OversampleV = 1;
io.FontDefault = io.Fonts->AddFontFromMemoryCompressedTTF(
imgui_font_notosansjp_regular_compressed_data,
imgui_font_notosansjp_regular_compressed_size, 16.0f, &font_cfg, ranges.Data);
io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_proggyvector_regular_compressed_data,
imgui_font_proggyvector_regular_compressed_size,
16.0f);
StyleColorsDark();
::Core::Devtools::Layer::SetupSettings();
Sdl::Init(window.GetSdlWindow());
const Vulkan::InitInfo vk_info{
.instance = instance.GetInstance(),
.physical_device = instance.GetPhysicalDevice(),
.device = instance.GetDevice(),
.queue_family = instance.GetPresentQueueFamilyIndex(),
.queue = instance.GetPresentQueue(),
.image_count = image_count,
.min_allocation_size = 1024 * 1024,
.pipeline_rendering_create_info{
.colorAttachmentCount = 1,
.pColorAttachmentFormats = &surface_format,
},
.allocator = allocator,
.check_vk_result_fn = &CheckVkResult,
};
Vulkan::Init(vk_info);
TextureManager::StartWorker();
char label[32];
ImFormatString(label, IM_ARRAYSIZE(label), "WindowOverViewport_%08X", GetMainViewport()->ID);
dock_id = ImHashStr(label);
if (const auto dpi = SDL_GetWindowDisplayScale(window.GetSdlWindow()); dpi > 0.0f) {
GetIO().FontGlobalScale = dpi;
}
}
void OnResize() {
Sdl::OnResize();
}
void Shutdown(const vk::Device& device) {
auto result = device.waitIdle();
if (result != vk::Result::eSuccess) {
LOG_WARNING(ImGui, "Failed to wait for Vulkan device idle on shutdown: {}",
vk::to_string(result));
}
TextureManager::StopWorker();
const ImGuiIO& io = GetIO();
const auto ini_filename = (void*)io.IniFilename;
const auto log_filename = (void*)io.LogFilename;
Vulkan::Shutdown();
Sdl::Shutdown();
DestroyContext();
delete[] (char*)ini_filename;
delete[] (char*)log_filename;
}
bool ProcessEvent(SDL_Event* event) {
Sdl::ProcessEvent(event);
switch (event->type) {
// Don't block release/up events
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_WHEEL:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
return GetIO().WantCaptureMouse;
case SDL_EVENT_TEXT_INPUT:
case SDL_EVENT_KEY_DOWN:
return GetIO().WantCaptureKeyboard;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: {
const auto& io = GetIO();
return io.NavActive && io.Ctx->NavWindow != nullptr && io.Ctx->NavWindow->ID != dock_id;
}
default:
return false;
}
}
void NewFrame() {
{
std::scoped_lock lock{change_layers_mutex};
while (!GetChangeLayers().empty()) {
const auto [to_be_added, layer] = GetChangeLayers().front();
if (to_be_added) {
layers.push_back(layer);
} else {
const auto [begin, end] = std::ranges::remove(layers, layer);
layers.erase(begin, end);
}
GetChangeLayers().pop_front();
}
}
Sdl::NewFrame();
ImGui::NewFrame();
DockSpaceOverViewport(0, GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
for (auto* layer : layers) {
layer->Draw();
}
}
void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
ImGui::Render();
ImDrawData* draw_data = GetDrawData();
if (draw_data->CmdListsCount == 0) {
return;
}
if (Config::vkMarkersEnabled()) {
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = "ImGui Render",
});
}
vk::RenderingAttachmentInfo color_attachments[1]{
{
.imageView = frame->image_view,
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
.loadOp = vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
},
};
vk::RenderingInfo render_info = {};
render_info.renderArea = vk::Rect2D{
.offset = {0, 0},
.extent = {frame->width, frame->height},
};
render_info.layerCount = 1;
render_info.colorAttachmentCount = 1;
render_info.pColorAttachments = color_attachments;
cmdbuf.beginRendering(render_info);
Vulkan::RenderDrawData(*draw_data, cmdbuf);
cmdbuf.endRendering();
if (Config::vkMarkersEnabled()) {
cmdbuf.endDebugUtilsLabelEXT();
}
}
} // namespace Core
void Layer::AddLayer(Layer* layer) {
std::scoped_lock lock{change_layers_mutex};
GetChangeLayers().emplace_back(true, layer);
}
void Layer::RemoveLayer(Layer* layer) {
std::scoped_lock lock{change_layers_mutex};
GetChangeLayers().emplace_back(false, layer);
}
} // namespace ImGui