Skip to content

Commit 920843e

Browse files
committed
Merge branch 'xbei/option_type' into 'main'
[REMIX-4107] Introduce layered settings save system (User, Quality, Mod) with runtime updates and config fix See merge request lightspeedrtx/dxvk-remix-nv!1762
2 parents ff7473f + 5dfb541 commit 920843e

File tree

7 files changed

+176
-28
lines changed

7 files changed

+176
-28
lines changed

RtxOptions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,10 @@ Tables below enumerate all the options and their defaults set by RTX Remix. Note
505505
|rtx.opaqueMaterial.thinFilmThicknessOverride|float|0|||The thin\-film layer's thickness in nanometers for the opaque material when the thin\-film override is enabled\.<br>Should be any value larger than 0, typically within the wavelength of light, but must be less than or equal to OPAQUE\_SURFACE\_MATERIAL\_THIN\_FILM\_MAX\_THICKNESS \(\(1500\.0f\) nm\)\.<br>Should only be used for debugging or development\.|
506506
|rtx.opaqueOpacityTransmissionLobeSamplingProbabilityZeroThreshold|float|0.01|||The threshold for which to zero opaque opacity probability weight values\.|
507507
|rtx.opaqueSpecularLobeSamplingProbabilityZeroThreshold|float|0.01|||The threshold for which to zero opaque specular probability weight values\.|
508+
|rtx.option.optionSavingType|int|0|||Saving type of current runtime changes\.|
509+
|rtx.option.overwriteConfig|bool|False|||This enables overwriting of the original config file when saving settings\.<br>Disable this option to merge the current settings with the preexisting settings in the config\.|
510+
|rtx.option.saveToLayerConf|bool|False|||Whether or not to save the layer to original config file\.<br>Disable this to save the layer into rtx\.conf\.<br>Base on overwriteConfig, the config of the layer will be merged or override the rtx\.conf\.|
511+
|rtx.option.serializeChangedOptionOnly|bool|True||||
508512
|rtx.orthographicIsUI|bool|True|||When enabled, draw calls that are orthographic will be considered as UI\.|
509513
|rtx.particleSoftnessFactor|float|0.05|||Multiplier for the view distance that is used to calculate the particle blending range\.|
510514
|rtx.particles.enable|bool|True|||Enables particle simulation and rendering\.|
@@ -678,7 +682,6 @@ Tables below enumerate all the options and their defaults set by RTX Remix. Note
678682
|rtx.sceneScale|float|1|||Defines the ratio of rendering unit \(1cm\) to game unit, i\.e\. sceneScale = 1cm / GameUnit\.|
679683
|rtx.secondaryRayMaxInteractions|int|8|||The maximum number of resolver interactions to use for secondary \(indirect\) rays\.<br>This affects how many Decals, Ray Portals and potentially particles \(if unordered approximations are not enabled\) may be interacted with along a ray at the cost of performance for higher amounts of interactions\.<br>This value is recommended to be set lower than the primary/PSR max ray interactions as secondary ray interactions are less visually relevant relative to the performance cost of resolving them\.|
680684
|rtx.secondarySpecularFireflyFilteringThreshold|float|1000|||Firefly luminance clamping threshold for secondary specular signal\.|
681-
|rtx.serializeChangedOptionOnly|bool|True||||
682685
|rtx.shader.asyncCompilationThrottleMilliseconds|int|33|||Specifies a time in milliseconds to throttle each application frame when async shader compilation is in progress\. Set to 0 to disable, and only takes effect when rtx\.shader\.enableAsyncCompilation is true\.<br>This generally should be set to a value low enough to not impact the application framerate significantly \(especially if non\-ray traced visuals are capable of being displayed by the application while loading, e\.g\. an intro video\), but also high enough to get the desired shader compilation performance \(especially relevant if the application is fairly heavy on the CPU during async shader compilation, or on CPUs with few hardware threads\)\.|
683686
|rtx.shader.asyncSpirVRecompilation|bool|True|||When set to true runtime shader recompilation will recompile shaders to SPIR\-V asynchronously rather than blocking until complete\.<br>Do note that despite setting this option the actual compilation of the shader from SPIR\-V to the ISA will still be blocking as only the prewarming process can handle this step asynchronously for now\.<br>Generally this option should remain enabled, though disabling it may be useful for CI where deterministic behavior is needed, and may be useful to maximize performance at the cost of blocking \(by not having application running while compiling to SPIR\-V\)\.<br>This option is mainly meant for development use and should not be set for user\-facing operation\.|
684687
|rtx.shader.enableAsyncCompilation|bool|True|||When set to true shader compilation \(especially that of prewarming\) will be done asynchronously rather than blocking\.<br>Typically shader prewarming with async finalization is done to attempt to compile all required shader variants before they are used, often by overlapping this work with a startup sequence \(e\.g\. a game's loading screen\)\. Often times however this prewarming takes longer than the time available, or an application may not have a startup sequence to begin with and immediately begin using Remix shaders\.<br>To accomodate this, async shader compilation allows for this work to be done asynchronously to avoid blocking the application at the cost of being unable to render anything until the process is complete\.<br>This is typically better choice than blocking however and is recommended to be enabled as on Windows Remix blocking will cause the application to stop responding, making it seem as if the application has crashed if shader compilation takes a long time\. Additionally, when combined with rtx\.shader\.enableAsyncCompilationUI the progress of the compilation process can be shown to the user as a UI, improving user experience\.<br>The main downside to this approach is that when blocking shader compilation is allowed to take up more of the CPU, whereas async shader compilation will have to compete with the application which can make compilation take slightly longer than it would otherwise \(especially true if the application's framerate is uncapped\)\.<br>To mitigate this, Remix can optionally throttle the application during async compilation via rtx\.shader\.asyncCompilationThrottleMilliseconds to ensure enough time is available for compilation\.<br>Finally, a more minor downside is that when async shader compilation is in use Remix currently has no way of keeping the application in a startup sequence \(e\.g\. keeping a game on its loading screen\) while it waits for shaders to compile\.<br>This will mean for instance a game's menu may be active but not be able to render until the compilation is complete, rather than blocking on the loading screen and transitioning to the menu only once all shaders are loaded\. Not blocking the application is typically better for user experience regardless though as long as some sort of progress UI is displayed to indicate what is happening\.|

src/dxvk/dxvk_instance.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,10 @@ namespace dxvk {
641641
initConfig<Config::Type_RtxUser>();
642642
initConfig<Config::Type_RtxMod>();
643643

644-
RtxOptionImpl::addRtxOptionLayer("user.conf", RtxOptionLayer::s_runtimeOptionLayerPriority, 1.0f, 1.0f);
644+
RtxOptionImpl::addRtxOptionLayer("quality.conf", (uint32_t) RtxOptionLayer::SystemLayerPriority::Quality, true, 1.0f, 1.0f);
645+
Logger::info("Set quality configs.");
646+
647+
RtxOptionImpl::addRtxOptionLayer("user.conf", (uint32_t) RtxOptionLayer::SystemLayerPriority::USER, true, 1.0f, 1.0f);
645648
Logger::info("Set user realtime configs.");
646649

647650
RtxOption<bool>::initializeRtxOptions();
@@ -694,6 +697,7 @@ namespace dxvk {
694697
const auto baseGameModPath = ModManager::getBaseGameModPath(
695698
m_config.getOption<std::string>("rtx.baseGameModRegex", "", ""),
696699
m_config.getOption<std::string>("rtx.baseGameModPathRegex", "", ""));
700+
697701
if (baseGameModPath.empty()) {
698702
// Skip RtxMod if not present, as it may just pick up a different rtx.mod path
699703
Logger::info("No base game mod path found. Skipping initialization.");
@@ -710,13 +714,13 @@ namespace dxvk {
710714
// Set config so that any rtx option initialized later will use the value in that config object
711715
// The start-up config contains the values from the code and dxvk.conf, only.
712716
RtxOption<bool>::setStartupConfig(m_config);
713-
RtxOptionImpl::addRtxOptionLayer("dxvk.conf", 1, 1.0f, 1.0f, &m_config);
717+
RtxOptionImpl::addRtxOptionLayer("dxvk.conf", (uint32_t)RtxOptionLayer::SystemLayerPriority::DxvkConf, true, 1.0f, 1.0f, &m_config);
714718
Logger::info("Set startup config.");
715719
} else if constexpr ((type == Config::Type_RtxUser) || (type == Config::Type_RtxMod)) {
716720
// Set custom config after the RTX user config has been merged into the config and
717721
// update the RTX options. Contains values from rtx.conf
718722
RtxOption<bool>::setCustomConfig(m_config);
719-
RtxOptionImpl::addRtxOptionLayer("rtx.conf", 2, 1.0f, 1.0f, &m_config);
723+
RtxOptionImpl::addRtxOptionLayer("rtx.conf", (uint32_t)RtxOptionLayer::SystemLayerPriority::RtxConf, true, 1.0f, 1.0f, nullptr);
720724
Logger::info("Set custom config.");
721725
}
722726
}

src/dxvk/imgui/dxvk_imgui.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,16 @@ namespace dxvk {
541541
{ TerrainMode::AsDecals, "Terrain-as-Decals"},
542542
});
543543

544+
ImGui::ComboWithKey<OptionLayerType>::ComboEntries optionSavingModeComboEntries = { {
545+
{ OptionLayerType::User, "User", "Runtime settings"},
546+
{ OptionLayerType::Rtx, "Rtx", "RTX settings"},
547+
{ OptionLayerType::Quality, "Quality", "Graphics quality preset settings"},
548+
{ OptionLayerType::None, "None", "No settings layer; used for testing or temporary development" },
549+
} };
550+
551+
static auto optionSavingModeCombo = ImGui::ComboWithKey<OptionLayerType>(
552+
"Type of setting to save##option", ImGui::ComboWithKey<OptionLayerType>::ComboEntries { optionSavingModeComboEntries });
553+
544554
static auto themeCombo = ImGui::ComboWithKey<ImGUI::Theme>(
545555
"Mode##theme",
546556
{
@@ -1099,12 +1109,13 @@ namespace dxvk {
10991109
ImGui::Separator();
11001110
ImGui::Dummy(ImVec2(0, 2));
11011111

1102-
ImGui::Checkbox("Save Changed Settings Only", &RtxOptions::serializeChangedOptionOnlyObject());
1103-
const float buttonWidth = ImGui::GetContentRegionAvail().x / 3 - (ImGui::GetStyle().ItemSpacing.x);
1104-
1105-
if (IMGUI_ADD_TOOLTIP(ImGui::Button("Save Settings", ImVec2(buttonWidth, 0)), "Changes are now saved to user.conf. Use the 'Save' button in the rtx.conf layer if you want to store them there for sharing.")) {
1112+
IMGUI_ADD_TOOLTIP(optionSavingModeCombo.getKey(&RtxOptions::Option::optionSavingTypeObject()), "Setting saving mode");
11061113

1114+
ImGui::Checkbox("Save Changed Settings Only", &RtxOptions::Option::serializeChangedOptionOnlyObject());
1115+
ImGui::Checkbox("Override configs", &RtxOptions::Option::overwriteConfigObject());
11071116

1117+
const float buttonWidth = ImGui::GetContentRegionAvail().x / 3 - (ImGui::GetStyle().ItemSpacing.x);
1118+
if (IMGUI_ADD_TOOLTIP(ImGui::Button("Save Settings", ImVec2(buttonWidth, 0)), "Changes are now saved to selected config file.")) {
11081119
RtxOptions::serialize();
11091120
}
11101121

@@ -2055,12 +2066,17 @@ namespace dxvk {
20552066
}
20562067
}
20572068

2069+
ImGui::Checkbox("Override configs", &RtxOptions::Option::overwriteConfigObject());
2070+
20582071
uint32_t optionLayerCounter = 1;
20592072
for (auto& [priority, optionLayer] : RtxOptionImpl::getRtxOptionLayerMap()) {
20602073
// Runtime option layer priority is reserved for real-time user changes.
20612074
// These layers should not be modified through the GUI.
20622075
if (priority != RtxOptionLayer::s_runtimeOptionLayerPriority) {
20632076
ImGui::Dummy(ImVec2(0.0f, 5.0f));
2077+
ImGui::Separator();
2078+
ImGui::Dummy(ImVec2(0.0f, 5.0f));
2079+
20642080
const std::string optionLayerName = optionLayer.getName();
20652081

20662082
// Process the display name
@@ -2081,8 +2097,8 @@ namespace dxvk {
20812097
}
20822098

20832099
const std::string optionLayerText = std::to_string(optionLayerCounter++) + ". " + displayName;
2084-
const std::string optionLayerStrengthText = " Strength";
2085-
const std::string optionLayerThresholdText = " Threshold";
2100+
const std::string optionLayerStrengthText = " Strength###Strength_" + displayName;
2101+
const std::string optionLayerThresholdText = " Threshold###Threshold_" + displayName;
20862102

20872103
// Use pending values for UI display and send requests on change
20882104
bool pendingEnabled = optionLayer.getPendingEnabled();
@@ -2102,11 +2118,22 @@ namespace dxvk {
21022118
optionLayer.requestBlendThreshold(pendingThreshold);
21032119
}
21042120

2105-
// Disabled because this blows away the existing settings and replaces it with the current runtime settings.
2106-
// TODO make this save out the combo of existing settings and runtime settings.
2107-
// const std::string optionLayerSavingText = "Save realtime changes into layer " + displayName;
2108-
// if (ImGui::Button(optionLayerSavingText.c_str())) {
2109-
// RtxOptions::serializeOptionLayer(optionLayer.getName());
2121+
// TODO: We need to move these part into a separate saving session
2122+
// std::string layerType;
2123+
// if (optionLayerName == "rtx.conf") {
2124+
// layerType = "RTX";
2125+
// } else if (optionLayerName == "quality.conf") {
2126+
// layerType = "Quality";
2127+
// } else if (optionLayerName == "user.conf") {
2128+
// layerType = "Runtime";
2129+
// } else {
2130+
// layerType = optionLayerName;
2131+
// }
2132+
// const std::string optionLayerSavingText = RtxOptions::Option::saveToLayerConf() || displayName == "rtx.conf"?
2133+
// "Save all settings from " + layerType + " layer to " + displayName :
2134+
// "Save all settings from " + layerType + " layer to rtx.conf";
2135+
// if (IMGUI_ADD_TOOLTIP(ImGui::Button(optionLayerSavingText.c_str()), "Save layer to rtx.conf")) {
2136+
// RtxOptions::serializeOptionLayer(optionLayer, RtxOptions::Option::saveToLayerConf());
21102137
// }
21112138

21122139
if (ImGui::CollapsingHeader(("Contents of " + displayName).c_str(), collapsingHeaderClosedFlags)) {

src/dxvk/rtx_render/rtx_option.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,16 +1069,21 @@ Tables below enumerate all the options and their defaults set by RTX Remix. Note
10691069
return s_rtxOptionLayers;
10701070
}
10711071

1072-
const RtxOptionLayer* RtxOptionImpl::addRtxOptionLayer(const std::string& configPath, const uint32_t priority, const float blendStrength, const float blendThreshold, const Config* config) {
1072+
const RtxOptionLayer* RtxOptionImpl::addRtxOptionLayer(
1073+
const std::string& configPath, const uint32_t priority, const bool isSystemOptionLayer,
1074+
const float blendStrength, const float blendThreshold, const Config* config) {
1075+
// Adjust rtx.conf path if env var DXVK_RTX_CONFIG_FILE is set
1076+
const std::string adjustedConfigPath = configPath == "rtx.conf" ? RtxOptions::getRtxConfPath() : configPath;
1077+
10731078
// Load config from path if not provided
1074-
const Config& layerConfig = config ? *config : Config::getOptionLayerConfig(configPath);
1079+
const Config& layerConfig = config ? *config : Config::getOptionLayerConfig(adjustedConfigPath);
10751080

10761081
// Apply priority offset for option layers only when loading from path (not for rtx.conf or dxvk.conf)
10771082
uint32_t adjustedPriority = priority;
1078-
if (!config && priority != RtxOptionLayer::s_runtimeOptionLayerPriority) {
1083+
if (!isSystemOptionLayer && !config && priority != RtxOptionLayer::s_runtimeOptionLayerPriority) {
10791084
adjustedPriority += RtxOptionLayer::s_userOptionLayerOffset;
10801085
}
1081-
1086+
10821087
// Construct the layer in-place in the map using emplace
10831088
auto result = getRtxOptionLayerMap().emplace(
10841089
std::piecewise_construct,
@@ -1097,7 +1102,7 @@ Tables below enumerate all the options and their defaults set by RTX Remix. Note
10971102
if (!layer.isValid()) {
10981103
// Layer is invalid, remove it from the map
10991104
getRtxOptionLayerMap().erase(result.first);
1100-
Logger::warn(str::format("[RTX Option]: Failed to load valid config for layer '", configPath, "' with original priority ", priority, " and adjusted priority ", adjustedPriority, "."));
1105+
Logger::warn(str::format("[RTX Option]: Failed to load valid config for layer '", adjustedConfigPath, "' with original priority ", priority, " and adjusted priority ", adjustedPriority, "."));
11011106
return nullptr;
11021107
}
11031108

src/dxvk/rtx_render/rtx_option.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ namespace dxvk {
6868
Vector4
6969
};
7070

71+
enum class OptionLayerType {
72+
User,
73+
Rtx,
74+
Quality,
75+
None
76+
};
77+
7178
union GenericValue {
7279
bool b;
7380
int i;
@@ -103,6 +110,16 @@ namespace dxvk {
103110
RequestEnabled = 1 // At least one component requested enabled (wins over disabled)
104111
};
105112

113+
enum class SystemLayerPriority : uint32_t {
114+
Default = 0,
115+
DxvkConf = 1,
116+
RtxConf = 2,
117+
Quality = 3,
118+
Mod = 4,
119+
NONE = 0xFFFFFFFE,
120+
USER = 0xFFFFFFFF
121+
};
122+
106123
// Constructor for creating option layers
107124
// Should not be called directly. Use RtxOptionLayerManager::acquireLayer instead.
108125
RtxOptionLayer(const Config& config, const std::string& configName, const uint32_t priority, const float blendStrength, const float blendThreshold);
@@ -157,6 +174,10 @@ namespace dxvk {
157174
m_blendStrengthDirty = dirty;
158175
}
159176

177+
void setConfig(const Config& config) {
178+
m_config = config;
179+
}
180+
160181
const bool isValid() const { return m_config.getOptions().size() > 0; }
161182
const bool isEnabled() const { return m_enabled; }
162183
const Config& getConfig() const { return m_config; }
@@ -392,7 +413,9 @@ namespace dxvk {
392413
// Add an option layer to global option layer map
393414
// Returns a pointer to the newly created layer, or nullptr if the layer was invalid
394415
// If config is provided, uses it directly; otherwise loads from configPath
395-
static const RtxOptionLayer* addRtxOptionLayer(const std::string& configPath, const uint32_t priority, const float blendStrength, const float blendThreshold, const Config* config = nullptr);
416+
static const RtxOptionLayer* addRtxOptionLayer(
417+
const std::string& configPath, const uint32_t priority, const bool isSystemOptionLayer,
418+
const float blendStrength, const float blendThreshold, const Config* config = nullptr);
396419
// Remove an option layer from the global option layer map by pointer
397420
// Returns true if the layer was found and removed
398421
static bool removeRtxOptionLayer(const RtxOptionLayer* layer);

src/dxvk/rtx_render/rtx_option_layer_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const RtxOptionLayer* RtxOptionLayerManager::acquireLayer(const std::string& con
5454
}
5555

5656
// Create new layer
57-
const RtxOptionLayer* newLayer = RtxOptionImpl::addRtxOptionLayer(configPath, priority, blendStrength, blendThreshold);
57+
const RtxOptionLayer* newLayer = RtxOptionImpl::addRtxOptionLayer(configPath, priority, false, blendStrength, blendThreshold);
5858

5959
if (newLayer == nullptr) {
6060
Logger::err(str::format("RtxOptionLayerManager: Failed to create layer for '", configPath, "' with priority ", priority, "."));

0 commit comments

Comments
 (0)