Skip to content

Commit

Permalink
feat: 添加最小帧率设置
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Dec 30, 2024
1 parent 2c25505 commit 2ca4732
Show file tree
Hide file tree
Showing 34 changed files with 123 additions and 101 deletions.
2 changes: 1 addition & 1 deletion src/Magpie.Core/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void Logger::_Log(spdlog::level::level_enum logLevel, std::string_view msg, cons
assert(!msg.empty());

if (logLevel >= spdlog::level::warn && IsDebuggerPresent()) {
// 警告或更高等级的日志也记录到调试器(VS 中的“即时窗口”
// 警告或更高等级的日志也记录到调试器(VS 中的输出窗口
if (msg.back() == '\n') {
OutputDebugString(StrHelper::Concat(L"[LOG] ", StrHelper::UTF8ToUTF16(msg)).c_str());
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/Magpie.Core/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ ID3D11Texture2D* Renderer::_InitBackend() noexcept {
}
}

_stepTimer.Initialize(5.0f, frameRateLimit);
_stepTimer.Initialize(options.minFrameRate, frameRateLimit);
}

ID3D11Texture2D* outputTexture = _BuildEffects();
Expand Down
2 changes: 2 additions & 0 deletions src/Magpie.Core/ScalingOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void ScalingOptions::Log() const noexcept {
idx: {}
venderId: {}
deviceId: {}
minFrameRate: {}
maxFrameRate: {}
cursorScaling: {}
captureMethod: {}
Expand Down Expand Up @@ -86,6 +87,7 @@ void ScalingOptions::Log() const noexcept {
graphicsCardId.idx,
graphicsCardId.vendorId,
graphicsCardId.deviceId,
minFrameRate,
maxFrameRate.has_value() ? *maxFrameRate : 0.0f,
cursorScaling,
(int)captureMethod,
Expand Down
57 changes: 32 additions & 25 deletions src/Magpie.Core/StepTimer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ using namespace std::chrono;

namespace Magpie {

void StepTimer::Initialize(std::optional<float> minFrameRate, std::optional<float> maxFrameRate) noexcept {
if (minFrameRate) {
assert(*minFrameRate >= 0);
if (*minFrameRate > 0) {
_maxInterval = duration_cast<nanoseconds>(duration<float>(1 / *minFrameRate));
}
void StepTimer::Initialize(float minFrameRate, std::optional<float> maxFrameRate) noexcept {
assert(minFrameRate >= 0);
if (minFrameRate > 0) {
_maxInterval = duration_cast<nanoseconds>(duration<float>(1 / minFrameRate));
}

if (maxFrameRate) {
Expand All @@ -23,11 +21,6 @@ void StepTimer::Initialize(std::optional<float> minFrameRate, std::optional<floa
_maxInterval = _maxInterval / _minInterval * _minInterval;
}
}

if (_HasMinInterval() || _HasMaxInterval()) {
_hTimer.reset(CreateWaitableTimerEx(nullptr, nullptr,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS));
}
}

StepTimerStatus StepTimer::WaitForNextFrame(bool waitMsgForNewFrame) noexcept {
Expand All @@ -38,17 +31,35 @@ StepTimerStatus StepTimer::WaitForNextFrame(bool waitMsgForNewFrame) noexcept {
if (waitMsgForNewFrame) {
WaitMessage();
}

if (_isNewFrame) {
_isNewFrame = false;
_lastFrameTime = now;
}

return StepTimerStatus::WaitForNewFrame;
}

if (_isNewFrame) {
_isNewFrame = false;

if (_HasMinInterval()) {
// 总是以最小帧间隔计算上一帧的时间点。因为最大帧间隔是最小帧间隔的整数倍,
// 帧间隔可以保持稳定。
_lastFrameTime = now - (now - _lastFrameTime) % _minInterval;
} else {
_lastFrameTime = now;
}
}

const nanoseconds delta = now - _lastFrameTime;

if (delta >= _maxInterval) {
return StepTimerStatus::ForceNewFrame;
}

// 没有新帧也应更新 FPS。作为性能优化,强制帧无需更新,因为 PrepareForNewFrame 必定会执行
_UpdateFPS();
_UpdateFPS(now);

if (delta < _minInterval) {
_WaitForMsgAndTimer(_minInterval - delta);
Expand All @@ -67,25 +78,22 @@ StepTimerStatus StepTimer::WaitForNextFrame(bool waitMsgForNewFrame) noexcept {
return StepTimerStatus::WaitForNewFrame;
}


void StepTimer::PrepareForNewFrame() noexcept {
const time_point<steady_clock> now = steady_clock::now();
if (_HasMinInterval()) {
// 总是以最小帧间隔计算上一帧的时间点。因为最大帧间隔是最小帧间隔的整数倍,
// 帧间隔可以保持稳定。
_lastFrameTime = now - (now - _lastFrameTime) % _minInterval;
} else {
_lastFrameTime = now;
}
_isNewFrame = true;

++_framesThisSecond;
++_frameCount;

_UpdateFPS();
_UpdateFPS(steady_clock::now());
}

void StepTimer::_WaitForMsgAndTimer(std::chrono::nanoseconds time) noexcept {
if (time > 1ms) {
if (!_hTimer) {
_hTimer.reset(CreateWaitableTimerEx(nullptr, nullptr,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS));
}

// Sleep 精度太低,我们使用 WaitableTimer 睡眠。负值表示相对时间
LARGE_INTEGER liDueTime{
.QuadPart = (time - 1ms).count() / -100
Expand All @@ -101,15 +109,14 @@ void StepTimer::_WaitForMsgAndTimer(std::chrono::nanoseconds time) noexcept {
}
}

void StepTimer::_UpdateFPS() noexcept {
void StepTimer::_UpdateFPS(time_point<steady_clock> now) noexcept {
if (_lastSecondTime == time_point<steady_clock>{}) {
// 第一帧
_lastSecondTime = steady_clock::now();
_lastSecondTime = now;
_framesPerSecond.store(1, std::memory_order_relaxed);
return;
}

const time_point<steady_clock> now = steady_clock::now();
const nanoseconds delta = now - _lastSecondTime;
if (delta >= 1s) {
_lastSecondTime = now - delta % 1s;
Expand Down
6 changes: 4 additions & 2 deletions src/Magpie.Core/StepTimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class StepTimer {
StepTimer(const StepTimer&) = delete;
StepTimer(StepTimer&&) = delete;

void Initialize(std::optional<float> minFrameRate, std::optional<float> maxFrameRate) noexcept;
void Initialize(float minFrameRate, std::optional<float> maxFrameRate) noexcept;

StepTimerStatus WaitForNextFrame(bool waitMsgForNewFrame) noexcept;

Expand All @@ -37,7 +37,7 @@ class StepTimer {

void _WaitForMsgAndTimer(std::chrono::nanoseconds time) noexcept;

void _UpdateFPS() noexcept;
void _UpdateFPS(std::chrono::time_point<std::chrono::steady_clock> now) noexcept;

std::chrono::nanoseconds _minInterval{};
std::chrono::nanoseconds _maxInterval{ std::numeric_limits<std::chrono::nanoseconds::rep>::max() };
Expand All @@ -49,6 +49,8 @@ class StepTimer {
uint32_t _frameCount = 0;
std::atomic<uint32_t> _framesPerSecond = 0;
uint32_t _framesThisSecond = 0;

bool _isNewFrame = false;
};

}
1 change: 1 addition & 0 deletions src/Magpie.Core/include/ScalingOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct ScalingOptions {
Cropping cropping{};
uint32_t flags = ScalingFlags::AdjustCursorSpeed | ScalingFlags::DrawCursor; // ScalingFlags
GraphicsCardId graphicsCardId;
float minFrameRate = 0.0f;
std::optional<float> maxFrameRate;
float cursorScaling = 1.0f;
CaptureMethod captureMethod = CaptureMethod::GraphicsCapture;
Expand Down
3 changes: 1 addition & 2 deletions src/Magpie/AboutPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ struct AboutPage : AboutPageT<AboutPage> {

namespace winrt::Magpie::factory_implementation {

struct AboutPage : AboutPageT<AboutPage, implementation::AboutPage> {
};
struct AboutPage : AboutPageT<AboutPage, implementation::AboutPage> {};

}
15 changes: 15 additions & 0 deletions src/Magpie/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

using namespace ::Magpie;
using namespace winrt;
using namespace Windows::Globalization::NumberFormatting;
using namespace Windows::UI::ViewManagement;

namespace winrt::Magpie::implementation {
Expand Down Expand Up @@ -263,6 +264,20 @@ const com_ptr<RootPage>& App::RootPage() const noexcept {
return _mainWindow->Content();
}

INumberFormatter2 App::DoubleFormatter() {
static DecimalFormatter numberFormatter = []() {
DecimalFormatter result;
IncrementNumberRounder rounder;
// 保留五位小数
rounder.Increment(0.00001);
result.NumberRounder(rounder);
result.FractionDigits(0);
return result;
}();

return numberFormatter;
}

void App::_Uninitialize() {
NotifyIconService::Get().Uninitialize();
ScalingService::Get().Uninitialize();
Expand Down
9 changes: 9 additions & 0 deletions src/Magpie/App.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "App.g.h"
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.Globalization.NumberFormatting.h>
#include "AppSettings.h"
#include "Event.h"

Expand Down Expand Up @@ -48,6 +49,8 @@ class App : public App_base<App, Markup::IXamlMetadataProvider> {
return _isLightTheme.load(std::memory_order_relaxed);
}

static Windows::Globalization::NumberFormatting::INumberFormatter2 DoubleFormatter();

::Magpie::MultithreadEvent<bool> ThemeChanged;

private:
Expand Down Expand Up @@ -110,3 +113,9 @@ class App : public App_base<App, Markup::IXamlMetadataProvider> {
};

}

namespace winrt::Magpie::factory_implementation {

struct App : AppT<App, implementation::App> {};

}
1 change: 1 addition & 0 deletions src/Magpie/App.idl
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ namespace Magpie {
namespace Magpie {
[default_interface]
runtimeclass App : Windows.UI.Xaml.Application {
static Windows.Globalization.NumberFormatting.INumberFormatter2 DoubleFormatter { get; };
}
}
3 changes: 3 additions & 0 deletions src/Magpie/AppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,8 @@ bool AppSettings::_Save(const _AppSettingsData& data) noexcept {
writer.Uint((uint32_t)data._duplicateFrameDetectionMode);
writer.Key("enableStatisticsForDynamicDetection");
writer.Bool(data._isStatisticsForDynamicDetectionEnabled);
writer.Key("minFrameRate");
writer.Double(data._minFrameRate);

ScalingModesService::Get().Export(writer);

Expand Down Expand Up @@ -678,6 +680,7 @@ void AppSettings::_LoadSettings(const rapidjson::GenericObject<true, rapidjson::
_duplicateFrameDetectionMode = (::Magpie::DuplicateFrameDetectionMode)duplicateFrameDetectionMode;
}
JsonHelper::ReadBool(root, "enableStatisticsForDynamicDetection", _isStatisticsForDynamicDetectionEnabled);
JsonHelper::ReadFloat(root, "minFrameRate", _minFrameRate);

[[maybe_unused]] bool result = ScalingModesService::Get().Import(root, true);
assert(result);
Expand Down
11 changes: 11 additions & 0 deletions src/Magpie/AppSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ struct _AppSettingsData {

DuplicateFrameDetectionMode _duplicateFrameDetectionMode =
DuplicateFrameDetectionMode::Dynamic;

float _minFrameRate = 5.0f;

bool _isPortableMode = false;
bool _isAlwaysRunAsAdmin = false;
Expand Down Expand Up @@ -281,6 +283,15 @@ class AppSettings : private _AppSettingsData {
SaveAsync();
}

float MinFrameRate() const noexcept {
return _minFrameRate;
}

void MinFrameRate(float value) noexcept {
_minFrameRate = value;
SaveAsync();
}

Event<AppTheme> ThemeChanged;
Event<winrt::Magpie::ShortcutAction> ShortcutChanged;
Event<bool> IsAutoRestoreChanged;
Expand Down
1 change: 1 addition & 0 deletions src/Magpie/AppXReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <parallel_hashmap/phmap.h>
#include <AppxPackaging.h>
#include <propsys.h>
#include <winrt/Windows.Graphics.Imaging.h>

using namespace winrt;
using namespace Windows::Graphics::Imaging;
Expand Down
4 changes: 4 additions & 0 deletions src/Magpie/EffectParametersViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,8 @@ phmap::flat_hash_map<std::wstring, float>& EffectParametersViewModel::_Data() {
return scalingMode.effects[_effectIdx].parameters;
}

inline hstring ScalingModeFloatParameter::ValueText() const noexcept {
return App::DoubleFormatter().FormatDouble(_value);
}

}
4 changes: 1 addition & 3 deletions src/Magpie/EffectParametersViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ struct ScalingModeFloatParameter : ScalingModeFloatParameterT<ScalingModeFloatPa
RaisePropertyChanged(L"ValueText");
}

hstring ValueText() const noexcept {
return ScalingModesPage::NumberFormatter().FormatDouble(_value);
}
hstring ValueText() const noexcept;

hstring Label() const noexcept {
return _label;
Expand Down
3 changes: 1 addition & 2 deletions src/Magpie/HomePage.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ struct HomePage : HomePageT<HomePage> {

namespace winrt::Magpie::factory_implementation {

struct HomePage : HomePageT<HomePage, implementation::HomePage> {
};
struct HomePage : HomePageT<HomePage, implementation::HomePage> {};

}
10 changes: 10 additions & 0 deletions src/Magpie/HomeViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,16 @@ void HomeViewModel::IsStatisticsForDynamicDetectionEnabled(bool value) {
RaisePropertyChanged(L"IsStatisticsForDynamicDetectionEnabled");
}

double HomeViewModel::MinFrameRate() const noexcept {
return AppSettings::Get().MinFrameRate();
}

void HomeViewModel::MinFrameRate(double value) {
// 清空数字框则重置为 5
AppSettings::Get().MinFrameRate(std::isnan(value) ? 5.0f : (float)value);
RaisePropertyChanged(L"MinFrameRate");
}

void HomeViewModel::_ScalingService_IsTimerOnChanged(bool value) {
if (!value) {
RaisePropertyChanged(L"TimerProgressRingValue");
Expand Down
4 changes: 4 additions & 0 deletions src/Magpie/HomeViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ struct HomeViewModel : HomeViewModelT<HomeViewModel>, wil::notify_property_chang

bool IsStatisticsForDynamicDetectionEnabled() const noexcept;
void IsStatisticsForDynamicDetectionEnabled(bool value);

double MinFrameRate() const noexcept;
void MinFrameRate(double value);

private:
void _ScalingService_IsTimerOnChanged(bool value);

Expand Down
1 change: 1 addition & 0 deletions src/Magpie/HomeViewModel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ namespace Magpie {
Int32 DuplicateFrameDetectionMode;
Boolean IsDynamicDection { get; };
Boolean IsStatisticsForDynamicDetectionEnabled;
Double MinFrameRate;
}
}
1 change: 1 addition & 0 deletions src/Magpie/IconHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "StrHelper.h"
#include "resource.h"
#include <Shlobj.h>
#include <winrt/Windows.Graphics.Imaging.h>

using namespace winrt;
using namespace Windows::Graphics::Imaging;
Expand Down
2 changes: 0 additions & 2 deletions src/Magpie/Profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ struct Profile {

// 10~1000
float maxFrameRate = 60.0f;
// 0~1000
float minFrameRate = 0.0f;

std::wstring launchParameters;

Expand Down
Loading

0 comments on commit 2ca4732

Please sign in to comment.