feat: 添加“最高 shader model”开发者选项

This commit is contained in:
Xu 2026-03-15 15:45:55 +08:00
commit 10dcfaa683
13 changed files with 153 additions and 93 deletions

View file

@ -513,9 +513,13 @@ bool D3D12Context::_QueryHighestShaderModel() noexcept {
D3D_SHADER_MODEL_6_0,
D3D_SHADER_MODEL_5_1
};
constexpr uint32_t versionCount = (uint32_t)std::size(allModelVersions);
for (D3D_SHADER_MODEL modelVersion : allModelVersions) {
D3D12_FEATURE_DATA_SHADER_MODEL data = { .HighestShaderModel = modelVersion };
HighestShaderModel versionLimit = ScalingWindow::Get().Options().highestShaderModel;
uint32_t startIdx = versionLimit == HighestShaderModel::NotLimited ? 0 : (uint32_t)versionLimit - 1;
for (uint32_t i = startIdx; i < versionCount; ++i) {
D3D12_FEATURE_DATA_SHADER_MODEL data = { .HighestShaderModel = allModelVersions[i]};
HRESULT hr = _device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &data, sizeof(data));
if (hr == E_INVALIDARG) {
continue;

View file

@ -66,6 +66,7 @@ void ScalingOptions::Prepare() noexcept {
IsWindowedMode: {}
IsDebugMode: {}
IsBenchmarkMode: {}
UseWarp: {}
IsTopmostDisabled: {}
IsFP16Disabled: {}
IsEffectCacheDisabled: {}
@ -94,11 +95,14 @@ void ScalingOptions::Prepare() noexcept {
duplicateFrameDetectionMode: {}
fullscreenInitialToolbarState: {}
windowedInitialToolbarState: {}
initialWindowedScaleFactor: {},
highestShaderModel: {},
screenshotsDir: {}
effects: {})",
IsWindowedMode(),
IsDebugMode(),
IsBenchmarkMode(),
UseWarp(),
IsTopmostDisabled(),
IsFP16Disabled(),
IsEffectCacheDisabled(),
@ -120,12 +124,14 @@ void ScalingOptions::Prepare() noexcept {
minFrameRate,
maxFrameRate.has_value() ? *maxFrameRate : 0.0f,
cursorScale,
(int)captureMethod,
(int)multiMonitorUsage,
(int)cursorInterpolationMode,
(int)duplicateFrameDetectionMode,
(int)fullscreenInitialToolbarState,
(int)windowedInitialToolbarState,
(uint32_t)captureMethod,
(uint32_t)multiMonitorUsage,
(uint32_t)cursorInterpolationMode,
(uint32_t)duplicateFrameDetectionMode,
(uint32_t)fullscreenInitialToolbarState,
(uint32_t)windowedInitialToolbarState,
initialWindowedScaleFactor,
(uint32_t)highestShaderModel,
StrHelper::UTF16ToUTF8(screenshotsDir.native()),
LogEffects(effects)
));

View file

@ -77,7 +77,8 @@ struct EffectOption {
enum class DuplicateFrameDetectionMode {
Always,
Dynamic,
Never
Never,
COUNT
};
enum class ToolbarState {
@ -104,6 +105,22 @@ struct OverlayOptions {
phmap::flat_hash_map<std::string, OverlayWindowOption> windows;
};
enum class HighestShaderModel {
NotLimited,
SM_6_9,
SM_6_8,
SM_6_7,
SM_6_6,
SM_6_5,
SM_6_4,
SM_6_3,
SM_6_2,
SM_6_1,
SM_6_0,
SM_5_1,
COUNT
};
enum class ScalingError {
NoError,
@ -208,6 +225,7 @@ struct ScalingOptions {
ToolbarState fullscreenInitialToolbarState = ToolbarState::AutoHide;
ToolbarState windowedInitialToolbarState = ToolbarState::AutoHide;
float initialWindowedScaleFactor = 0.0f;
HighestShaderModel highestShaderModel = HighestShaderModel::NotLimited;
std::filesystem::path screenshotsDir;
// 下面的成员支持在缩放时修改

View file

@ -375,6 +375,7 @@ void AppSettings::IsDeveloperMode(bool value) noexcept {
_isSaveEffectSources = false;
_isWarningsAreErrors = false;
_duplicateFrameDetectionMode = DuplicateFrameDetectionMode::Dynamic;
_highestShaderModel = HighestShaderModel::NotLimited;
_isFP16Disabled = false;
}
@ -623,6 +624,8 @@ bool AppSettings::_Save(const _AppSettingsData& data) noexcept {
writer.Int64(data._updateCheckDate.time_since_epoch().count());
writer.Key("duplicateFrameDetectionMode");
writer.Uint((uint32_t)data._duplicateFrameDetectionMode);
writer.Key("highestShaderModel");
writer.Uint((uint32_t)data._highestShaderModel);
writer.Key("minFrameRate");
writer.Double(data._minFrameRate);
writer.Key("disableFP16");
@ -818,14 +821,9 @@ void AppSettings::_LoadSettings(const rapidjson::GenericObject<true, rapidjson::
using std::chrono::system_clock;
_updateCheckDate = system_clock::time_point(system_clock::duration(d));
}
{
uint32_t duplicateFrameDetectionMode = (uint32_t)DuplicateFrameDetectionMode::Dynamic;
JsonHelper::ReadUInt(root, "duplicateFrameDetectionMode", duplicateFrameDetectionMode);
if (duplicateFrameDetectionMode > 2) {
duplicateFrameDetectionMode = (uint32_t)DuplicateFrameDetectionMode::Dynamic;
}
_duplicateFrameDetectionMode = (::Magpie::DuplicateFrameDetectionMode)duplicateFrameDetectionMode;
}
JsonHelper::ReadEnum(root, "duplicateFrameDetectionMode", _duplicateFrameDetectionMode);
JsonHelper::ReadEnum(root, "highestShaderModel", _highestShaderModel);
JsonHelper::ReadFloat(root, "minFrameRate", _minFrameRate);
JsonHelper::ReadBool(root, "disableFP16", _isFP16Disabled);
@ -868,27 +866,13 @@ void AppSettings::_LoadSettings(const rapidjson::GenericObject<true, rapidjson::
if (overlayNode != root.MemberEnd() && overlayNode->value.IsObject()) {
auto overlayObj = overlayNode->value.GetObj();
uint32_t initialToolbarState = (uint32_t)ToolbarState::AutoHide;
if (JsonHelper::ReadUInt(overlayObj, "fullscreenInitialToolbarState", initialToolbarState, true)) {
if (initialToolbarState >= (uint32_t)ToolbarState::COUNT) {
initialToolbarState = (uint32_t)ToolbarState::AutoHide;
}
_fullscreenInitialToolbarState = (ToolbarState)initialToolbarState;
initialToolbarState = (uint32_t)ToolbarState::AutoHide;
JsonHelper::ReadUInt(overlayObj, "windowedInitialToolbarState", initialToolbarState);
if (initialToolbarState >= (uint32_t)ToolbarState::COUNT) {
initialToolbarState = (uint32_t)ToolbarState::AutoHide;
}
_windowedInitialToolbarState = (ToolbarState)initialToolbarState;
if (JsonHelper::ReadEnum(overlayObj, "fullscreenInitialToolbarState",
_fullscreenInitialToolbarState, true)) {
JsonHelper::ReadEnum(overlayObj, "windowedInitialToolbarState", _windowedInitialToolbarState);
} else {
// v0.12.0-preview1 中工具栏初始状态不区分全屏和窗口模式缩放
JsonHelper::ReadUInt(overlayObj, "initialToolbarState", initialToolbarState);
if (initialToolbarState >= (uint32_t)ToolbarState::COUNT) {
initialToolbarState = (uint32_t)ToolbarState::AutoHide;
}
_fullscreenInitialToolbarState = (ToolbarState)initialToolbarState;
_windowedInitialToolbarState = (ToolbarState)initialToolbarState;
JsonHelper::ReadEnum(overlayObj, "initialToolbarState", _fullscreenInitialToolbarState);
_windowedInitialToolbarState = _fullscreenInitialToolbarState;
}
{
@ -992,42 +976,23 @@ bool AppSettings::_LoadProfile(
profile.scalingMode = -1;
}
{
uint32_t captureMethod = (uint32_t)CaptureMethod::GraphicsCapture;
if (!JsonHelper::ReadUInt(profileObj, "captureMethod", captureMethod, true)) {
// v0.10.0-preview1 使用 captureMode
JsonHelper::ReadUInt(profileObj, "captureMode", captureMethod);
if (!JsonHelper::ReadEnum(profileObj, "captureMethod", profile.captureMethod, true)) {
// v0.10.0-preview1 使用 captureMode
JsonHelper::ReadEnum(profileObj, "captureMode", profile.captureMethod);
}
if (profile.captureMethod == CaptureMethod::DesktopDuplication) {
// Desktop Duplication 捕获模式要求 Win10 20H1+
if (!Win32Helper::GetOSVersion().Is20H1OrNewer()) {
profile.captureMethod = CaptureMethod::GraphicsCapture;
}
if (captureMethod >= (uint32_t)CaptureMethod::COUNT) {
captureMethod = (uint32_t)CaptureMethod::GraphicsCapture;
} else if (captureMethod == (uint32_t)CaptureMethod::DesktopDuplication) {
// Desktop Duplication 捕获模式要求 Win10 20H1+
if (!Win32Helper::GetOSVersion().Is20H1OrNewer()) {
captureMethod = (uint32_t)CaptureMethod::GraphicsCapture;
}
}
profile.captureMethod = (CaptureMethod)captureMethod;
}
{
uint32_t multiMonitorUsage = (uint32_t)MultiMonitorUsage::Closest;
JsonHelper::ReadUInt(profileObj, "multiMonitorUsage", multiMonitorUsage);
if (multiMonitorUsage >= (uint32_t)MultiMonitorUsage::COUNT) {
multiMonitorUsage = (uint32_t)MultiMonitorUsage::Closest;
}
profile.multiMonitorUsage = (MultiMonitorUsage)multiMonitorUsage;
}
{
uint32_t factor = (uint32_t)InitialWindowedScaleFactor::Auto;
JsonHelper::ReadUInt(profileObj, "initialWindowedScaleFactor", factor);
if (factor >= (uint32_t)InitialWindowedScaleFactor::COUNT) {
factor = (uint32_t)InitialWindowedScaleFactor::Auto;
}
profile.initialWindowedScaleFactor = (InitialWindowedScaleFactor)factor;
}
JsonHelper::ReadEnum(profileObj, "multiMonitorUsage", profile.multiMonitorUsage);
JsonHelper::ReadEnum(profileObj, "initialWindowedScaleFactor",
profile.initialWindowedScaleFactor);
JsonHelper::ReadFloat(profileObj, "customInitialWindowedScaleFactor",
profile.customInitialWindowedScaleFactor);
if (profile.customInitialWindowedScaleFactor < 1.0f) {
@ -1088,29 +1053,14 @@ bool AppSettings::_LoadProfile(
profile.scalingFlags = (ScalingFlags)flags;
}
{
uint32_t cursorScaling = (uint32_t)CursorScaling::NoScaling;
JsonHelper::ReadUInt(profileObj, "cursorScaling", cursorScaling);
if (cursorScaling >= (uint32_t)CursorScaling::COUNT) {
cursorScaling = (uint32_t)CursorScaling::NoScaling;
}
profile.cursorScaling = (CursorScaling)cursorScaling;
}
JsonHelper::ReadEnum(profileObj, "cursorScaling", profile.cursorScaling);
JsonHelper::ReadFloat(profileObj, "customCursorScaling", profile.customCursorScaling);
if (profile.customCursorScaling < 0) {
profile.customCursorScaling = 1.0f;
}
{
uint32_t cursorInterpolationMode = (uint32_t)CursorInterpolationMode::NearestNeighbor;
JsonHelper::ReadUInt(profileObj, "cursorInterpolationMode", cursorInterpolationMode);
if (cursorInterpolationMode >= (uint32_t)CursorInterpolationMode::COUNT) {
cursorInterpolationMode = (uint32_t)CursorInterpolationMode::NearestNeighbor;
}
profile.cursorInterpolationMode = (CursorInterpolationMode)cursorInterpolationMode;
}
JsonHelper::ReadEnum(profileObj, "cursorInterpolationMode", profile.cursorInterpolationMode);
JsonHelper::ReadBool(profileObj, "autoHideCursorEnabled", profile.isAutoHideCursorEnabled);
JsonHelper::ReadFloat(profileObj, "autoHideCursorDelay", profile.autoHideCursorDelay);
if (profile.autoHideCursorDelay <= 0.1f - FLOAT_EPSILON<float> ||
@ -1138,14 +1088,7 @@ bool AppSettings::_LoadProfile(
}
}
{
uint32_t outputAlignment = (uint32_t)OutputAlignment::Center;
JsonHelper::ReadUInt(profileObj, "outputAlignment", outputAlignment);
if (outputAlignment >= (uint32_t)OutputAlignment::COUNT) {
outputAlignment = (uint32_t)OutputAlignment::Center;
}
profile.outputAlignment = (OutputAlignment)outputAlignment;
}
JsonHelper::ReadEnum(profileObj, "outputAlignment", profile.outputAlignment);
return true;
}

View file

@ -47,6 +47,7 @@ struct _AppSettingsData {
DuplicateFrameDetectionMode _duplicateFrameDetectionMode =
DuplicateFrameDetectionMode::Dynamic;
HighestShaderModel _highestShaderModel = HighestShaderModel::NotLimited;
float _minFrameRate = 10.0f;
@ -312,6 +313,15 @@ public:
SaveAsync();
}
HighestShaderModel HighestShaderModel() const noexcept {
return _highestShaderModel;
}
void HighestShaderModel(enum HighestShaderModel value) noexcept {
_highestShaderModel = value;
SaveAsync();
}
float MinFrameRate() const noexcept {
return _minFrameRate;
}

View file

@ -298,7 +298,7 @@
</local:SettingsCard>
<local:SettingsCard ContentAlignment="Left">
<CheckBox x:Uid="Home_Advanced_DeveloperOptions_UseWarp"
IsChecked="{x:Bind ViewModel.UseWarp, Mode=TwoWay}" />
IsChecked="{x:Bind ViewModel.UseWarp, Mode=TwoWay}" />
</local:SettingsCard>
<local:SettingsCard ContentAlignment="Left">
<CheckBox x:Uid="Home_Advanced_DeveloperOptions_DisableTopmost"
@ -333,6 +333,24 @@
<ComboBoxItem x:Uid="Home_Advanced_DeveloperOptions_DuplicateFrameDetection_Never" />
</ComboBox>
</local:SettingsCard>
<local:SettingsCard x:Uid="Home_Advanced_DeveloperOptions_HighestShaderModel"
IsWrapEnabled="True">
<ComboBox DropDownOpened="ComboBox_DropDownOpened"
SelectedIndex="{x:Bind ViewModel.HighestShaderModel, Mode=TwoWay}">
<ComboBoxItem x:Uid="Home_Advanced_DeveloperOptions_HighestShaderModel_NotLimited" />
<x:String>6.9</x:String>
<x:String>6.8</x:String>
<x:String>6.7</x:String>
<x:String>6.6</x:String>
<x:String>6.5</x:String>
<x:String>6.4</x:String>
<x:String>6.3</x:String>
<x:String>6.2</x:String>
<x:String>6.1</x:String>
<x:String>6.0</x:String>
<x:String>5.1</x:String>
</ComboBox>
</local:SettingsCard>
</local:SettingsExpander.Items>
</local:SettingsExpander>
</local:SettingsGroup>

View file

@ -609,6 +609,26 @@ void HomeViewModel::DuplicateFrameDetectionMode(int value) {
RaisePropertyChanged(L"DuplicateFrameDetectionMode");
}
int HomeViewModel::HighestShaderModel() const noexcept {
return (int)AppSettings::Get().HighestShaderModel();
}
void HomeViewModel::HighestShaderModel(int value) {
if (value < 0) {
return;
}
auto version = (::Magpie::HighestShaderModel)value;
AppSettings& settings = AppSettings::Get();
if (settings.HighestShaderModel() == version) {
return;
}
settings.HighestShaderModel(version);
RaisePropertyChanged(L"HighestShaderModel");
}
void HomeViewModel::_ScalingService_IsTimerOnChanged(bool value, bool) {
if (!value) {
RaisePropertyChanged(L"TimerProgressRingValue");

View file

@ -117,6 +117,9 @@ struct HomeViewModel : HomeViewModelT<HomeViewModel>, wil::notify_property_chang
int DuplicateFrameDetectionMode() const noexcept;
void DuplicateFrameDetectionMode(int value);
int HighestShaderModel() const noexcept;
void HighestShaderModel(int value);
private:
void _ScalingService_IsTimerOnChanged(bool value, bool windowedMode);

View file

@ -50,5 +50,6 @@ namespace Magpie {
Boolean IsWarningsAreErrors;
Boolean IsFP16Disabled;
Int32 DuplicateFrameDetectionMode;
Int32 HighestShaderModel;
}
}

View file

@ -19,6 +19,30 @@ struct JsonHelper {
bool required = false
) noexcept;
template <typename Enum>
static bool ReadEnum(
const rapidjson::GenericObject<true, rapidjson::Value>& obj,
const char* name,
Enum& result,
bool required = false
) noexcept {
auto node = obj.FindMember(name);
if (node == obj.MemberEnd()) {
return !required;
}
if (!node->value.IsUint()) {
return false;
}
uint32_t value = node->value.GetUint();
if (value < (uint32_t)Enum::COUNT) {
result = (Enum)value;
}
return true;
}
static bool ReadUInt(
const rapidjson::GenericObject<true, rapidjson::Value>& obj,
const char* name,

View file

@ -1054,4 +1054,10 @@
<data name="Home_Advanced_DeveloperOptions_UseWarp.Content" xml:space="preserve">
<value>Use software rendering</value>
</data>
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel.Header" xml:space="preserve">
<value>Highest shader model</value>
</data>
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel_NotLimited.Content" xml:space="preserve">
<value>Not limited</value>
</data>
</root>

View file

@ -1054,4 +1054,10 @@
<data name="Home_Advanced_DeveloperOptions_UseWarp.Content" xml:space="preserve">
<value>使用软件渲染</value>
</data>
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel.Header" xml:space="preserve">
<value>最高 shader model</value>
</data>
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel_NotLimited.Content" xml:space="preserve">
<value>不限制</value>
</data>
</root>

View file

@ -449,6 +449,7 @@ ScalingError ScalingService::_StartScaleImpl(HWND hWnd, const Profile& profile,
options.IsAllowScalingMaximized(settings.IsAllowScalingMaximized());
options.IsSimulateExclusiveFullscreen(settings.IsSimulateExclusiveFullscreen());
options.duplicateFrameDetectionMode = settings.DuplicateFrameDetectionMode();
options.highestShaderModel = settings.HighestShaderModel();
options.IsInlineParams(settings.IsInlineParams());
options.IsFP16Disabled(settings.IsFP16Disabled());