mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-21 21:40:32 -04:00
feat: FPS Limiter (#1446)
* Add interpolation frame rate cap * wip: reworked framelimiter Based on my testing this is a bit more stable in frametimes. * wip: efficiency improvement + windows build fix Significantly improve efficiency by using a hybrid approach. * wip: UI changes * wip: end frame AFTER limiting * wip: remove unused include * wip: minor ui code change Makes it easier to remove/add presets * Simplify Limiter UI - Change enableFrameInterpolation to an enum with off/capped/unlimited values - Simplify the UI to use 2 settings (unlock framerate + a max value entry) * wip: slight limiter simplification * wip: implement review suggestions * wip: fix syntax error * wip: revert enum order + replace old checks * Fix compile error --------- Co-authored-by: SailorSnoW <sailorsnow@pm.me> Co-authored-by: Loïs <49660929+SailorSnoW@users.noreply.github.com> Co-authored-by: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
class camera_process_class;
|
class camera_process_class;
|
||||||
class view_class;
|
class view_class;
|
||||||
@@ -18,7 +19,7 @@ void begin_record();
|
|||||||
void end_record();
|
void end_record();
|
||||||
void begin_sim_tick();
|
void begin_sim_tick();
|
||||||
uint64_t sim_tick_seq();
|
uint64_t sim_tick_seq();
|
||||||
void begin_frame(bool enabled, bool is_sim_frame, float step);
|
void begin_frame(FrameInterpMode mode, bool is_sim_frame, float step);
|
||||||
void interpolate();
|
void interpolate();
|
||||||
float get_interpolation_step();
|
float get_interpolation_step();
|
||||||
|
|
||||||
|
|||||||
+15
-2
@@ -34,6 +34,12 @@ enum class GyroMode : u8 {
|
|||||||
Mouse = 1,
|
Mouse = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FrameInterpMode : u8 {
|
||||||
|
Off = 0,
|
||||||
|
Capped = 1,
|
||||||
|
Unlimited = 2,
|
||||||
|
};
|
||||||
|
|
||||||
namespace config {
|
namespace config {
|
||||||
template <>
|
template <>
|
||||||
struct ConfigEnumRange<BloomMode> {
|
struct ConfigEnumRange<BloomMode> {
|
||||||
@@ -58,7 +64,13 @@ struct ConfigEnumRange<GyroMode> {
|
|||||||
static constexpr auto min = GyroMode::Sensor;
|
static constexpr auto min = GyroMode::Sensor;
|
||||||
static constexpr auto max = GyroMode::Mouse;
|
static constexpr auto max = GyroMode::Mouse;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
template <>
|
||||||
|
struct ConfigEnumRange<FrameInterpMode> {
|
||||||
|
static constexpr auto min = FrameInterpMode::Off;
|
||||||
|
static constexpr auto max = FrameInterpMode::Unlimited;
|
||||||
|
};
|
||||||
|
} // namespace config
|
||||||
|
|
||||||
// Persistent user settings
|
// Persistent user settings
|
||||||
|
|
||||||
@@ -72,6 +84,7 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> lockAspectRatio;
|
ConfigVar<bool> lockAspectRatio;
|
||||||
ConfigVar<bool> enableFpsOverlay;
|
ConfigVar<bool> enableFpsOverlay;
|
||||||
ConfigVar<int> fpsOverlayCorner;
|
ConfigVar<int> fpsOverlayCorner;
|
||||||
|
ConfigVar<int> maxFrameRate;
|
||||||
} video;
|
} video;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -124,7 +137,7 @@ struct UserSettings {
|
|||||||
ConfigVar<float> bloomMultiplier;
|
ConfigVar<float> bloomMultiplier;
|
||||||
ConfigVar<bool> disableWaterRefraction;
|
ConfigVar<bool> disableWaterRefraction;
|
||||||
ConfigVar<bool> enableTextureReplacements;
|
ConfigVar<bool> enableTextureReplacements;
|
||||||
ConfigVar<bool> enableFrameInterpolation;
|
ConfigVar<FrameInterpMode> enableFrameInterpolation;
|
||||||
ConfigVar<int> internalResolutionScale;
|
ConfigVar<int> internalResolutionScale;
|
||||||
ConfigVar<int> shadowResolutionMultiplier;
|
ConfigVar<int> shadowResolutionMultiplier;
|
||||||
ConfigVar<bool> enableDepthOfField;
|
ConfigVar<bool> enableDepthOfField;
|
||||||
|
|||||||
+37
-4
@@ -17,16 +17,21 @@
|
|||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class Limiter {
|
class Limiter {
|
||||||
public:
|
public:
|
||||||
using duration_t = Uint64;
|
using duration_t = Uint64;
|
||||||
|
|
||||||
void Reset() { m_oldTime = SDL_GetTicksNS(); }
|
void Reset() {
|
||||||
|
m_oldTime = SDL_GetTicksNS();
|
||||||
|
}
|
||||||
|
|
||||||
void Sleep(duration_t targetFrameTime) {
|
duration_t Sleep(duration_t targetFrameTime) {
|
||||||
if (targetFrameTime == 0) {
|
if (targetFrameTime == 0) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Uint64 start = SDL_GetTicksNS();
|
const Uint64 start = SDL_GetTicksNS();
|
||||||
@@ -41,6 +46,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
|
return adjustedSleepTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_t SleepTime(duration_t targetFrameTime) {
|
duration_t SleepTime(duration_t targetFrameTime) {
|
||||||
@@ -74,7 +81,6 @@ private:
|
|||||||
if (!initialized || numSleeps++ % 1000 == 0) {
|
if (!initialized || numSleeps++ % 1000 == 0) {
|
||||||
LARGE_INTEGER freq;
|
LARGE_INTEGER freq;
|
||||||
if (QueryPerformanceFrequency(&freq) == 0) {
|
if (QueryPerformanceFrequency(&freq) == 0) {
|
||||||
DuskLog.warn("QueryPerformanceFrequency failed: {}", GetLastError());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
countPerNs = static_cast<double>(freq.QuadPart) / 1e9;
|
countPerNs = static_cast<double>(freq.QuadPart) / 1e9;
|
||||||
@@ -98,6 +104,33 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
} while (current.QuadPart - start.QuadPart < ticksToWait);
|
} while (current.QuadPart - start.QuadPart < ticksToWait);
|
||||||
}
|
}
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
void NanoSleep(const duration_t duration) {
|
||||||
|
// Hybrid approach using Apple Mach
|
||||||
|
uint64_t start_mach = mach_absolute_time();
|
||||||
|
|
||||||
|
mach_timebase_info_data_t timebase_info;
|
||||||
|
mach_timebase_info(&timebase_info);
|
||||||
|
|
||||||
|
uint64_t total_mach_ticks = (duration * timebase_info.denom) / timebase_info.numer;
|
||||||
|
uint64_t target_mach = start_mach + total_mach_ticks;
|
||||||
|
|
||||||
|
uint64_t buffer_ns = 2'000'000ULL;
|
||||||
|
uint64_t buffer_mach_ticks = (buffer_ns * timebase_info.denom) / timebase_info.numer;
|
||||||
|
|
||||||
|
if (total_mach_ticks > buffer_mach_ticks) {
|
||||||
|
uint64_t sleep_until_mach = target_mach - buffer_mach_ticks;
|
||||||
|
mach_wait_until(sleep_until_mach);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mach_absolute_time() < target_mach) {
|
||||||
|
#if defined(__aarch64__) || defined(__arm__)
|
||||||
|
asm volatile("yield" ::: "memory"); // Hardware hint, not a scheduler hint.
|
||||||
|
#else
|
||||||
|
_mm_pause();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
void NanoSleep(const duration_t duration) { SDL_DelayPrecise(duration); }
|
void NanoSleep(const duration_t duration) { SDL_DelayPrecise(duration); }
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -370,28 +370,28 @@ constexpr auto FRAME_PERIOD = std::chrono::duration_cast<std::chrono::nanosecond
|
|||||||
constexpr auto RETRACE_PERIOD = FRAME_PERIOD / 2;
|
constexpr auto RETRACE_PERIOD = FRAME_PERIOD / 2;
|
||||||
|
|
||||||
static void waitPrecise(Limiter& limiter, Limiter::duration_t targetNs) {
|
static void waitPrecise(Limiter& limiter, Limiter::duration_t targetNs) {
|
||||||
const auto sleepTime = limiter.SleepTime(targetNs);
|
const auto sleepTime = limiter.Sleep(targetNs);
|
||||||
dusk::frameUsagePct =
|
dusk::frameUsagePct =
|
||||||
100.0f * (1.0f - static_cast<float>(sleepTime) / static_cast<float>(targetNs));
|
100.0f * (1.0f - static_cast<float>(sleepTime) / static_cast<float>(targetNs));
|
||||||
limiter.Sleep(targetNs);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void waitForTick(u32 p1, u16 p2) {
|
static void waitForTick(u32 p1, u16 p2) {
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit) {
|
static Limiter limiter;
|
||||||
dusk::frameUsagePct = 0.f;
|
|
||||||
return;
|
if (dusk::frame_interp::is_enabled() && !dusk::getTransientSettings().skipFrameRateLimit) {
|
||||||
|
dusk::frameUsagePct = 0.f;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dusk::getTransientSettings().skipFrameRateLimit) {
|
if (dusk::getTransientSettings().skipFrameRateLimit) {
|
||||||
p1 = OS_TIMER_CLOCK / 120;
|
p1 = OS_TIMER_CLOCK / 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
if (fopOvlpM_IsPeek() && dusk::getTransientSettings().stateShareLoadActive) {
|
if (fopOvlpM_IsPeek() && dusk::getTransientSettings().stateShareLoadActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
ZoneScopedC(tracy::Color::DimGray);
|
ZoneScopedC(tracy::Color::DimGray);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ value_or_fun:
|
|||||||
|
|
||||||
value:
|
value:
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation && u <= 5 &&
|
if (dusk::frame_interp::is_enabled() && u <= 5 &&
|
||||||
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
|
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
|
||||||
{
|
{
|
||||||
dusk::frame_interp::request_presentation_sync();
|
dusk::frame_interp::request_presentation_sync();
|
||||||
@@ -666,7 +666,7 @@ value:
|
|||||||
|
|
||||||
value_n:
|
value_n:
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation &&
|
if (dusk::frame_interp::is_enabled() &&
|
||||||
(pN == TAdaptor_camera::sauVariableValue_3_POSITION_XYZ || pN == TAdaptor_camera::sauVariableValue_3_TARGET_POSITION_XYZ) &&
|
(pN == TAdaptor_camera::sauVariableValue_3_POSITION_XYZ || pN == TAdaptor_camera::sauVariableValue_3_TARGET_POSITION_XYZ) &&
|
||||||
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
|
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5990,7 +5990,7 @@ void daAlink_c::setItemMatrix(int param_0) {
|
|||||||
|
|
||||||
mDoMtx_stack_c::XrotS(-0x8000);
|
mDoMtx_stack_c::XrotS(-0x8000);
|
||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
Mtx boot_mtx;
|
Mtx boot_mtx;
|
||||||
mDoMtx_concat(mpLinkModel->getAnmMtx(0x18), mDoMtx_stack_c::get(), boot_mtx);
|
mDoMtx_concat(mpLinkModel->getAnmMtx(0x18), mDoMtx_stack_c::get(), boot_mtx);
|
||||||
mpLinkBootModels[1]->setAnmMtx(1, boot_mtx);
|
mpLinkBootModels[1]->setAnmMtx(1, boot_mtx);
|
||||||
@@ -19767,7 +19767,7 @@ int daAlink_c::draw() {
|
|||||||
dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0);
|
dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0);
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation &&
|
if (dusk::frame_interp::is_enabled() &&
|
||||||
mEquipItem == dItemNo_IRONBALL_e &&
|
mEquipItem == dItemNo_IRONBALL_e &&
|
||||||
mIronBallChainPos != NULL && mIronBallChainAngle != NULL)
|
mIronBallChainPos != NULL && mIronBallChainAngle != NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ static int daB_GND_Draw(b_gnd_class* i_this) {
|
|||||||
i_this->field_0x21e8.update(2, l_color, &a_this->tevStr);
|
i_this->field_0x21e8.update(2, l_color, &a_this->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->field_0x21e8);
|
dComIfGd_set3DlineMat(&i_this->field_0x21e8);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mReinsInterpCurrValid) {
|
if (i_this->mReinsInterpCurrValid) {
|
||||||
memcpy(i_this->mReinsInterpPrev, i_this->mReinsInterpCurr, sizeof(i_this->mReinsInterpCurr));
|
memcpy(i_this->mReinsInterpPrev, i_this->mReinsInterpCurr, sizeof(i_this->mReinsInterpCurr));
|
||||||
memcpy(i_this->mReinsTexInterpPrev, i_this->mReinsTexInterpCurr, sizeof(i_this->mReinsTexInterpCurr));
|
memcpy(i_this->mReinsTexInterpPrev, i_this->mReinsTexInterpCurr, sizeof(i_this->mReinsTexInterpCurr));
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ static int daE_DB_Draw(e_db_class* i_this) {
|
|||||||
i_this->stalkLine.update(12, l_color, &actor->tevStr);
|
i_this->stalkLine.update(12, l_color, &actor->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->stalkLine);
|
dComIfGd_set3DlineMat(&i_this->stalkLine);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mStalkLineInterpCurrValid) {
|
if (i_this->mStalkLineInterpCurrValid) {
|
||||||
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
|
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
|
||||||
i_this->mStalkLineInterpPrevValid = true;
|
i_this->mStalkLineInterpPrevValid = true;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ static int daE_HB_Draw(e_hb_class* i_this) {
|
|||||||
i_this->stalkLine.update(12, l_color, &actor->tevStr);
|
i_this->stalkLine.update(12, l_color, &actor->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->stalkLine);
|
dComIfGd_set3DlineMat(&i_this->stalkLine);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mStalkLineInterpCurrValid) {
|
if (i_this->mStalkLineInterpCurrValid) {
|
||||||
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
|
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
|
||||||
i_this->mStalkLineInterpPrevValid = true;
|
i_this->mStalkLineInterpPrevValid = true;
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ static int daE_MB_Draw(e_mb_class* i_this) {
|
|||||||
i_this->mRopeMat.update(16, l_color, &a_this->tevStr);
|
i_this->mRopeMat.update(16, l_color, &a_this->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->mRopeMat);
|
dComIfGd_set3DlineMat(&i_this->mRopeMat);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mRopeInterpCurrValid) {
|
if (i_this->mRopeInterpCurrValid) {
|
||||||
memcpy(i_this->mRopeInterpPrev, i_this->mRopeInterpCurr, sizeof(i_this->mRopeInterpCurr));
|
memcpy(i_this->mRopeInterpPrev, i_this->mRopeInterpCurr, sizeof(i_this->mRopeInterpCurr));
|
||||||
i_this->mRopeInterpPrevValid = true;
|
i_this->mRopeInterpPrevValid = true;
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ static int daE_S1_Draw(e_s1_class* i_this) {
|
|||||||
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
|
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mHairInterpCurrValid) {
|
if (i_this->mHairInterpCurrValid) {
|
||||||
memcpy(i_this->mHairInterpPrev, i_this->mHairInterpCurr, sizeof(i_this->mHairInterpCurr));
|
memcpy(i_this->mHairInterpPrev, i_this->mHairInterpCurr, sizeof(i_this->mHairInterpCurr));
|
||||||
i_this->mHairInterpPrevValid = true;
|
i_this->mHairInterpPrevValid = true;
|
||||||
|
|||||||
@@ -535,7 +535,7 @@ static int daE_WB_Draw(e_wb_class* i_this) {
|
|||||||
i_this->himo_tex.update(2, l_color, &actor->tevStr);
|
i_this->himo_tex.update(2, l_color, &actor->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->himo_tex);
|
dComIfGd_set3DlineMat(&i_this->himo_tex);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->himo_interp_curr_valid) {
|
if (i_this->himo_interp_curr_valid) {
|
||||||
memcpy(i_this->himo_mat_interp_prev, i_this->himo_mat_interp_curr, sizeof(i_this->himo_mat_interp_curr));
|
memcpy(i_this->himo_mat_interp_prev, i_this->himo_mat_interp_curr, sizeof(i_this->himo_mat_interp_curr));
|
||||||
memcpy(i_this->himo_tex_interp_prev, i_this->himo_tex_interp_curr, sizeof(i_this->himo_tex_interp_curr));
|
memcpy(i_this->himo_tex_interp_prev, i_this->himo_tex_interp_curr, sizeof(i_this->himo_tex_interp_curr));
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ static s32 daE_YD_Draw(e_yd_class* i_this) {
|
|||||||
i_this->mLineMat.update(12, l_color, &i_this->actor.tevStr);
|
i_this->mLineMat.update(12, l_color, &i_this->actor.tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->mLineMat);
|
dComIfGd_set3DlineMat(&i_this->mLineMat);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mLineMatInterpCurrValid) {
|
if (i_this->mLineMatInterpCurrValid) {
|
||||||
memcpy(i_this->mLineMatInterpPrev, i_this->mLineMatInterpCurr, sizeof(i_this->mLineMatInterpCurr));
|
memcpy(i_this->mLineMatInterpPrev, i_this->mLineMatInterpCurr, sizeof(i_this->mLineMatInterpCurr));
|
||||||
i_this->mLineMatInterpPrevValid = true;
|
i_this->mLineMatInterpPrevValid = true;
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ static int daE_YG_Draw(e_yg_class* i_this) {
|
|||||||
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
|
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mTentacleInterpCurrValid) {
|
if (i_this->mTentacleInterpCurrValid) {
|
||||||
memcpy(i_this->mTentacleInterpPrev, i_this->mTentacleInterpCurr, sizeof(i_this->mTentacleInterpCurr));
|
memcpy(i_this->mTentacleInterpPrev, i_this->mTentacleInterpCurr, sizeof(i_this->mTentacleInterpCurr));
|
||||||
i_this->mTentacleInterpPrevValid = true;
|
i_this->mTentacleInterpPrevValid = true;
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ static int daE_YH_Draw(e_yh_class* i_this) {
|
|||||||
i_this->mLine.update(12, l_color, &a_this->tevStr);
|
i_this->mLine.update(12, l_color, &a_this->tevStr);
|
||||||
dComIfGd_set3DlineMat(&i_this->mLine);
|
dComIfGd_set3DlineMat(&i_this->mLine);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (i_this->mLineInterpCurrValid) {
|
if (i_this->mLineInterpCurrValid) {
|
||||||
memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, sizeof(i_this->mLineInterpCurr));
|
memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, sizeof(i_this->mLineInterpCurr));
|
||||||
i_this->mLineInterpPrevValid = true;
|
i_this->mLineInterpPrevValid = true;
|
||||||
|
|||||||
@@ -3165,7 +3165,7 @@ void daHorse_c::setReinPosNormalSubstance() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
void daHorse_c::lerpControlPoints(f32 alpha) {
|
void daHorse_c::lerpControlPoints(f32 alpha) {
|
||||||
// FRAME INTERP NOTE: Currently only lerping points for Epona's reins. Need a more global solution.
|
// FRAME INTERP NOTE: Currently only lerping points for Epona's reins. Need a more global solution.
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation || !s_horseReinSimPrevValid || !s_horseReinSimCurrValid) {
|
if (!dusk::frame_interp::is_enabled() || !s_horseReinSimPrevValid || !s_horseReinSimCurrValid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int nCurr = s_horseReinSimNumCurr;
|
const int nCurr = s_horseReinSimNumCurr;
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ int daObjFchain_c::draw() {
|
|||||||
dComIfGd_getOpaListDark()->entryImm(&mShape, 0);
|
dComIfGd_getOpaListDark()->entryImm(&mShape, 0);
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (mChainInterpCurrValid) {
|
if (mChainInterpCurrValid) {
|
||||||
memcpy(mChainInterpPrev, mChainInterpCurr, sizeof(mChainInterpCurr));
|
memcpy(mChainInterpPrev, mChainInterpCurr, sizeof(mChainInterpCurr));
|
||||||
mChainInterpPrevValid = true;
|
mChainInterpPrevValid = true;
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ int daObjKLift00_c::Draw() {
|
|||||||
dComIfGd_setList();
|
dComIfGd_setList();
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
if (mChainInterpCurrValid) {
|
if (mChainInterpCurrValid) {
|
||||||
memcpy(mChainInterpPrev, mChainInterpCurr, mNumChains * sizeof(cXyz));
|
memcpy(mChainInterpPrev, mChainInterpCurr, mNumChains * sizeof(cXyz));
|
||||||
mChainInterpPrevValid = true;
|
mChainInterpPrevValid = true;
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ int daTitle_c::Execute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation) {
|
if (!dusk::frame_interp::is_enabled()) {
|
||||||
#endif
|
#endif
|
||||||
dMenu_Collect3D_c::setViewPortOffsetY(0.0f);
|
dMenu_Collect3D_c::setViewPortOffsetY(0.0f);
|
||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
@@ -354,7 +354,7 @@ void daTitle_c::fastLogoDispInit() {
|
|||||||
mProcID = 5;
|
mProcID = 5;
|
||||||
|
|
||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
dusk::frame_interp::request_presentation_sync();
|
dusk::frame_interp::request_presentation_sync();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -10431,7 +10431,7 @@ bool dCamera_c::eventCamera(s32 param_0) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
switch (var_r29) {
|
switch (var_r29) {
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
@@ -11322,7 +11322,7 @@ static int camera_execute(camera_process_class* i_this) {
|
|||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
widezoom_correction(i_this, i_this->mCamera.TrimHeight());
|
widezoom_correction(i_this, i_this->mCamera.TrimHeight());
|
||||||
|
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) {
|
dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) {
|
||||||
const auto i_this = static_cast<camera_process_class*>(pUserWork);
|
const auto i_this = static_cast<camera_process_class*>(pUserWork);
|
||||||
const auto camera = &i_this->mCamera;
|
const auto camera = &i_this->mCamera;
|
||||||
|
|||||||
@@ -991,7 +991,7 @@ void dMenu_DmapBg_c::draw() {
|
|||||||
-35.0f + (local_224.x - local_218.x),
|
-35.0f + (local_224.x - local_218.x),
|
||||||
-35.0f + (local_224.y - local_218.y));
|
-35.0f + (local_224.y - local_218.y));
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation) {
|
if (!dusk::frame_interp::is_enabled()) {
|
||||||
field_0xdda = 0;
|
field_0xdda = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -2624,7 +2624,7 @@ void dMenu_Dmap_c::zoomIn_proc() {
|
|||||||
|
|
||||||
void dMenu_Dmap_c::zoomOut_init_proc() {
|
void dMenu_Dmap_c::zoomOut_init_proc() {
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
mpDrawBg->resetScrollArrowMask();
|
mpDrawBg->resetScrollArrowMask();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1146,7 +1146,7 @@ void dMenu_Fmap_c::zoom_spot_to_region_init() {
|
|||||||
field_0x1ec = 1.0f;
|
field_0x1ec = 1.0f;
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
// Frame interp note: field_0x122d used to be set every draw, causing flickering. Do it here instead.
|
// Frame interp note: field_0x122d used to be set every draw, causing flickering. Do it here instead.
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
mpDraw2DBack->resetScrollArrowMask();
|
mpDraw2DBack->resetScrollArrowMask();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ void dMenu_Fmap2DBack_c::draw() {
|
|||||||
if (field_0x122d) {
|
if (field_0x122d) {
|
||||||
mpMeterHaihai->drawHaihai(field_0x122d);
|
mpMeterHaihai->drawHaihai(field_0x122d);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation) {
|
if (!dusk::frame_interp::is_enabled()) {
|
||||||
field_0x122d = 0;
|
field_0x122d = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -56,6 +56,23 @@ static T sanitizeEnumValue(const ConfigVar<T>& cVar, T value) {
|
|||||||
|
|
||||||
template<ConfigValue T>
|
template<ConfigValue T>
|
||||||
void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
||||||
|
if constexpr (std::is_enum_v<T>) {
|
||||||
|
if (jsonValue.is_boolean()) {
|
||||||
|
using Underlying = std::underlying_type_t<T>;
|
||||||
|
const bool b = jsonValue.get<bool>();
|
||||||
|
|
||||||
|
Underlying raw;
|
||||||
|
if constexpr (std::is_same_v<T, dusk::FrameInterpMode>) {
|
||||||
|
raw = b ? static_cast<Underlying>(2) : static_cast<Underlying>(0);
|
||||||
|
} else {
|
||||||
|
raw = b ? static_cast<Underlying>(1) : static_cast<Underlying>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cVar.setValue(sanitizeEnumValue(cVar, static_cast<T>(raw)), false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get<T>()), false);
|
cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get<T>()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +175,7 @@ namespace dusk::config {
|
|||||||
template class ConfigImpl<dusk::DiscVerificationState>;
|
template class ConfigImpl<dusk::DiscVerificationState>;
|
||||||
template class ConfigImpl<dusk::GameLanguage>;
|
template class ConfigImpl<dusk::GameLanguage>;
|
||||||
template class ConfigImpl<dusk::GyroMode>;
|
template class ConfigImpl<dusk::GyroMode>;
|
||||||
|
template class ConfigImpl<dusk::FrameInterpMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dusk::config::Register(ConfigVarBase& configVar) {
|
void dusk::config::Register(ConfigVarBase& configVar) {
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ uint64_t sim_tick_seq() {
|
|||||||
return g_sim_tick_seq;
|
return g_sim_tick_seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin_frame(bool enabled, bool is_sim_frame, float step) {
|
void begin_frame(FrameInterpMode mode, bool is_sim_frame, float step) {
|
||||||
g_enabled = enabled;
|
g_enabled = mode != FrameInterpMode::Off;
|
||||||
g_is_sim_frame = is_sim_frame;
|
g_is_sim_frame = is_sim_frame;
|
||||||
g_step = std::clamp(step, 0.0f, 1.0f);
|
g_step = std::clamp(step, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <dusk/frame_interpolation.h>
|
||||||
|
|
||||||
namespace dusk::game_clock {
|
namespace dusk::game_clock {
|
||||||
|
|
||||||
@@ -45,7 +46,8 @@ MainLoopPacer advance_main_loop() {
|
|||||||
MainLoopPacer out{};
|
MainLoopPacer out{};
|
||||||
out.presentation_dt_seconds = presentation_dt;
|
out.presentation_dt_seconds = presentation_dt;
|
||||||
|
|
||||||
const bool should_interpolate = dusk::getSettings().game.enableFrameInterpolation &&
|
const bool should_interpolate = dusk::getSettings().game.enableFrameInterpolation.getValue() !=
|
||||||
|
dusk::FrameInterpMode::Off &&
|
||||||
!dusk::getTransientSettings().skipFrameRateLimit;
|
!dusk::getTransientSettings().skipFrameRateLimit;
|
||||||
out.is_interpolating = should_interpolate;
|
out.is_interpolating = should_interpolate;
|
||||||
out.sim_pace = sim_pace();
|
out.sim_pace = sim_pace();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ UserSettings g_userSettings = {
|
|||||||
.lockAspectRatio {"video.lockAspectRatio", false},
|
.lockAspectRatio {"video.lockAspectRatio", false},
|
||||||
.enableFpsOverlay {"game.enableFpsOverlay", false},
|
.enableFpsOverlay {"game.enableFpsOverlay", false},
|
||||||
.fpsOverlayCorner {"game.fpsOverlayCorner", 0},
|
.fpsOverlayCorner {"game.fpsOverlayCorner", 0},
|
||||||
|
.maxFrameRate {"video.maxFrameRate", 240},
|
||||||
},
|
},
|
||||||
|
|
||||||
.audio = {
|
.audio = {
|
||||||
@@ -59,7 +60,7 @@ UserSettings g_userSettings = {
|
|||||||
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
|
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
|
||||||
.disableWaterRefraction {"game.disableWaterRefraction", false},
|
.disableWaterRefraction {"game.disableWaterRefraction", false},
|
||||||
.enableTextureReplacements {"game.enableTextureReplacements", true},
|
.enableTextureReplacements {"game.enableTextureReplacements", true},
|
||||||
.enableFrameInterpolation {"game.enableFrameInterpolation", false},
|
.enableFrameInterpolation {"game.enableFrameInterpolation", FrameInterpMode::Off},
|
||||||
.internalResolutionScale {"game.internalResolutionScale", 0},
|
.internalResolutionScale {"game.internalResolutionScale", 0},
|
||||||
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
|
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
|
||||||
.enableDepthOfField {"game.enableDepthOfField", true},
|
.enableDepthOfField {"game.enableDepthOfField", true},
|
||||||
@@ -178,6 +179,7 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.video.lockAspectRatio);
|
Register(g_userSettings.video.lockAspectRatio);
|
||||||
Register(g_userSettings.video.enableFpsOverlay);
|
Register(g_userSettings.video.enableFpsOverlay);
|
||||||
Register(g_userSettings.video.fpsOverlayCorner);
|
Register(g_userSettings.video.fpsOverlayCorner);
|
||||||
|
Register(g_userSettings.video.maxFrameRate);
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
Register(g_userSettings.audio.masterVolume);
|
Register(g_userSettings.audio.masterVolume);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ void applyPresetDusk() {
|
|||||||
s.game.enableQuickTransform.setValue(true);
|
s.game.enableQuickTransform.setValue(true);
|
||||||
s.game.instantSaves.setValue(true);
|
s.game.instantSaves.setValue(true);
|
||||||
s.game.midnasLamentNonStop.setValue(true);
|
s.game.midnasLamentNonStop.setValue(true);
|
||||||
s.game.enableFrameInterpolation.setValue(true);
|
s.game.enableFrameInterpolation.setValue(FrameInterpMode::Unlimited);
|
||||||
s.game.sunsSong.setValue(true);
|
s.game.sunsSong.setValue(true);
|
||||||
s.game.bloomMode.setValue(BloomMode::Dusk);
|
s.game.bloomMode.setValue(BloomMode::Dusk);
|
||||||
s.game.internalResolutionScale.setValue(0);
|
s.game.internalResolutionScale.setValue(0);
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ constexpr std::array kFpsOverlayCornerNames = {
|
|||||||
"Bottom Right",
|
"Bottom Right",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::array kInterpolationModes = {
|
||||||
|
"Off",
|
||||||
|
"Capped",
|
||||||
|
"Unlimited",
|
||||||
|
};
|
||||||
|
|
||||||
constexpr std::array kGyroInputModeLabels = {
|
constexpr std::array kGyroInputModeLabels = {
|
||||||
"Sensor",
|
"Sensor",
|
||||||
"Mouse",
|
"Mouse",
|
||||||
@@ -357,7 +363,7 @@ const Rml::String kBloomHelpText =
|
|||||||
const Rml::String kBloomBrightnessHelpText =
|
const Rml::String kBloomBrightnessHelpText =
|
||||||
"Configure bloom intensity. Higher values make bright areas glow more strongly.";
|
"Configure bloom intensity. Higher values make bright areas glow more strongly.";
|
||||||
const Rml::String kUnlockFramerateHelpText =
|
const Rml::String kUnlockFramerateHelpText =
|
||||||
"Uses inter-frame interpolation to enable higher frame rates.<br/><br/>May introduce minor "
|
"<br/>Uses inter-frame interpolation to enable higher frame rates.<br/><br/>May introduce minor "
|
||||||
"visual artifacts or animation glitches.";
|
"visual artifacts or animation glitches.";
|
||||||
|
|
||||||
int float_setting_percent(ConfigVar<float>& var) {
|
int float_setting_percent(ConfigVar<float>& var) {
|
||||||
@@ -440,6 +446,31 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar<f
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SelectButton& config_int_select(Pane& leftPane, Pane& rightPane, ConfigVar<int>& var,
|
||||||
|
Rml::String key, Rml::String helpText, int min, int max, int step = 5,
|
||||||
|
std::function<bool()> isDisabled = {}, std::string suffix = "") {
|
||||||
|
auto& button = leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||||
|
.key = std::move(key),
|
||||||
|
.getValue = [&var] { return var; },
|
||||||
|
.setValue =
|
||||||
|
[&var, min, max](int value) {
|
||||||
|
var.setValue(std::clamp(value, min, max));
|
||||||
|
config::Save();
|
||||||
|
},
|
||||||
|
.isDisabled = std::move(isDisabled),
|
||||||
|
.isModified = [&var] { return var.getValue() != var.getDefaultValue(); },
|
||||||
|
.min = min,
|
||||||
|
.max = max,
|
||||||
|
.step = step,
|
||||||
|
.suffix = suffix,
|
||||||
|
});
|
||||||
|
leftPane.register_control(button, rightPane, [helpText = std::move(helpText)](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
pane.add_text(helpText);
|
||||||
|
});
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void graphics_tuner_control(Window& window, Pane& leftPane, Pane& rightPane, ConfigVar<T>& var,
|
void graphics_tuner_control(Window& window, Pane& leftPane, Pane& rightPane, ConfigVar<T>& var,
|
||||||
const GraphicsTunerProps& props, bool prelaunch) {
|
const GraphicsTunerProps& props, bool prelaunch) {
|
||||||
@@ -803,11 +834,39 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
.helpText = "Enable installed texture replacements.",
|
.helpText = "Enable installed texture replacements.",
|
||||||
.onChange = [](bool value) { aurora_set_texture_replacements_enabled(value); },
|
.onChange = [](bool value) { aurora_set_texture_replacements_enabled(value); },
|
||||||
});
|
});
|
||||||
config_bool_select(leftPane, rightPane, getSettings().game.enableFrameInterpolation,
|
leftPane.register_control(
|
||||||
{
|
leftPane.add_select_button({
|
||||||
.key = "Unlock Framerate",
|
.key = "Unlock Framerate",
|
||||||
.helpText = kUnlockFramerateHelpText,
|
.getValue =
|
||||||
|
[] {
|
||||||
|
return kInterpolationModes[static_cast<u8>(getSettings().game.enableFrameInterpolation.getValue())];
|
||||||
|
},
|
||||||
|
.isModified =
|
||||||
|
[] {
|
||||||
|
return getSettings().game.enableFrameInterpolation.getValue() !=
|
||||||
|
getSettings().game.enableFrameInterpolation.getDefaultValue();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [](Pane& pane) {
|
||||||
|
for (int i = 0; i < kInterpolationModes.size(); i++) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = kInterpolationModes[i],
|
||||||
|
.isSelected =
|
||||||
|
[i] {
|
||||||
|
return getSettings().game.enableFrameInterpolation.getValue() == static_cast<FrameInterpMode>(i);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on_pressed([i] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
getSettings().game.enableFrameInterpolation.setValue(static_cast<FrameInterpMode>(i));
|
||||||
|
config::Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pane.add_rml(kUnlockFramerateHelpText);
|
||||||
});
|
});
|
||||||
|
config_int_select(leftPane, rightPane, getSettings().video.maxFrameRate,
|
||||||
|
"Framerate Cap", "Limit the framerate to the specified value.", 30, 540, 1,
|
||||||
|
[] { return getSettings().game.enableFrameInterpolation.getValue() != FrameInterpMode::Capped; });
|
||||||
config_bool_select(leftPane, rightPane, getSettings().game.enableDepthOfField,
|
config_bool_select(leftPane, rightPane, getSettings().game.enableDepthOfField,
|
||||||
{
|
{
|
||||||
.key = "Enable Depth of Field",
|
.key = "Enable Depth of Field",
|
||||||
|
|||||||
@@ -2410,7 +2410,7 @@ void mDoExt_3DlineMat0_c::draw() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation)
|
if (!dusk::frame_interp::is_enabled())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
field_0x16 ^= (u8)1;
|
field_0x16 ^= (u8)1;
|
||||||
@@ -2740,7 +2740,7 @@ void mDoExt_3DlineMat1_c::draw() {
|
|||||||
}
|
}
|
||||||
GXSetTexCoordScaleManually(GX_TEXCOORD0, 0, 0, 0);
|
GXSetTexCoordScaleManually(GX_TEXCOORD0, 0, 0, 0);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation)
|
if (!dusk::frame_interp::is_enabled())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
mIsDrawn ^= (u8)1;
|
mIsDrawn ^= (u8)1;
|
||||||
@@ -2822,7 +2822,7 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
const cXyz& lineEye = (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation) ? *presentationEye : sp_3c->lookat.eye;
|
const cXyz& lineEye = (presentationEye != nullptr && dusk::frame_interp::is_enabled()) ? *presentationEye : sp_3c->lookat.eye;
|
||||||
sp_13c = *local_r27 - lineEye;
|
sp_13c = *local_r27 - lineEye;
|
||||||
#else
|
#else
|
||||||
sp_13c = *local_r27 - sp_3c->lookat.eye;
|
sp_13c = *local_r27 - sp_3c->lookat.eye;
|
||||||
@@ -2982,7 +2982,7 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
|
|||||||
local_r27 = sp_38[0].field_0x0;
|
local_r27 = sp_38[0].field_0x0;
|
||||||
size_p = sp_38->field_0x4;
|
size_p = sp_38->field_0x4;
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation && size_p == NULL) {
|
if (presentationEye != nullptr && dusk::frame_interp::is_enabled() && size_p == NULL) {
|
||||||
sp_38 += 1;
|
sp_38 += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3001,7 +3001,7 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
|
|||||||
local_f30 = sp_130.abs();
|
local_f30 = sp_130.abs();
|
||||||
local_f31 += local_f30 * 0.1f;
|
local_f31 += local_f30 * 0.1f;
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
const cXyz& lineEye = (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation) ? *presentationEye : stack_3c->lookat.eye;
|
const cXyz& lineEye = (presentationEye != nullptr && dusk::frame_interp::is_enabled()) ? *presentationEye : stack_3c->lookat.eye;
|
||||||
sp_13c = local_r27[0] - lineEye;
|
sp_13c = local_r27[0] - lineEye;
|
||||||
#else
|
#else
|
||||||
sp_13c = local_r27[0] - stack_3c->lookat.eye;
|
sp_13c = local_r27[0] - stack_3c->lookat.eye;
|
||||||
@@ -3077,7 +3077,7 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
|
|||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
void mDoExt_3DlineMat1_c::refreshGeometryForPresentationEye(const cXyz& eye) {
|
void mDoExt_3DlineMat1_c::refreshGeometryForPresentationEye(const cXyz& eye) {
|
||||||
if (!dusk::getSettings().game.enableFrameInterpolation) {
|
if (!dusk::frame_interp::is_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mInterpLineKind == 1) {
|
if (mInterpLineKind == 1) {
|
||||||
|
|||||||
@@ -2063,7 +2063,7 @@ static void captureScreenPerspDrawInfo(JPADrawInfo& info) {
|
|||||||
static void drawItem3D() {
|
static void drawItem3D() {
|
||||||
ZoneScoped;
|
ZoneScoped;
|
||||||
#ifdef TARGET_PC
|
#ifdef TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
// FRAME INTERP NOTE: Title screen needs 0.0f while everything else that runs through this is -100.0f.
|
// FRAME INTERP NOTE: Title screen needs 0.0f while everything else that runs through this is -100.0f.
|
||||||
if (fopAcM_SearchByName(fpcNm_TITLE_e) != nullptr) {
|
if (fopAcM_SearchByName(fpcNm_TITLE_e) != nullptr) {
|
||||||
dMenu_Collect3D_c::setViewPortOffsetY(0.0f);
|
dMenu_Collect3D_c::setViewPortOffsetY(0.0f);
|
||||||
@@ -2241,7 +2241,7 @@ int mDoGph_Painter() {
|
|||||||
#endif
|
#endif
|
||||||
dKy_setLight();
|
dKy_setLight();
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
dKy_setLight_again();
|
dKy_setLight_again();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2296,7 +2296,7 @@ int mDoGph_Painter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
if (dusk::frame_interp::is_enabled()) {
|
||||||
// FRAME INTERP NOTE: Currently only recalculating points for Epona's reins. Need a more global solution.
|
// FRAME INTERP NOTE: Currently only recalculating points for Epona's reins. Need a more global solution.
|
||||||
if (daHorse_c* horse = dComIfGp_getHorseActor()) {
|
if (daHorse_c* horse = dComIfGp_getHorseActor()) {
|
||||||
horse->lerpControlPoints(dusk::frame_interp::get_interpolation_step());
|
horse->lerpControlPoints(dusk::frame_interp::get_interpolation_step());
|
||||||
|
|||||||
+23
-3
@@ -28,6 +28,7 @@
|
|||||||
#include "d/d_s_logo.h"
|
#include "d/d_s_logo.h"
|
||||||
#include "d/d_s_menu.h"
|
#include "d/d_s_menu.h"
|
||||||
#include "d/d_s_play.h"
|
#include "d/d_s_play.h"
|
||||||
|
#include "dusk/time.h"
|
||||||
#include "f_ap/f_ap_game.h"
|
#include "f_ap/f_ap_game.h"
|
||||||
#include "f_op/f_op_msg.h"
|
#include "f_op/f_op_msg.h"
|
||||||
#include "m_Do/m_Do_MemCard.h"
|
#include "m_Do/m_Do_MemCard.h"
|
||||||
@@ -279,8 +280,9 @@ void main01(void) {
|
|||||||
const auto pacing = dusk::game_clock::advance_main_loop();
|
const auto pacing = dusk::game_clock::advance_main_loop();
|
||||||
if (pacing.is_interpolating) {
|
if (pacing.is_interpolating) {
|
||||||
if (pacing.sim_ticks_to_run > 0) {
|
if (pacing.sim_ticks_to_run > 0) {
|
||||||
dusk::frame_interp::begin_frame(true, true, 0.0f);
|
dusk::frame_interp::begin_frame(dusk::getSettings().game.enableFrameInterpolation, true, 0.0f);
|
||||||
dusk::frame_interp::set_ui_tick_pending(true);
|
dusk::frame_interp::set_ui_tick_pending(true);
|
||||||
|
|
||||||
for (int sim_tick = 0; sim_tick < pacing.sim_ticks_to_run; ++sim_tick) {
|
for (int sim_tick = 0; sim_tick < pacing.sim_ticks_to_run; ++sim_tick) {
|
||||||
dusk::frame_interp::begin_sim_tick();
|
dusk::frame_interp::begin_sim_tick();
|
||||||
mDoCPd_c::read();
|
mDoCPd_c::read();
|
||||||
@@ -291,7 +293,7 @@ void main01(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dusk::frame_interp::begin_frame(true, false,
|
dusk::frame_interp::begin_frame(dusk::getSettings().game.enableFrameInterpolation, false,
|
||||||
dusk::game_clock::sample_interpolation_step());
|
dusk::game_clock::sample_interpolation_step());
|
||||||
dusk::frame_interp::interpolate();
|
dusk::frame_interp::interpolate();
|
||||||
dusk::frame_interp::begin_presentation_camera();
|
dusk::frame_interp::begin_presentation_camera();
|
||||||
@@ -301,7 +303,7 @@ void main01(void) {
|
|||||||
dusk::frame_interp::end_presentation_camera();
|
dusk::frame_interp::end_presentation_camera();
|
||||||
dusk::frame_interp::set_ui_tick_pending(false);
|
dusk::frame_interp::set_ui_tick_pending(false);
|
||||||
} else {
|
} else {
|
||||||
dusk::frame_interp::begin_frame(false, true, 0.0f);
|
dusk::frame_interp::begin_frame(dusk::FrameInterpMode::Off, true, 0.0f);
|
||||||
dusk::frame_interp::set_ui_tick_pending(true);
|
dusk::frame_interp::set_ui_tick_pending(true);
|
||||||
|
|
||||||
// Game Inputs
|
// Game Inputs
|
||||||
@@ -315,8 +317,26 @@ void main01(void) {
|
|||||||
mDoAud_Execute();
|
mDoAud_Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Limiter main_loop_limiter;
|
||||||
|
static double last_fps_setting = 0.0;
|
||||||
|
static Limiter::duration_t target_ns = 0;
|
||||||
|
|
||||||
|
if (dusk::getSettings().game.enableFrameInterpolation.getValue() == dusk::FrameInterpMode::Capped && !dusk::getTransientSettings().skipFrameRateLimit) {
|
||||||
|
double current_fps = dusk::getSettings().video.maxFrameRate.getValue();
|
||||||
|
if (current_fps != last_fps_setting) {
|
||||||
|
last_fps_setting = current_fps;
|
||||||
|
target_ns = static_cast<Limiter::duration_t>(1'000'000'000.0 / current_fps);
|
||||||
|
}
|
||||||
|
|
||||||
|
Limiter::duration_t sleepTime = main_loop_limiter.Sleep(target_ns);
|
||||||
|
dusk::frameUsagePct = 100.0f * (1.0f - static_cast<float>(sleepTime) / static_cast<float>(target_ns));
|
||||||
|
} else {
|
||||||
|
main_loop_limiter.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
aurora_end_frame();
|
aurora_end_frame();
|
||||||
|
|
||||||
|
|
||||||
FrameMark;
|
FrameMark;
|
||||||
|
|
||||||
#ifdef DUSK_DISCORD
|
#ifdef DUSK_DISCORD
|
||||||
|
|||||||
Reference in New Issue
Block a user