From a4c3c665fe381e422a7607a85d6e46187569afec Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Sun, 2 Nov 2025 14:55:43 -0300 Subject: [PATCH] add null gpu notice (#3768) --- CMakeLists.txt | 1 + src/core/devtools/layer.cpp | 10 +- src/core/devtools/layer.h | 20 ++-- src/core/devtools/layer_extra.cpp | 95 +++++++++++++++++++ src/imgui/imgui_std.h | 3 + src/imgui/renderer/imgui_core.cpp | 11 ++- .../renderer_vulkan/vk_presenter.cpp | 71 +++++++------- 7 files changed, 160 insertions(+), 51 deletions(-) create mode 100644 src/core/devtools/layer_extra.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bfbc81f0e..7f6144bc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -617,6 +617,7 @@ set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp ) set(DEV_TOOLS src/core/devtools/layer.cpp src/core/devtools/layer.h + src/core/devtools/layer_extra.cpp src/core/devtools/options.cpp src/core/devtools/options.h src/core/devtools/gcn/gcn_context_regs.cpp diff --git a/src/core/devtools/layer.cpp b/src/core/devtools/layer.cpp index 5b323da7c..1fb810030 100644 --- a/src/core/devtools/layer.cpp +++ b/src/core/devtools/layer.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "layer.h" @@ -460,12 +460,12 @@ void L::Draw() { } void L::TextCentered(const std::string& text) { - float window_width = ImGui::GetWindowSize().x; - float text_width = ImGui::CalcTextSize(text.c_str()).x; + float window_width = GetWindowSize().x; + float text_width = CalcTextSize(text.c_str()).x; float text_indentation = (window_width - text_width) * 0.5f; - ImGui::SameLine(text_indentation); - ImGui::Text("%s", text.c_str()); + SameLine(text_indentation); + Text("%s", text.c_str()); } namespace Overlay { diff --git a/src/core/devtools/layer.h b/src/core/devtools/layer.h index 8abd52f2f..44afc95bc 100644 --- a/src/core/devtools/layer.h +++ b/src/core/devtools/layer.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -9,18 +9,20 @@ namespace Core::Devtools { class Layer final : public ImGui::Layer { - - static void DrawMenuBar(); - - static void DrawAdvanced(); - - static void DrawSimple(); - public: static void SetupSettings(); void Draw() override; - void TextCentered(const std::string& text); + + // Must be inside a window + static void DrawNullGpuNotice(); + +private: + static void DrawMenuBar(); + static void DrawAdvanced(); + static void DrawSimple(); + + static void TextCentered(const std::string& text); }; } // namespace Core::Devtools diff --git a/src/core/devtools/layer_extra.cpp b/src/core/devtools/layer_extra.cpp new file mode 100644 index 000000000..d5e55302d --- /dev/null +++ b/src/core/devtools/layer_extra.cpp @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "layer.h" + +#include "imgui/imgui_std.h" + +#include +#include + +#include +#include + +namespace Core::Devtools { + +void Layer::DrawNullGpuNotice() { + + auto* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) { + return; + } + + constexpr std::string_view mainNotice = "Null GPU is enabled"; + constexpr std::string_view detailsNotice = + "Disable the nullGpu config to show the game display"; + + auto displaySize = window->Size; + + ImVec2 targetSize = displaySize * 0.7f; + + float minFontSize = 1.0f; + float maxFontSize = 200.0f; + float optimalFontSize = minFontSize; + + static auto lastSize = ImVec2(-1, -1); + static float lastFontSize = -1.0f; + + auto* font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT_BIG]; + + if (lastSize != targetSize) { + while (maxFontSize - minFontSize > 0.1f) { + float testFontSize = (minFontSize + maxFontSize) / 2.0f; + + ImVec2 textSize = font->CalcTextSizeA(testFontSize, FLT_MAX, 0.0f, &mainNotice.front(), + &mainNotice.back() + 1); + + if (textSize.x <= targetSize.x && textSize.y <= targetSize.y) { + optimalFontSize = testFontSize; + minFontSize = testFontSize; + } else { + maxFontSize = testFontSize; + } + } + lastSize = targetSize; + lastFontSize = optimalFontSize; + } else { + optimalFontSize = lastFontSize; + } + ImVec2 textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &mainNotice.front(), + &mainNotice.back() + 1); + + ImVec2 textPos = (displaySize - textSize) * 0.5f + window->Pos; + + const float scale = optimalFontSize / font->FontSize; + double timeAnim = -std::numbers::pi * ImGui::GetTime(); + int i = 0; + for (auto ch : mainNotice) { + double colorTime = sin(timeAnim + i * std::numbers::pi / 6.0) / 2.0 + 0.5; + int color = (int)(200 * colorTime) + 55; + + double posTime = sin(timeAnim + i * std::numbers::pi / 15.0) / 2.0 + 0.5; + + auto pos = textPos; + pos.y += 10.0 * (posTime < 0.5 ? std::pow(2.0, 20.0 * posTime - 10.0) / 2.0 + : (2.0 - std::pow(2.0, -20.0 * posTime + 10.0)) / 2.0); + + window->DrawList->AddText(font, optimalFontSize, pos, IM_COL32(color, color, color, 255), + &ch, &ch + 1); + textPos.x += font->FindGlyph(ch)->AdvanceX * scale; + i++; + } + + font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT]; + + textPos.y += textSize.y + 1.0; + + optimalFontSize *= 0.2; + textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &detailsNotice.front(), + &detailsNotice.back() + 1); + textPos.x = window->Pos.x + (window->Size.x - textSize.x) * 0.5f; + window->DrawList->AddText(font, optimalFontSize, textPos, IM_COL32(200, 200, 200, 255), + &detailsNotice.front(), &detailsNotice.back() + 1); +} + +} // namespace Core::Devtools diff --git a/src/imgui/imgui_std.h b/src/imgui/imgui_std.h index 986a3e24f..821ef1568 100644 --- a/src/imgui/imgui_std.h +++ b/src/imgui/imgui_std.h @@ -3,6 +3,8 @@ #pragma once +#include "common/types.h" + #include #include @@ -12,6 +14,7 @@ #define IMGUI_FONT_TEXT 0 #define IMGUI_FONT_MONO 1 +#define IMGUI_FONT_TEXT_BIG 2 namespace ImGui { diff --git a/src/imgui/renderer/imgui_core.cpp b/src/imgui/renderer/imgui_core.cpp index d143232dc..f82612444 100644 --- a/src/imgui/renderer/imgui_core.cpp +++ b/src/imgui/renderer/imgui_core.cpp @@ -76,10 +76,15 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w 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); + imgui_font_notosansjp_regular_compressed_size, 32.0f, &font_cfg, ranges.Data); io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_proggyvector_regular_compressed_data, imgui_font_proggyvector_regular_compressed_size, - 16.0f); + 32.0f); + io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_notosansjp_regular_compressed_data, + imgui_font_notosansjp_regular_compressed_size, 128.0f, + &font_cfg, ranges.Data); + + io.FontGlobalScale = 0.5f; StyleColorsDark(); @@ -110,7 +115,7 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w dock_id = ImHashStr(label); if (const auto dpi = SDL_GetWindowDisplayScale(window.GetSDLWindow()); dpi > 0.0f) { - GetIO().FontGlobalScale = dpi; + GetIO().FontGlobalScale *= dpi; } std::at_quick_exit([] { SaveIniSettingsToDisk(GetIO().IniFilename); }); diff --git a/src/video_core/renderer_vulkan/vk_presenter.cpp b/src/video_core/renderer_vulkan/vk_presenter.cpp index ac6b2b994..1694d137f 100644 --- a/src/video_core/renderer_vulkan/vk_presenter.cpp +++ b/src/video_core/renderer_vulkan/vk_presenter.cpp @@ -539,45 +539,48 @@ void Presenter::Present(Frame* frame, bool is_reusing_frame) { ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); ImGui::SetNextWindowDockID(dockId, ImGuiCond_Once); - ImGui::Begin("Display##game_display", nullptr, ImGuiWindowFlags_NoNav); + if (ImGui::Begin("Display##game_display", nullptr, ImGuiWindowFlags_NoNav)) { + auto game_texture = frame->imgui_texture; + auto game_width = frame->width; + auto game_height = frame->height; - auto game_texture = frame->imgui_texture; - auto game_width = frame->width; - auto game_height = frame->height; - - if (Libraries::SystemService::IsSplashVisible()) { // draw splash - if (!splash_img.has_value()) { - splash_img.emplace(); - auto splash_path = Common::ElfInfo::Instance().GetSplashPath(); - if (!splash_path.empty()) { - splash_img = ImGui::RefCountedTexture::DecodePngFile(splash_path); + if (Libraries::SystemService::IsSplashVisible()) { // draw splash + if (!splash_img.has_value()) { + splash_img.emplace(); + auto splash_path = Common::ElfInfo::Instance().GetSplashPath(); + if (!splash_path.empty()) { + splash_img = ImGui::RefCountedTexture::DecodePngFile(splash_path); + } + } + if (auto& splash_image = this->splash_img.value()) { + auto [im_id, width, height] = splash_image.GetTexture(); + game_texture = im_id; + game_width = width; + game_height = height; } } - if (auto& splash_image = this->splash_img.value()) { - auto [im_id, width, height] = splash_image.GetTexture(); - game_texture = im_id; - game_width = width; - game_height = height; + + ImVec2 contentArea = ImGui::GetContentRegionAvail(); + SetExpectedGameSize((s32)contentArea.x, (s32)contentArea.y); + + const auto imgRect = + FitImage(game_width, game_height, (s32)contentArea.x, (s32)contentArea.y); + ImVec2 offset{ + static_cast(imgRect.offset.x), + static_cast(imgRect.offset.y), + }; + ImVec2 size{ + static_cast(imgRect.extent.width), + static_cast(imgRect.extent.height), + }; + + ImGui::SetCursorPos(ImGui::GetCursorStartPos() + offset); + ImGui::Image(game_texture, size); + + if (Config::nullGpu()) { + Core::Devtools::Layer::DrawNullGpuNotice(); } } - - ImVec2 contentArea = ImGui::GetContentRegionAvail(); - SetExpectedGameSize((s32)contentArea.x, (s32)contentArea.y); - - const auto imgRect = - FitImage(game_width, game_height, (s32)contentArea.x, (s32)contentArea.y); - ImVec2 offset{ - static_cast(imgRect.offset.x), - static_cast(imgRect.offset.y), - }; - ImVec2 size{ - static_cast(imgRect.extent.width), - static_cast(imgRect.extent.height), - }; - - ImGui::SetCursorPos(ImGui::GetCursorStartPos() + offset); - ImGui::Image(game_texture, size); - ImGui::End(); ImGui::PopStyleVar(3); ImGui::PopStyleColor();