From 4680d758a622f2d4b5284bd73ed51e31234b5aa4 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 8 Jul 2025 15:55:50 +0600 Subject: [PATCH 1/8] 1ms --- src/86box.c | 4 ++-- src/qt/qt_main.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/86box.c b/src/86box.c index ae58aca03..74b95aeae 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1714,7 +1714,7 @@ pc_run(void) /* Run a block of code. */ startblit(); - cpu_exec((int32_t) cpu_s->rspeed / 100); + cpu_exec((int32_t) cpu_s->rspeed / 1000); ack_pause(); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ if (gdbstub_step == GDBSTUB_EXEC) { @@ -1729,7 +1729,7 @@ pc_run(void) /* Done with this frame, update statistics. */ framecount++; - if (++framecountx >= 100) { + if (++framecountx >= 1000) { framecountx = 0; frames = 0; } diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index da57bcf80..077e92641 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -448,15 +448,15 @@ main_thread_fn() const uint64_t new_time = elapsed_timer.elapsed(); #ifdef USE_GDBSTUB if (gdbstub_next_asap && (drawits <= 0)) - drawits = 10; + drawits = 1; else #endif drawits += static_cast(new_time - old_time); old_time = new_time; if (drawits > 0 && !dopause) { /* Yes, so do one frame now. */ - drawits -= 10; - if (drawits > 50) + drawits -= 1; + if (drawits > 500) drawits = 0; #ifdef USE_INSTRUMENT @@ -475,7 +475,7 @@ main_thread_fn() } #endif /* Every 200 frames we save the machine status. */ - if (++frames >= 200 && nvr_dosave) { + if (++frames >= 2000 && nvr_dosave) { qt_nvr_save(); nvr_dosave = 0; frames = 0; @@ -493,7 +493,7 @@ main_thread_fn() if (dopause) ack_pause(); - plat_delay_ms(1); + //plat_delay_ms(1); } } From ddea070faae91a6573395e2b16c3ee18d8941a95 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 8 Jul 2025 16:51:53 +0600 Subject: [PATCH 2/8] Fix cycle period of dynarec --- src/cpu/386_dynarec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index fd6285057..dfad67020 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -739,7 +739,7 @@ exec386_dynarec(int32_t cycs) uint64_t oldtsc; uint64_t delta; - int32_t cyc_period = cycs / 2000; /*5us*/ + int32_t cyc_period = cycs / 200; /*5us*/ # ifdef USE_ACYCS acycs = 0; From 7b6d726c18cb82fb980ebd69cce5700e4353f5ae Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 01:14:08 +0600 Subject: [PATCH 3/8] Restore 1 ms sleep --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 077e92641..57c6a3996 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -493,7 +493,7 @@ main_thread_fn() if (dopause) ack_pause(); - //plat_delay_ms(1); + plat_delay_ms(1); } } From b45d7962185f2ac0a964790e4e2aae1d67a54fc0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 02:11:55 +0600 Subject: [PATCH 4/8] Allow up to 50 missed CPU frames instead of 500 --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 57c6a3996..73c501abf 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -456,7 +456,7 @@ main_thread_fn() if (drawits > 0 && !dopause) { /* Yes, so do one frame now. */ drawits -= 1; - if (drawits > 500) + if (drawits > 50) drawits = 0; #ifdef USE_INSTRUMENT From 916533499ae30e819fc32718f6a4b15c0b33777b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 12:59:16 +0600 Subject: [PATCH 5/8] Add 10ms interval option (not exposed yet to UI) Fix percentage counter --- src/86box.c | 17 +++++++++-------- src/config.c | 6 ++++++ src/cpu/386_dynarec.c | 2 +- src/include/86box/86box.h | 1 + src/qt/qt_main.cpp | 8 ++++---- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/86box.c b/src/86box.c index 74b95aeae..8b57e4b90 100644 --- a/src/86box.c +++ b/src/86box.c @@ -217,6 +217,7 @@ int test_mode = 0; /* (C) Test mo char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ int sound_muted = 0; /* (C) Is sound muted? */ int inhibit_multimedia_keys; /* (C) Inhibit multimedia keys on Windows. */ +int force_10ms; /* (C) Force 10ms CPU frame intervals. */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are present */ @@ -1592,19 +1593,19 @@ update_mouse_msg(void) *(wcp - 1) = L'\0'; mbstowcs(wcpu, cpu_s->name, strlen(cpu_s->name) + 1); #ifdef _WIN32 - swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i%%%% - %ls", + swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%.1lf%%%% - %ls", plat_get_string(STRING_MOUSE_CAPTURE)); - swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i%%%% - %ls", + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%.1lf%%%% - %ls", (mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB)); wcsncpy(mouse_msg[2], L"%i%%", sizeof_w(mouse_msg[2])); #else - swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls", + swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls - %ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, plat_get_string(STRING_MOUSE_CAPTURE)); - swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls", + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls - %ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, (mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB)); - swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls", + swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu); #endif } @@ -1714,7 +1715,7 @@ pc_run(void) /* Run a block of code. */ startblit(); - cpu_exec((int32_t) cpu_s->rspeed / 1000); + cpu_exec((int32_t) cpu_s->rspeed / (force_10ms ? 100 : 1000)); ack_pause(); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ if (gdbstub_step == GDBSTUB_EXEC) { @@ -1729,14 +1730,14 @@ pc_run(void) /* Done with this frame, update statistics. */ framecount++; - if (++framecountx >= 1000) { + if (++framecountx >= (force_10ms ? 100 : 1000)) { framecountx = 0; frames = 0; } if (title_update) { mouse_msg_idx = ((mouse_type == MOUSE_TYPE_NONE) || (mouse_input_mode >= 1)) ? 2 : !!mouse_capture; - swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps); + swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], (double)fps / (force_10ms ? 1. : 10.)); #ifdef __APPLE__ /* Needed due to modifying the UI on the non-main thread is a big no-no. */ dispatch_async_f(dispatch_get_main_queue(), wcsdup((const wchar_t *) temp), _ui_window_title); diff --git a/src/config.c b/src/config.c index 272ca43b7..76abbae23 100644 --- a/src/config.c +++ b/src/config.c @@ -144,6 +144,8 @@ load_general(void) video_grayscale = ini_section_get_int(cat, "video_grayscale", 0); video_graytype = ini_section_get_int(cat, "video_graytype", 0); + force_10ms = !!ini_section_get_int(cat, "force_10ms", 0); + rctrl_is_lalt = ini_section_get_int(cat, "rctrl_is_lalt", 0); update_icons = ini_section_get_int(cat, "update_icons", 1); @@ -1947,6 +1949,10 @@ save_general(void) const char *va_name; + ini_section_set_int(cat, "force_10ms", force_10ms); + if (force_10ms == 0) + ini_section_delete_var(cat, "force_10ms"); + ini_section_set_int(cat, "inhibit_multimedia_keys", inhibit_multimedia_keys); if (inhibit_multimedia_keys == 0) ini_section_delete_var(cat, "inhibit_multimedia_keys"); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index dfad67020..23f3f1e35 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -739,7 +739,7 @@ exec386_dynarec(int32_t cycs) uint64_t oldtsc; uint64_t delta; - int32_t cyc_period = cycs / 200; /*5us*/ + int32_t cyc_period = cycs / (force_10ms ? 2000 : 200); /*5us*/ # ifdef USE_ACYCS acycs = 0; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e572d670b..bba99b555 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -154,6 +154,7 @@ extern int confirm_reset; /* (C) enable reset confirmation */ extern int confirm_exit; /* (C) enable exit confirmation */ extern int confirm_save; /* (C) enable save confirmation */ extern int enable_discord; /* (C) enable Discord integration */ +extern int force_10ms; /* (C) force 10ms CPU frame interval */ extern int other_ide_present; /* IDE controllers from non-IDE cards are present */ extern int other_scsi_present; /* SCSI controllers from non-SCSI cards are present */ diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 73c501abf..1a1f71acb 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -448,14 +448,14 @@ main_thread_fn() const uint64_t new_time = elapsed_timer.elapsed(); #ifdef USE_GDBSTUB if (gdbstub_next_asap && (drawits <= 0)) - drawits = 1; + drawits = force_10ms ? 10 : 1; else #endif drawits += static_cast(new_time - old_time); old_time = new_time; if (drawits > 0 && !dopause) { /* Yes, so do one frame now. */ - drawits -= 1; + drawits -= force_10ms ? 10 : 1; if (drawits > 50) drawits = 0; @@ -474,8 +474,8 @@ main_thread_fn() break; } #endif - /* Every 200 frames we save the machine status. */ - if (++frames >= 2000 && nvr_dosave) { + /* Every 2 emulated seconds we save the machine status. */ + if (++frames >= (force_10ms ? 200 : 2000) && nvr_dosave) { qt_nvr_save(); nvr_dosave = 0; frames = 0; From b2f99d72079542de421c4f2770d4e5a5b813bf7f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 13:36:57 +0600 Subject: [PATCH 6/8] Add CPU frame size option --- src/qt/qt_settingsmachine.cpp | 16 ++++ src/qt/qt_settingsmachine.hpp | 4 + src/qt/qt_settingsmachine.ui | 138 ++++++++++++++++++++++------------ 3 files changed, 111 insertions(+), 47 deletions(-) diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp index fb5576f69..0063ac727 100644 --- a/src/qt/qt_settingsmachine.cpp +++ b/src/qt/qt_settingsmachine.cpp @@ -117,6 +117,9 @@ SettingsMachine::SettingsMachine(QWidget *parent) ui->comboBoxMachineType->setCurrentIndex(-1); ui->comboBoxMachineType->setCurrentIndex(selectedMachineType); + ui->radioButtonLargerFrames->setChecked(force_10ms); + ui->radioButtonSmallerFrames->setChecked(!force_10ms); + #ifndef USE_DYNAREC ui->checkBoxDynamicRecompiler->setEnabled(false); ui->checkBoxDynamicRecompiler->setVisible(false); @@ -137,6 +140,7 @@ SettingsMachine::save() fpu_type = ui->comboBoxFPU->currentData().toInt(); cpu_use_dynarec = ui->checkBoxDynamicRecompiler->isChecked() ? 1 : 0; fpu_softfloat = ui->checkBoxFPUSoftfloat->isChecked() ? 1 : 0; + force_10ms = ui->radioButtonLargerFrames->isChecked() ? 1 : 0; int64_t temp_mem_size; if (machine_get_ram_granularity(machine) < 1024) @@ -359,3 +363,15 @@ void SettingsMachine::on_checkBoxFPUSoftfloat_stateChanged(int state) { ui->softFloatWarningText->setVisible(false); } } + +void SettingsMachine::on_radioButtonSmallerFrames_clicked() +{ + ui->radioButtonLargerFrames->setChecked(false); +} + + +void SettingsMachine::on_radioButtonLargerFrames_clicked() +{ + ui->radioButtonSmallerFrames->setChecked(false); +} + diff --git a/src/qt/qt_settingsmachine.hpp b/src/qt/qt_settingsmachine.hpp index 864894447..36ece7f18 100644 --- a/src/qt/qt_settingsmachine.hpp +++ b/src/qt/qt_settingsmachine.hpp @@ -28,6 +28,10 @@ private slots: void on_comboBoxMachineType_currentIndexChanged(int index); void on_checkBoxFPUSoftfloat_stateChanged(int state); + void on_radioButtonSmallerFrames_clicked(); + + void on_radioButtonLargerFrames_clicked(); + private: Ui::SettingsMachine *ui; }; diff --git a/src/qt/qt_settingsmachine.ui b/src/qt/qt_settingsmachine.ui index e3b3cdbde..0cd15e749 100644 --- a/src/qt/qt_settingsmachine.ui +++ b/src/qt/qt_settingsmachine.ui @@ -41,7 +41,6 @@ 0 - @@ -49,7 +48,6 @@ - @@ -57,7 +55,6 @@ - @@ -65,7 +62,6 @@ - @@ -73,7 +69,6 @@ - @@ -84,7 +79,6 @@ - @@ -92,7 +86,6 @@ - @@ -100,7 +93,6 @@ - @@ -129,18 +121,16 @@ - Frequency: - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - @@ -157,7 +147,6 @@ - @@ -165,7 +154,6 @@ - @@ -173,7 +161,6 @@ - @@ -196,7 +183,6 @@ - @@ -213,7 +199,6 @@ - @@ -268,7 +253,6 @@ - @@ -286,7 +270,6 @@ - @@ -302,7 +285,6 @@ - @@ -310,7 +292,6 @@ - @@ -321,7 +302,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -333,39 +314,102 @@ - - - - - 0 - 0 - - - - Time synchronization - - - - - - Disabled + + + + + + + 0 + 0 + + + Time synchronization + + + + + + Disabled + + + + + + + Enabled (UTC) + + + + + + + Enabled (local time) + + + + - - - - Enabled (local time) + + + + Qt::Orientation::Horizontal + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + CPU frame size + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop + + + + + + Larger frames (less smooth) + + + + + + + Smaller frames (smoother) + + + + - - - - Enabled (UTC) + + + + Qt::Orientation::Vertical - + + + 20 + 40 + + + @@ -373,7 +417,7 @@ - Qt::Vertical + Qt::Orientation::Vertical From 16f15ed53ea83a8ea560ce924e3388ee25cc0885 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 16:45:11 +0600 Subject: [PATCH 7/8] Use integer instead of float for percentage calculations --- src/86box.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/86box.c b/src/86box.c index 8b57e4b90..277d842b4 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1593,19 +1593,19 @@ update_mouse_msg(void) *(wcp - 1) = L'\0'; mbstowcs(wcpu, cpu_s->name, strlen(cpu_s->name) + 1); #ifdef _WIN32 - swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%.1lf%%%% - %ls", + swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i.%%i%%%% - %ls", plat_get_string(STRING_MOUSE_CAPTURE)); - swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%.1lf%%%% - %ls", + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i.%%i%%%% - %ls", (mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB)); wcsncpy(mouse_msg[2], L"%i%%", sizeof_w(mouse_msg[2])); #else - swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls - %ls", + swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls - %ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, plat_get_string(STRING_MOUSE_CAPTURE)); - swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls - %ls", + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls - %ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, (mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB)); - swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%.1lf%%%% - %ls - %ls/%ls", + swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls", EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu); #endif } @@ -1737,7 +1737,7 @@ pc_run(void) if (title_update) { mouse_msg_idx = ((mouse_type == MOUSE_TYPE_NONE) || (mouse_input_mode >= 1)) ? 2 : !!mouse_capture; - swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], (double)fps / (force_10ms ? 1. : 10.)); + swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps / (force_10ms ? 1 : 10), force_10ms ? 0 : (fps % 10)); #ifdef __APPLE__ /* Needed due to modifying the UI on the non-main thread is a big no-no. */ dispatch_async_f(dispatch_get_main_queue(), wcsdup((const wchar_t *) temp), _ui_window_title); From 1a18bf58acfc2e32c139c2b1e7440af2fd442ee3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 9 Jul 2025 17:07:33 +0600 Subject: [PATCH 8/8] Make emulator thread time critical if possible on Windows to reduce fluctuations --- src/qt/qt_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 1a1f71acb..d02ed6b67 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -437,6 +437,9 @@ main_thread_fn() int frames; QThread::currentThread()->setPriority(QThread::HighestPriority); +#ifdef _WIN32 + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); +#endif plat_set_thread_name(nullptr, "main_thread_fn"); framecountx = 0; // title_update = 1;