Skip to content

Commit 51e17f6

Browse files
author
Riley Alston
committed
Merge branch 'dev/ralston/enhancements_progress_hud_main' into 'main'
Enhancements Progress HUD See merge request lightspeedrtx/dxvk-remix-nv!1369
2 parents 7524c89 + a529646 commit 51e17f6

File tree

9 files changed

+204
-64
lines changed

9 files changed

+204
-64
lines changed

src/dxvk/imgui/dxvk_imgui.cpp

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -814,13 +814,13 @@ namespace dxvk {
814814
};
815815

816816
auto common = ctx->getCommonObjects();
817-
static RtxQuickAction sQuickAction = common->getSceneManager().areReplacementsLoaded() ? RtxQuickAction::kRtxOnEnhanced : RtxQuickAction::kRtxOn;
817+
static RtxQuickAction sQuickAction = common->getSceneManager().areAllReplacementsLoaded() ? RtxQuickAction::kRtxOnEnhanced : RtxQuickAction::kRtxOn;
818818

819819
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_KeypadAdd))) {
820820
sQuickAction = (RtxQuickAction) ((sQuickAction + 1) % RtxQuickAction::kCount);
821821

822822
// Skip over the enhancements quick option if no replacements are loaded
823-
if(!common->getSceneManager().areReplacementsLoaded() && sQuickAction == RtxQuickAction::kRtxOnEnhanced)
823+
if(!common->getSceneManager().areAllReplacementsLoaded() && sQuickAction == RtxQuickAction::kRtxOnEnhanced)
824824
sQuickAction = (RtxQuickAction) ((sQuickAction + 1) % RtxQuickAction::kCount);
825825

826826
switch (sQuickAction) {
@@ -1364,7 +1364,7 @@ namespace dxvk {
13641364

13651365
ImGui::Dummy(ImVec2(0.0f, 5.0f));
13661366

1367-
ImGui::BeginDisabled(!common->getSceneManager().areReplacementsLoaded());
1367+
ImGui::BeginDisabled(!common->getSceneManager().areAllReplacementsLoaded());
13681368

13691369
m_userGraphicsSettingChanged |= ImGui::Checkbox("Enable All Enhanced Assets", &RtxOptions::Get()->enableReplacementAssetsObject());
13701370

@@ -1401,10 +1401,10 @@ namespace dxvk {
14011401
auto common = ctx->getCommonObjects();
14021402
const auto& pipelineManager = common->pipelineManager();
14031403

1404-
// Add needed Hud Messages
1405-
14061404
std::vector<HudMessage> hudMessages;
14071405

1406+
// Add Shader Compilation HUD messages
1407+
14081408
uint32_t asyncShaderCompilationCount = 0;
14091409
if (RtxOptions::Shader::enableAsyncCompilation()) {
14101410
asyncShaderCompilationCount = pipelineManager.remixShaderCompilationCount();
@@ -1416,8 +1416,55 @@ namespace dxvk {
14161416
hudMessages.emplace_back(std::move(compilationText), "This may take some time if shaders are not cached yet.\nRemix will not render properly until compilation is finished.");
14171417
}
14181418

1419-
if (common->getSceneManager().areReplacementsLoading()) {
1420-
hudMessages.emplace_back("Loading enhancements", std::nullopt);
1419+
// Add Enhancement Loading HUD messages
1420+
1421+
const auto replacementStates = common->getSceneManager().getReplacementStates();
1422+
std::string replacementLoadingSubtext;
1423+
std::uint32_t loadingReplacementStateCount{ 0U };
1424+
1425+
for (std::size_t i{ 0U }; i < replacementStates.size(); ++i) {
1426+
auto&& replacementState = replacementStates[i];
1427+
1428+
// Add a newline when reporting on more than one mod in a loading state
1429+
1430+
if (loadingReplacementStateCount != 0) {
1431+
replacementLoadingSubtext += '\n';
1432+
}
1433+
1434+
// Hide individual mod progress messages beyond a requested amount
1435+
// Note: This ensures if for some reason there are a significant amount of mods in place that the screen will not be filled with progress hud messages.
1436+
1437+
constexpr std::size_t maxModProgressCount{ 4 };
1438+
1439+
if (loadingReplacementStateCount >= maxModProgressCount) {
1440+
replacementLoadingSubtext += str::format(replacementStates.size() - maxModProgressCount, " more hidden...");
1441+
1442+
break;
1443+
}
1444+
1445+
// Set the progress message if the mod is in a loading state and increment the number of currently loading mods
1446+
1447+
switch (replacementState.progressState) {
1448+
case Mod::ProgressState::OpeningUSD: replacementLoadingSubtext += str::format("Opening USD"); break;
1449+
case Mod::ProgressState::ProcessingMaterials: replacementLoadingSubtext += str::format("Processing Materials (", replacementState.progressCount, " processed)"); break;
1450+
case Mod::ProgressState::ProcessingMeshes: replacementLoadingSubtext += str::format("Processing Meshes (", replacementState.progressCount, " processed)"); break;
1451+
case Mod::ProgressState::ProcessingLights: replacementLoadingSubtext += str::format("Processing Lights (", replacementState.progressCount, " processed)"); break;
1452+
}
1453+
1454+
if (
1455+
replacementState.progressState == Mod::ProgressState::OpeningUSD ||
1456+
replacementState.progressState == Mod::ProgressState::ProcessingMaterials ||
1457+
replacementState.progressState == Mod::ProgressState::ProcessingMeshes ||
1458+
replacementState.progressState == Mod::ProgressState::ProcessingLights
1459+
) {
1460+
++loadingReplacementStateCount;
1461+
}
1462+
}
1463+
1464+
assert((loadingReplacementStateCount == 0U) == replacementLoadingSubtext.empty());
1465+
1466+
if (loadingReplacementStateCount != 0U) {
1467+
hudMessages.emplace_back("Loading enhancements", replacementLoadingSubtext);
14211468
}
14221469

14231470
// Draw Hud Messages
@@ -2113,11 +2160,11 @@ namespace dxvk {
21132160
}
21142161

21152162
void ImGUI::showEnhancementsTab(const Rc<DxvkContext>& ctx) {
2116-
if (!ctx->getCommonObjects()->getSceneManager().areReplacementsLoaded()) {
2163+
if (!ctx->getCommonObjects()->getSceneManager().areAllReplacementsLoaded()) {
21172164
ImGui::Text("No USD enhancements detected, the following options have been disabled. See documentation for how to use enhancements with Remix.");
21182165
}
21192166

2120-
ImGui::BeginDisabled(!ctx->getCommonObjects()->getSceneManager().areReplacementsLoaded());
2167+
ImGui::BeginDisabled(!ctx->getCommonObjects()->getSceneManager().areAllReplacementsLoaded());
21212168
ImGui::Checkbox("Enable Enhanced Assets", &RtxOptions::Get()->enableReplacementAssetsObject());
21222169
{
21232170
ImGui::Indent();

src/dxvk/imgui/dxvk_imgui_capture.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace dxvk {
5757
void ImGuiCapture::show(const Rc<DxvkContext>& ctx) {
5858
auto capturer = ctx->getCommonObjects()->capturer();
5959
const bool disableCapture =
60-
ctx->getCommonObjects()->getSceneManager().areReplacementsLoaded() &&
60+
ctx->getCommonObjects()->getSceneManager().areAllReplacementsLoaded() &&
6161
RtxOptions::Get()->getEnableAnyReplacements();
6262
constexpr auto headerFlagsDefaultOpen = kCollapsingHeaderFlags | ImGuiTreeNodeFlags_DefaultOpen;
6363
if(ImGui::CollapsingHeader("USD Scene Capture", headerFlagsDefaultOpen)) {

src/dxvk/rtx_render/rtx_asset_replacer.cpp

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,29 +97,25 @@ bool AssetReplacer::checkForChanges(const Rc<DxvkContext>& context) {
9797
return changed;
9898
}
9999

100-
bool AssetReplacer::areReplacementsLoaded() const {
101-
bool loaded = false;
100+
bool AssetReplacer::areAllReplacementsLoaded() const {
102101
for (auto& mod : m_modManager.mods()) {
103-
loaded |= mod->state() == Mod::State::Loaded;
102+
if (mod->state().progressState != Mod::ProgressState::Loaded) {
103+
return false;
104+
}
104105
}
105-
return loaded;
106-
}
107106

108-
bool AssetReplacer::areReplacementsLoading() const {
109-
bool loading = false;
110-
for (auto& mod : m_modManager.mods()) {
111-
loading |= mod->state() == Mod::State::Loading;
112-
}
113-
return loading;
107+
return true;
114108
}
115109

116-
const std::string& AssetReplacer::getReplacementStatus() const {
117-
// TODO: make an array?
118-
for (auto& mod : m_modManager.mods()) {
119-
return mod->status();
110+
std::vector<Mod::State> AssetReplacer::getReplacementStates() const {
111+
const auto& mods = m_modManager.mods();
112+
std::vector<Mod::State> modStates(mods.size());
113+
114+
for (auto& mod : mods) {
115+
modStates.emplace_back(mod->state());
120116
}
121-
static const std::string noReplacements("no replacements");
122-
return noReplacements;
117+
118+
return modStates;
123119
}
124120

125121
void AssetReplacer::updateSecretReplacements() {
@@ -129,7 +125,7 @@ void AssetReplacer::updateSecretReplacements() {
129125
m_secretReplacements.clear();
130126

131127
for (auto& mod : m_modManager.mods()) {
132-
if (mod->state() != Mod::State::Loaded) {
128+
if (mod->state().progressState != Mod::ProgressState::Loaded) {
133129
continue;
134130
}
135131

src/dxvk/rtx_render/rtx_asset_replacer.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,11 @@ namespace dxvk {
200200
// returns true if the state of replacements has changed.
201201
bool checkForChanges(const Rc<DxvkContext>& context);
202202

203-
bool areReplacementsLoaded() const;
204-
bool areReplacementsLoading() const;
205-
const std::string& getReplacementStatus() const;
203+
204+
// Returns true if all replacement mods are in the loaded state, false otherwise.
205+
bool areAllReplacementsLoaded() const;
206+
// Gets the states of all the current replacement mods.
207+
std::vector<Mod::State> getReplacementStates() const;
206208

207209
const bool hasNewSecretReplacementInfo() const {
208210
return m_bSecretReplacementsUpdated;

src/dxvk/rtx_render/rtx_game_capturer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace dxvk {
150150
if (m_bTriggerCapture) {
151151
m_bTriggerCapture = false;
152152
if(isIdle()) {
153-
if (RtxOptions::Get()->getEnableAnyReplacements() && m_sceneManager.areReplacementsLoaded()) {
153+
if (RtxOptions::Get()->getEnableAnyReplacements() && m_sceneManager.areAllReplacementsLoaded()) {
154154
Logger::warn("[GameCapturer] Cannot begin capture when replacement assets are enabled/loaded.");
155155
} else if (m_state.has<State::Capturing>()) {
156156
Logger::warn("[GameCapturer] Cannot begin new capture, one currently in progress.");

src/dxvk/rtx_render/rtx_mod_manager.h

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <string>
2828
#include <filesystem>
2929
#include <set>
30+
#include <cassert>
3031

3132
namespace dxvk {
3233

@@ -43,11 +44,27 @@ class Mod {
4344
public:
4445
typedef std::filesystem::path Path;
4546

46-
enum State : uint32_t {
47+
enum ProgressState : std::uint8_t {
48+
// Set when the stage has yet to be loaded.
4749
Unloaded = 0,
48-
Loading,
50+
51+
// Set during the first phase of stage loading when opening the USD file.
52+
OpeningUSD,
53+
// Set during the next phases of stage loading when material, mesh or light processing is currently underway.
54+
// When these are set the progress count may be read from for progress information.
55+
ProcessingMaterials,
56+
ProcessingMeshes,
57+
ProcessingLights,
58+
59+
// Set when the stage is completely loaded without errors.
4960
Loaded,
50-
Error,
61+
};
62+
63+
struct State {
64+
ProgressState progressState;
65+
// Note: This progress value should only be read when the stage state is LoadingMaterials, LoadingMeshes or LoadingLights, as it will
66+
// be uninitialized otherwise.
67+
std::uint32_t progressCount;
5168
};
5269

5370
virtual ~Mod();
@@ -60,7 +77,13 @@ class Mod {
6077
virtual bool checkForChanges(const Rc<DxvkContext>& context) = 0;
6178

6279
State state() const {
63-
return m_state.load();
80+
const auto encodedState{ m_state.load() };
81+
State decodedState;
82+
83+
decodedState.progressState = static_cast<ProgressState>((encodedState >> 29ull) & progressStateMask);
84+
decodedState.progressCount = static_cast<std::uint32_t>((encodedState >> 0ull) & progressCountMask);
85+
86+
return decodedState;
6487
}
6588

6689
const std::string& status() const {
@@ -90,17 +113,56 @@ class Mod {
90113
protected:
91114
explicit Mod(const Path& filePath);
92115

93-
void setState(State state) {
94-
m_state = state;
116+
constexpr static std::uint32_t progressStateMask{ (1ull << 3ull) - 1ull };
117+
constexpr static std::uint32_t progressCountMask{ (1ull << 29ull) - 1ull };
118+
119+
constexpr static std::uint32_t encodeProgressState(ProgressState progressState) {
120+
return static_cast<std::uint32_t>(progressState) << 29ull;
121+
}
122+
123+
// Sets the Mod progress state, only to be used when setting to Unloaded, OpeningUSD or Loaded. Use setStateWithProgress for other states.
124+
void setState(ProgressState progressState) {
125+
// Note: This set state function is only intended to be used with states that do not have progress associated with them.
126+
assert(
127+
progressState == ProgressState::Unloaded ||
128+
progressState == ProgressState::OpeningUSD ||
129+
progressState == ProgressState::Loaded
130+
);
131+
132+
m_state = encodeProgressState(progressState);
133+
}
134+
135+
// Sets the Mod progress state with a progress count value, only to be used when setting to ProcessingMaterials/Meshes/Lights. Use setState for other states.
136+
void setStateWithCount(ProgressState progressState, std::uint32_t progressCount) {
137+
// Note: This set state function is only intended to be used with states that do not have progress associated with them.
138+
assert(
139+
progressState == ProgressState::ProcessingMaterials ||
140+
progressState == ProgressState::ProcessingMeshes ||
141+
progressState == ProgressState::ProcessingLights
142+
);
143+
// Note: Ensure the progress count falls within the expected range. The progress count isare masked during encoding for
144+
// safety as it is in theory possible for values this large to be passed in at runtime, but it likely indicates a bug as there
145+
// probably should not be 500 million of any sort of asset loading.
146+
assert(progressCount < (1u << 29u));
147+
148+
m_state =
149+
encodeProgressState(progressState) |
150+
(static_cast<std::uint64_t>(progressCount) & progressCountMask);
95151
}
96152

97153
const Path m_filePath;
98154
std::string m_name;
99155
size_t m_priority;
100156

101-
std::atomic<State> m_state;
157+
// Note: This uses a 32 bit atomic so that the state as well as the progress count can all be encoded into it together. This ensures all the data
158+
// can be read at the same time atomically to ensure all the values are in sync without the use of mutexes. This is somewhat important as the progress
159+
// count will be updated fairly rapidly depending on how fast assets load and avoiding any sort of overhead is ideal.
160+
// Current encoding: [3 bit progress state] [29 bit progress count]
161+
std::atomic<std::uint32_t> m_state{ encodeProgressState(ProgressState::Unloaded) };
102162
std::string m_status = "Unloaded";
103163

164+
static_assert(decltype(m_state)::is_always_lock_free, "Mod state atomic should be lock-free for performance.");
165+
104166
std::unique_ptr<AssetReplacements> m_replacements;
105167
};
106168

0 commit comments

Comments
 (0)