mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-25 16:04:28 -04:00
New pipeline progress UI
This commit is contained in:
Vendored
+1
-1
Submodule extern/aurora updated: 509021de0a...e145b9ec20
@@ -275,7 +275,6 @@ struct UserSettings {
|
||||
ConfigVar<DiscVerificationState> isoVerification;
|
||||
ConfigVar<std::string> graphicsBackend;
|
||||
ConfigVar<bool> skipPreLaunchUI;
|
||||
ConfigVar<bool> showPipelineCompilation;
|
||||
ConfigVar<bool> wasPresetChosen;
|
||||
ConfigVar<bool> checkForUpdates;
|
||||
ConfigVar<int> cardFileType;
|
||||
|
||||
+52
-2
@@ -21,6 +21,7 @@ body {
|
||||
}
|
||||
|
||||
fps,
|
||||
pipeline-progress,
|
||||
toast {
|
||||
position: absolute;
|
||||
border: 1dp #92875B;
|
||||
@@ -98,7 +99,7 @@ toast message row.muted {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
toast progress {
|
||||
progress {
|
||||
height: 4dp;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@@ -106,10 +107,50 @@ toast progress {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
toast progress fill {
|
||||
progress fill {
|
||||
background-color: rgba(194, 164, 45, 80%);
|
||||
}
|
||||
|
||||
pipeline-progress {
|
||||
left: 12dp;
|
||||
bottom: 12dp;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
z-index: 100;
|
||||
min-width: 260dp;
|
||||
max-width: 90%;
|
||||
padding: 10dp 16dp 12dp;
|
||||
border-radius: 7dp;
|
||||
overflow: hidden;
|
||||
filter: opacity(0);
|
||||
transition: filter 0.2s linear-in-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
pipeline-progress[open] {
|
||||
filter: opacity(1);
|
||||
}
|
||||
|
||||
pipeline-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8dp;
|
||||
font-size: 18dp;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
icon.pipeline-spinner {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
line-height: 1.2em;
|
||||
font-size: 1.2em;
|
||||
color: #C2A42D;
|
||||
text-align: center;
|
||||
transform-origin: center;
|
||||
animation: 1s linear infinite pipeline-spinner-spin;
|
||||
}
|
||||
|
||||
toast.achievement {
|
||||
border: 1dp #C2A42D;
|
||||
}
|
||||
@@ -310,6 +351,15 @@ logo img.outer {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pipeline-spinner-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 640dp) {
|
||||
toast {
|
||||
top: 20dp;
|
||||
|
||||
@@ -375,7 +375,6 @@ namespace dusk {
|
||||
|
||||
void ImGuiConsole::PostDraw() {
|
||||
m_menuTools.afterDraw();
|
||||
ShowPipelineProgress();
|
||||
}
|
||||
|
||||
void ImGuiConsole::UpdateDragScroll() {
|
||||
@@ -524,31 +523,4 @@ namespace dusk {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImGuiConsole::ShowPipelineProgress() {
|
||||
const auto* stats = aurora_get_stats();
|
||||
const u32 queuedPipelines = stats->queuedPipelines;
|
||||
if (queuedPipelines == 0 || !getSettings().backend.showPipelineCompilation) {
|
||||
return;
|
||||
}
|
||||
const u32 createdPipelines = stats->createdPipelines;
|
||||
const u32 totalPipelines = queuedPipelines + createdPipelines;
|
||||
|
||||
const auto* viewport = ImGui::GetMainViewport();
|
||||
const auto padding = viewport->WorkPos.y + 10.f;
|
||||
const auto halfWidth = viewport->GetWorkCenter().x;
|
||||
ImGui::SetNextWindowPos(ImVec2{halfWidth, padding}, ImGuiCond_Always, ImVec2{0.5f, 0.f});
|
||||
ImGui::SetNextWindowSize(ImVec2{halfWidth, 0.f}, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowBgAlpha(0.65f);
|
||||
ImGui::Begin("Pipelines", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing);
|
||||
const auto percent = static_cast<float>(createdPipelines) / static_cast<float>(totalPipelines);
|
||||
const auto progressStr = fmt::format("Processing pipelines: {} / {}", createdPipelines, totalPipelines);
|
||||
const auto textSize = ImGui::CalcTextSize(progressStr.data(), progressStr.data() + progressStr.size());
|
||||
ImGui::NewLine();
|
||||
ImGui::SameLine(ImGui::GetWindowWidth() / 2.f - textSize.x + textSize.x / 2.f);
|
||||
ImGuiStringViewText(progressStr);
|
||||
ImGui::ProgressBar(percent);
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ private:
|
||||
// Keep always last
|
||||
ImGuiMenuTools m_menuTools;
|
||||
|
||||
void ShowPipelineProgress();
|
||||
void UpdateDragScroll();
|
||||
};
|
||||
|
||||
|
||||
@@ -160,7 +160,6 @@ UserSettings g_userSettings = {
|
||||
.isoVerification {"backend.isoVerification", DiscVerificationState::Unknown},
|
||||
.graphicsBackend {"backend.graphicsBackend", "auto"},
|
||||
.skipPreLaunchUI {"backend.skipPreLaunchUI", false},
|
||||
.showPipelineCompilation {"backend.showPipelineCompilation", false},
|
||||
.wasPresetChosen {"backend.wasPresetChosen", false},
|
||||
.checkForUpdates {"backend.checkForUpdates", true},
|
||||
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)},
|
||||
@@ -345,7 +344,6 @@ void registerSettings() {
|
||||
Register(g_userSettings.backend.isoVerification);
|
||||
Register(g_userSettings.backend.graphicsBackend);
|
||||
Register(g_userSettings.backend.skipPreLaunchUI);
|
||||
Register(g_userSettings.backend.showPipelineCompilation);
|
||||
Register(g_userSettings.backend.wasPresetChosen);
|
||||
Register(g_userSettings.backend.checkForUpdates);
|
||||
Register(g_userSettings.backend.cardFileType);
|
||||
|
||||
+66
-8
@@ -1,9 +1,9 @@
|
||||
#include "overlay.hpp"
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "controller_config.hpp"
|
||||
#include "dusk/achievements.h"
|
||||
#include "dusk/action_bindings.h"
|
||||
#include "controller_config.hpp"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/speedrun.h"
|
||||
@@ -33,6 +33,13 @@ const Rml::String kDocumentSource = R"RML(
|
||||
</head>
|
||||
<body>
|
||||
<fps id="fps" />
|
||||
<pipeline-progress id="pipeline-progress">
|
||||
<pipeline-status>
|
||||
<icon class="pipeline-spinner"></icon>
|
||||
<span id="pipeline-progress-label" />
|
||||
</pipeline-status>
|
||||
<progress id="pipeline-progress-bar" />
|
||||
</pipeline-progress>
|
||||
<speedrun-timer id="speedrun-timer">
|
||||
<speedrun-rta id="speedrun-rta" />
|
||||
<speedrun-igt id="speedrun-igt" />
|
||||
@@ -48,6 +55,7 @@ constexpr std::array<std::pair<const char*, const char*>, 3> kAutoSaveLayers{{
|
||||
}};
|
||||
|
||||
constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500);
|
||||
constexpr auto kPipelineProgressOpenDelay = std::chrono::milliseconds(250);
|
||||
|
||||
constexpr std::array<const char*, 4> kFpsCorners = {"tl", "tr", "bl", "br"};
|
||||
|
||||
@@ -160,8 +168,8 @@ Rml::Element* create_menu_notification(Rml::Element* parent) {
|
||||
Rml::String padButton{};
|
||||
SDL_Gamepad* gamepad = gamepad_for_port(PAD_CHAN0);
|
||||
if (isActionBound(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0) && gamepad != nullptr) {
|
||||
padButton = native_button_name(gamepad,
|
||||
getActionBindButton(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0));
|
||||
padButton = native_button_name(
|
||||
gamepad, getActionBindButton(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0));
|
||||
} else {
|
||||
padButton = back_button_name();
|
||||
}
|
||||
@@ -197,6 +205,9 @@ static std::string FormatTime(OSTime ticks) {
|
||||
|
||||
Overlay::Overlay() : Document(kDocumentSource, true) {
|
||||
mFpsCounter = mDocument->GetElementById("fps");
|
||||
mPipelineProgress = mDocument->GetElementById("pipeline-progress");
|
||||
mPipelineProgressLabel = mDocument->GetElementById("pipeline-progress-label");
|
||||
mPipelineProgressBar = mDocument->GetElementById("pipeline-progress-bar");
|
||||
mSpeedrunTimer = mDocument->GetElementById("speedrun-timer");
|
||||
mSpeedrunRta = mDocument->GetElementById("speedrun-rta");
|
||||
mSpeedrunIgt = mDocument->GetElementById("speedrun-igt");
|
||||
@@ -258,6 +269,8 @@ void Overlay::update() {
|
||||
}
|
||||
}
|
||||
|
||||
update_pipeline_progress();
|
||||
|
||||
#if !(defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST))
|
||||
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::updateLiveSplit();
|
||||
@@ -309,7 +322,8 @@ void Overlay::update() {
|
||||
mSpeedrunRta->RemoveAttribute("open");
|
||||
}
|
||||
|
||||
mSpeedrunIgt->SetInnerRML(escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
||||
mSpeedrunIgt->SetInnerRML(
|
||||
escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
||||
} else {
|
||||
mSpeedrunTimer->RemoveAttribute("open");
|
||||
}
|
||||
@@ -373,10 +387,8 @@ void Overlay::update() {
|
||||
std::chrono::duration<float>(clock::now() - mCurrentToastStartTime).count();
|
||||
const float ratio = duration > 0.0f ? std::clamp(elapsed / duration, 0.0f, 1.0f) : 1.0f;
|
||||
const auto remaining = 1.f - ratio;
|
||||
Rml::ElementList list;
|
||||
mDocument->GetElementsByTagName(list, "progress");
|
||||
for (auto* elem : list) {
|
||||
elem->SetAttribute("value", remaining);
|
||||
if (auto* progress = mCurrentToast->QuerySelector("progress")) {
|
||||
progress->SetAttribute("value", remaining);
|
||||
}
|
||||
if (remaining == 0.f) {
|
||||
if (mCurrentToast->IsPseudoClassSet("done") ||
|
||||
@@ -395,6 +407,52 @@ void Overlay::update() {
|
||||
}
|
||||
}
|
||||
|
||||
void Overlay::update_pipeline_progress() {
|
||||
if (mPipelineProgress == nullptr || mPipelineProgressLabel == nullptr ||
|
||||
mPipelineProgressBar == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* stats = aurora_get_stats();
|
||||
const uint32_t queuedPipelines = stats != nullptr ? stats->queuedPipelines : 0;
|
||||
if (queuedPipelines == 0) {
|
||||
mPipelineProgress->RemoveAttribute("open");
|
||||
mPipelineProgressActive = false;
|
||||
mPipelineBatchCreatedBase = 0;
|
||||
mLastQueuedPipelines = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t createdPipelines = stats->createdPipelines;
|
||||
if (!mPipelineProgressActive || createdPipelines < mPipelineBatchCreatedBase) {
|
||||
mPipelineProgressActive = true;
|
||||
mPipelineBatchCreatedBase = createdPipelines;
|
||||
mPipelineProgressStartTime = clock::now();
|
||||
mLastQueuedPipelines = 0;
|
||||
}
|
||||
|
||||
const uint32_t builtPipelines = createdPipelines - mPipelineBatchCreatedBase;
|
||||
const uint32_t totalPipelines = queuedPipelines + builtPipelines;
|
||||
const float progress = totalPipelines > 0 ? static_cast<float>(builtPipelines) /
|
||||
static_cast<float>(totalPipelines) :
|
||||
0.0f;
|
||||
|
||||
if (queuedPipelines != mLastQueuedPipelines) {
|
||||
mLastQueuedPipelines = queuedPipelines;
|
||||
const auto noun = queuedPipelines == 1 ? "pipeline" : "pipelines";
|
||||
mPipelineProgressLabel->SetInnerRML(
|
||||
escape(fmt::format("Building {} {}", queuedPipelines, noun)));
|
||||
}
|
||||
mPipelineProgressBar->SetAttribute("value", progress);
|
||||
|
||||
if (clock::now() >= mPipelineProgressStartTime + kPipelineProgressOpenDelay) {
|
||||
mPipelineProgress->SetAttribute("open", "");
|
||||
} else {
|
||||
mPipelineProgress->RemoveAttribute("open");
|
||||
}
|
||||
}
|
||||
|
||||
bool Overlay::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
Log.warn("Overlay received nav command: {}", magic_enum::enum_name(cmd));
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,13 @@ public:
|
||||
protected:
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
|
||||
private:
|
||||
void update_pipeline_progress();
|
||||
|
||||
Rml::Element* mFpsCounter = nullptr;
|
||||
Rml::Element* mPipelineProgress = nullptr;
|
||||
Rml::Element* mPipelineProgressLabel = nullptr;
|
||||
Rml::Element* mPipelineProgressBar = nullptr;
|
||||
Rml::Element* mCurrentToast = nullptr;
|
||||
Rml::Element* mControllerWarning = nullptr;
|
||||
Rml::Element* mMenuNotification = nullptr;
|
||||
@@ -25,7 +31,11 @@ protected:
|
||||
Rml::Element* mSpeedrunIgt = nullptr;
|
||||
clock::time_point mCurrentToastStartTime;
|
||||
clock::time_point mMenuNotificationStartTime;
|
||||
clock::time_point mPipelineProgressStartTime;
|
||||
Uint64 mFpsLastUpdate = 0;
|
||||
uint32_t mPipelineBatchCreatedBase = 0;
|
||||
uint32_t mLastQueuedPipelines = 0;
|
||||
bool mPipelineProgressActive = false;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -1485,11 +1485,6 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.helpText = "When starting Dusklight, skip the main menu and boot straight into the "
|
||||
"game if a disc image is available.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().backend.showPipelineCompilation,
|
||||
{
|
||||
.key = "Show Pipeline Compilation",
|
||||
.helpText = "Show an overlay when shaders are being compiled for your hardware.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().backend.checkForUpdates,
|
||||
{
|
||||
.key = "Check for Updates",
|
||||
|
||||
Reference in New Issue
Block a user