mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/master' into feature/savestates-2
This commit is contained in:
		
						commit
						03379b2072
					
				
					 17 changed files with 224 additions and 93 deletions
				
			
		|  | @ -104,6 +104,8 @@ void Config::ReadValues() { | ||||||
| 
 | 
 | ||||||
|     // Core
 |     // Core
 | ||||||
|     Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); |     Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | ||||||
|  |     Settings::values.cpu_clock_percentage = | ||||||
|  |         sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100); | ||||||
| 
 | 
 | ||||||
|     // Renderer
 |     // Renderer
 | ||||||
|     Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false); |     Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false); | ||||||
|  |  | ||||||
|  | @ -91,6 +91,12 @@ udp_pad_index= | ||||||
| # 0: Interpreter (slow), 1 (default): JIT (fast) | # 0: Interpreter (slow), 1 (default): JIT (fast) | ||||||
| use_cpu_jit = | use_cpu_jit = | ||||||
| 
 | 
 | ||||||
|  | # Change the Clock Frequency of the emulated 3DS CPU. | ||||||
|  | # Underclocking can increase the performance of the game at the risk of freezing. | ||||||
|  | # Overclocking may fix lag that happens on console, but also comes with the risk of freezing. | ||||||
|  | # Range is any positive integer (but we suspect 25 - 400 is a good idea) Default is 100 | ||||||
|  | cpu_clock_percentage = | ||||||
|  | 
 | ||||||
| [Renderer] | [Renderer] | ||||||
| # Whether to render using GLES or OpenGL | # Whether to render using GLES or OpenGL | ||||||
| # 0 (default): OpenGL, 1: GLES | # 0 (default): OpenGL, 1: GLES | ||||||
|  |  | ||||||
|  | @ -253,6 +253,8 @@ void Config::ReadCoreValues() { | ||||||
|     qt_config->beginGroup(QStringLiteral("Core")); |     qt_config->beginGroup(QStringLiteral("Core")); | ||||||
| 
 | 
 | ||||||
|     Settings::values.use_cpu_jit = ReadSetting(QStringLiteral("use_cpu_jit"), true).toBool(); |     Settings::values.use_cpu_jit = ReadSetting(QStringLiteral("use_cpu_jit"), true).toBool(); | ||||||
|  |     Settings::values.cpu_clock_percentage = | ||||||
|  |         ReadSetting(QStringLiteral("cpu_clock_percentage"), 100).toInt(); | ||||||
| 
 | 
 | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
| } | } | ||||||
|  | @ -737,6 +739,8 @@ void Config::SaveCoreValues() { | ||||||
|     qt_config->beginGroup(QStringLiteral("Core")); |     qt_config->beginGroup(QStringLiteral("Core")); | ||||||
| 
 | 
 | ||||||
|     WriteSetting(QStringLiteral("use_cpu_jit"), Settings::values.use_cpu_jit, true); |     WriteSetting(QStringLiteral("use_cpu_jit"), Settings::values.use_cpu_jit, true); | ||||||
|  |     WriteSetting(QStringLiteral("cpu_clock_percentage"), Settings::values.cpu_clock_percentage, | ||||||
|  |                  100); | ||||||
| 
 | 
 | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ | ||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>345</width> |     <width>345</width> | ||||||
|     <height>357</height> |     <height>358</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="windowTitle"> |   <property name="windowTitle"> | ||||||
|  | @ -68,6 +68,13 @@ | ||||||
|         <string>Emulation</string> |         <string>Emulation</string> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QGridLayout" name="gridLayout"> |        <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |         <item row="1" column="0"> | ||||||
|  |          <widget class="QCheckBox" name="toggle_frame_limit"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Limit Speed Percent</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|         <item row="0" column="0"> |         <item row="0" column="0"> | ||||||
|          <widget class="QLabel" name="label"> |          <widget class="QLabel" name="label"> | ||||||
|           <property name="text"> |           <property name="text"> | ||||||
|  | @ -119,13 +126,6 @@ | ||||||
|           </item> |           </item> | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|         <item row="1" column="0"> |  | ||||||
|          <widget class="QCheckBox" name="toggle_frame_limit"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Limit Speed Percent</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="1" column="1"> |         <item row="1" column="1"> | ||||||
|          <widget class="QSpinBox" name="frame_limit"> |          <widget class="QSpinBox" name="frame_limit"> | ||||||
|           <property name="suffix"> |           <property name="suffix"> | ||||||
|  |  | ||||||
|  | @ -217,6 +217,17 @@ static const std::array<const char*, 187> country_names = { | ||||||
|     QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
 |     QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | // The QSlider doesn't have an easy way to set a custom step amount,
 | ||||||
|  | // so we can just convert from the sliders range (0 - 79) to the expected
 | ||||||
|  | // settings range (5 - 400) with simple math.
 | ||||||
|  | static constexpr int SliderToSettings(int value) { | ||||||
|  |     return 5 * value + 5; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static constexpr int SettingsToSlider(int value) { | ||||||
|  |     return (value - 5) / 5; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { | ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { | ||||||
|     ui->setupUi(this); |     ui->setupUi(this); | ||||||
|     connect(ui->combo_birthmonth, |     connect(ui->combo_birthmonth, | ||||||
|  | @ -233,6 +244,10 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     connect(ui->slider_clock_speed, &QSlider::valueChanged, [&](int value) { | ||||||
|  |         ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value))); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     ConfigureTime(); |     ConfigureTime(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -258,6 +273,10 @@ void ConfigureSystem::SetConfiguration() { | ||||||
| 
 | 
 | ||||||
|         ui->label_disable_info->hide(); |         ui->label_disable_info->hide(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     ui->slider_clock_speed->setValue(SettingsToSlider(Settings::values.cpu_clock_percentage)); | ||||||
|  |     ui->clock_display_label->setText( | ||||||
|  |         QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::ReadSystemSettings() { | void ConfigureSystem::ReadSystemSettings() { | ||||||
|  | @ -299,65 +318,65 @@ void ConfigureSystem::ReadSystemSettings() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::ApplyConfiguration() { | void ConfigureSystem::ApplyConfiguration() { | ||||||
|     if (!enabled) { |     if (enabled) { | ||||||
|         return; |         bool modified = false; | ||||||
|  | 
 | ||||||
|  |         // apply username
 | ||||||
|  |         // TODO(wwylele): Use this when we move to Qt 5.5
 | ||||||
|  |         // std::u16string new_username = ui->edit_username->text().toStdU16String();
 | ||||||
|  |         std::u16string new_username( | ||||||
|  |             reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16())); | ||||||
|  |         if (new_username != username) { | ||||||
|  |             cfg->SetUsername(new_username); | ||||||
|  |             modified = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // apply birthday
 | ||||||
|  |         int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1; | ||||||
|  |         int new_birthday = ui->combo_birthday->currentIndex() + 1; | ||||||
|  |         if (birthmonth != new_birthmonth || birthday != new_birthday) { | ||||||
|  |             cfg->SetBirthday(new_birthmonth, new_birthday); | ||||||
|  |             modified = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // apply language
 | ||||||
|  |         int new_language = ui->combo_language->currentIndex(); | ||||||
|  |         if (language_index != new_language) { | ||||||
|  |             cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language)); | ||||||
|  |             modified = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // apply sound
 | ||||||
|  |         int new_sound = ui->combo_sound->currentIndex(); | ||||||
|  |         if (sound_index != new_sound) { | ||||||
|  |             cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound)); | ||||||
|  |             modified = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // apply country
 | ||||||
|  |         u8 new_country = static_cast<u8>(ui->combo_country->currentData().toInt()); | ||||||
|  |         if (country_code != new_country) { | ||||||
|  |             cfg->SetCountryCode(new_country); | ||||||
|  |             modified = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // apply play coin
 | ||||||
|  |         u16 new_play_coin = static_cast<u16>(ui->spinBox_play_coins->value()); | ||||||
|  |         if (play_coin != new_play_coin) { | ||||||
|  |             Service::PTM::Module::SetPlayCoins(new_play_coin); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // update the config savegame if any item is modified.
 | ||||||
|  |         if (modified) { | ||||||
|  |             cfg->UpdateConfigNANDSavegame(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Settings::values.init_clock = | ||||||
|  |             static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex()); | ||||||
|  |         Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool modified = false; |     Settings::values.cpu_clock_percentage = SliderToSettings(ui->slider_clock_speed->value()); | ||||||
| 
 |  | ||||||
|     // apply username
 |  | ||||||
|     // TODO(wwylele): Use this when we move to Qt 5.5
 |  | ||||||
|     // std::u16string new_username = ui->edit_username->text().toStdU16String();
 |  | ||||||
|     std::u16string new_username( |  | ||||||
|         reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16())); |  | ||||||
|     if (new_username != username) { |  | ||||||
|         cfg->SetUsername(new_username); |  | ||||||
|         modified = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // apply birthday
 |  | ||||||
|     int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1; |  | ||||||
|     int new_birthday = ui->combo_birthday->currentIndex() + 1; |  | ||||||
|     if (birthmonth != new_birthmonth || birthday != new_birthday) { |  | ||||||
|         cfg->SetBirthday(new_birthmonth, new_birthday); |  | ||||||
|         modified = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // apply language
 |  | ||||||
|     int new_language = ui->combo_language->currentIndex(); |  | ||||||
|     if (language_index != new_language) { |  | ||||||
|         cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language)); |  | ||||||
|         modified = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // apply sound
 |  | ||||||
|     int new_sound = ui->combo_sound->currentIndex(); |  | ||||||
|     if (sound_index != new_sound) { |  | ||||||
|         cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound)); |  | ||||||
|         modified = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // apply country
 |  | ||||||
|     u8 new_country = static_cast<u8>(ui->combo_country->currentData().toInt()); |  | ||||||
|     if (country_code != new_country) { |  | ||||||
|         cfg->SetCountryCode(new_country); |  | ||||||
|         modified = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // apply play coin
 |  | ||||||
|     u16 new_play_coin = static_cast<u16>(ui->spinBox_play_coins->value()); |  | ||||||
|     if (play_coin != new_play_coin) { |  | ||||||
|         Service::PTM::Module::SetPlayCoins(new_play_coin); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // update the config savegame if any item is modified.
 |  | ||||||
|     if (modified) { |  | ||||||
|         cfg->UpdateConfigNANDSavegame(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Settings::values.init_clock = |  | ||||||
|         static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex()); |  | ||||||
|     Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t(); |  | ||||||
|     Settings::Apply(); |     Settings::Apply(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,8 +6,8 @@ | ||||||
|    <rect> |    <rect> | ||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>360</width> |     <width>471</width> | ||||||
|     <height>377</height> |     <height>555</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="windowTitle"> |   <property name="windowTitle"> | ||||||
|  | @ -228,8 +228,7 @@ | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|         <item row="4" column="1"> |         <item row="4" column="1"> | ||||||
|          <widget class="QComboBox" name="combo_country"> |          <widget class="QComboBox" name="combo_country"/> | ||||||
|          </widget> |  | ||||||
|         </item> |         </item> | ||||||
|         <item row="5" column="0"> |         <item row="5" column="0"> | ||||||
|          <widget class="QLabel" name="label_init_clock"> |          <widget class="QLabel" name="label_init_clock"> | ||||||
|  | @ -306,6 +305,63 @@ | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QGroupBox" name="groupBox"> | ||||||
|  |        <property name="title"> | ||||||
|  |         <string>Advanced</string> | ||||||
|  |        </property> | ||||||
|  |        <layout class="QGridLayout" name="gridLayout_2"> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <widget class="QLabel" name="label_3"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>CPU Clock Speed</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="0" column="2"> | ||||||
|  |          <widget class="QSlider" name="slider_clock_speed"> | ||||||
|  |           <property name="toolTip"> | ||||||
|  |            <string><html><body>Changes the emulated CPU clock frequency.<br>Underclocking can increase performance but may cause the game to freeze.<br>Overclocking may reduce in game lag but also might cause freezes</body></html></string> | ||||||
|  |           </property> | ||||||
|  |           <property name="minimum"> | ||||||
|  |            <number>0</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="maximum"> | ||||||
|  |            <number>79</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="singleStep"> | ||||||
|  |            <number>5</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="pageStep"> | ||||||
|  |            <number>15</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="value"> | ||||||
|  |            <number>25</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="orientation"> | ||||||
|  |            <enum>Qt::Horizontal</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="tickPosition"> | ||||||
|  |            <enum>QSlider::TicksBelow</enum> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="0" column="1"> | ||||||
|  |          <widget class="QLabel" name="clock_display_label"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string/> | ||||||
|  |           </property> | ||||||
|  |           <property name="alignment"> | ||||||
|  |            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item> | ||||||
|  |       <layout class="QHBoxLayout" name="horizontalLayout_2"/> | ||||||
|  |      </item> | ||||||
|      <item> |      <item> | ||||||
|       <widget class="QLabel" name="label_disable_info"> |       <widget class="QLabel" name="label_disable_info"> | ||||||
|        <property name="text"> |        <property name="text"> | ||||||
|  | @ -316,6 +372,16 @@ | ||||||
|        </property> |        </property> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QLabel" name="label_cpu_clock_info"> | ||||||
|  |        <property name="text"> | ||||||
|  |         <string><html><head/><body><p>CPU Clock Speed Information<br/>Underclocking can increase performance but may cause the game to freeze.<br/>Overclocking may reduce in game lag but also might cause freezes</p></body></html></string> | ||||||
|  |        </property> | ||||||
|  |        <property name="textFormat"> | ||||||
|  |         <enum>Qt::RichText</enum> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|      <item> |      <item> | ||||||
|       <spacer name="verticalSpacer"> |       <spacer name="verticalSpacer"> | ||||||
|        <property name="orientation"> |        <property name="orientation"> | ||||||
|  |  | ||||||
|  | @ -319,7 +319,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo | ||||||
| 
 | 
 | ||||||
|     memory = std::make_unique<Memory::MemorySystem>(); |     memory = std::make_unique<Memory::MemorySystem>(); | ||||||
| 
 | 
 | ||||||
|     timing = std::make_unique<Timing>(num_cores); |     timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage); | ||||||
| 
 | 
 | ||||||
|     kernel = std::make_unique<Kernel::KernelSystem>( |     kernel = std::make_unique<Kernel::KernelSystem>( | ||||||
|         *memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode); |         *memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode); | ||||||
|  |  | ||||||
|  | @ -22,14 +22,21 @@ bool Timing::Event::operator<(const Timing::Event& right) const { | ||||||
|     return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order); |     return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Timing::Timing(std::size_t num_cores) { | Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) { | ||||||
|     timers.resize(num_cores); |     timers.resize(num_cores); | ||||||
|     for (std::size_t i = 0; i < num_cores; ++i) { |     for (std::size_t i = 0; i < num_cores; ++i) { | ||||||
|         timers[i] = std::make_shared<Timer>(); |         timers[i] = std::make_shared<Timer>(); | ||||||
|     } |     } | ||||||
|  |     UpdateClockSpeed(cpu_clock_percentage); | ||||||
|     current_timer = timers[0]; |     current_timer = timers[0]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) { | ||||||
|  |     for (auto& timer : timers) { | ||||||
|  |         timer->cpu_clock_scale = 100.0 / cpu_clock_percentage; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) { | TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) { | ||||||
|     // check for existing type with same name.
 |     // check for existing type with same name.
 | ||||||
|     // we want event type names to remain unique so that we can use them for serialization.
 |     // we want event type names to remain unique so that we can use them for serialization.
 | ||||||
|  | @ -117,6 +124,8 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) { | ||||||
|     return timers[cpu_id]; |     return timers[cpu_id]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Timing::Timer::Timer() = default; | ||||||
|  | 
 | ||||||
| Timing::Timer::~Timer() { | Timing::Timer::~Timer() { | ||||||
|     MoveEvents(); |     MoveEvents(); | ||||||
| } | } | ||||||
|  | @ -130,7 +139,7 @@ u64 Timing::Timer::GetTicks() const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Timing::Timer::AddTicks(u64 ticks) { | void Timing::Timer::AddTicks(u64 ticks) { | ||||||
|     downcount -= ticks; |     downcount -= static_cast<u64>(ticks * cpu_clock_scale); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u64 Timing::Timer::GetIdleTicks() const { | u64 Timing::Timer::GetIdleTicks() const { | ||||||
|  |  | ||||||
|  | @ -176,6 +176,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     class Timer { |     class Timer { | ||||||
|     public: |     public: | ||||||
|  |         Timer(); | ||||||
|         ~Timer(); |         ~Timer(); | ||||||
| 
 | 
 | ||||||
|         s64 GetMaxSliceLength() const; |         s64 GetMaxSliceLength() const; | ||||||
|  | @ -218,7 +219,10 @@ public: | ||||||
|         s64 slice_length = MAX_SLICE_LENGTH; |         s64 slice_length = MAX_SLICE_LENGTH; | ||||||
|         s64 downcount = MAX_SLICE_LENGTH; |         s64 downcount = MAX_SLICE_LENGTH; | ||||||
|         s64 executed_ticks = 0; |         s64 executed_ticks = 0; | ||||||
|         u64 idled_cycles; |         u64 idled_cycles = 0; | ||||||
|  |         // Stores a scaling for the internal clockspeed. Changing this number results in
 | ||||||
|  |         // under/overclocking the guest cpu
 | ||||||
|  |         double cpu_clock_scale = 1.0; | ||||||
| 
 | 
 | ||||||
|         template <class Archive> |         template <class Archive> | ||||||
|         void serialize(Archive& ar, const unsigned int) { |         void serialize(Archive& ar, const unsigned int) { | ||||||
|  | @ -234,7 +238,7 @@ public: | ||||||
|         friend class boost::serialization::access; |         friend class boost::serialization::access; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     explicit Timing(std::size_t num_cores); |     explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage); | ||||||
| 
 | 
 | ||||||
|     ~Timing(){}; |     ~Timing(){}; | ||||||
| 
 | 
 | ||||||
|  | @ -261,6 +265,11 @@ public: | ||||||
|         global_timer += ticks; |         global_timer += ticks; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Updates the value of the cpu clock scaling to the new percentage. | ||||||
|  |      */ | ||||||
|  |     void UpdateClockSpeed(u32 cpu_clock_percentage); | ||||||
|  | 
 | ||||||
|     std::chrono::microseconds GetGlobalTimeUs() const; |     std::chrono::microseconds GetGlobalTimeUs() const; | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<Timer> GetTimer(std::size_t cpu_id); |     std::shared_ptr<Timer> GetTimer(std::size_t cpu_id); | ||||||
|  | @ -270,11 +279,15 @@ private: | ||||||
| 
 | 
 | ||||||
|     // unordered_map stores each element separately as a linked list node so pointers to
 |     // unordered_map stores each element separately as a linked list node so pointers to
 | ||||||
|     // elements remain stable regardless of rehashes/resizing.
 |     // elements remain stable regardless of rehashes/resizing.
 | ||||||
|     std::unordered_map<std::string, TimingEventType> event_types; |     std::unordered_map<std::string, TimingEventType> event_types = {}; | ||||||
| 
 | 
 | ||||||
|     std::vector<std::shared_ptr<Timer>> timers; |     std::vector<std::shared_ptr<Timer>> timers; | ||||||
|     std::shared_ptr<Timer> current_timer; |     std::shared_ptr<Timer> current_timer; | ||||||
| 
 | 
 | ||||||
|  |     // Stores a scaling for the internal clockspeed. Changing this number results in
 | ||||||
|  |     // under/overclocking the guest cpu
 | ||||||
|  |     double cpu_clock_scale = 1.0; | ||||||
|  | 
 | ||||||
|     template <class Archive> |     template <class Archive> | ||||||
|     void serialize(Archive& ar, const unsigned int) { |     void serialize(Archive& ar, const unsigned int) { | ||||||
|         // event_types set during initialization of other things
 |         // event_types set during initialization of other things
 | ||||||
|  |  | ||||||
|  | @ -152,13 +152,16 @@ ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expe | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(auto vma, CarveVMARange(target, size)); |     CASCADE_RESULT(auto vma, CarveVMARange(target, size)); | ||||||
|     ASSERT(vma->second.size == size); |  | ||||||
| 
 | 
 | ||||||
|     vma->second.permissions = new_perms; |     const VMAIter end = vma_map.end(); | ||||||
|     vma->second.meminfo_state = new_state; |     // The comparison against the end of the range must be done using addresses since VMAs can be
 | ||||||
|     UpdatePageTableForVMA(vma->second); |     // merged during this process, causing invalidation of the iterators.
 | ||||||
| 
 |     while (vma != end && vma->second.base < target_end) { | ||||||
|     MergeAdjacent(vma); |         vma->second.permissions = new_perms; | ||||||
|  |         vma->second.meminfo_state = new_state; | ||||||
|  |         UpdatePageTableForVMA(vma->second); | ||||||
|  |         vma = std::next(MergeAdjacent(vma)); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -46,10 +46,17 @@ static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D | ||||||
| 
 | 
 | ||||||
| static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) { | static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) { | ||||||
|     auto vma = process.vm_manager.FindVMA(buffer_ptr); |     auto vma = process.vm_manager.FindVMA(buffer_ptr); | ||||||
|     return vma != process.vm_manager.vma_map.end() && |     while (vma != process.vm_manager.vma_map.end()) { | ||||||
|            vma->second.base + vma->second.size >= buffer_ptr + size && |         if (vma->second.permissions != Kernel::VMAPermission::ReadWrite || | ||||||
|            vma->second.permissions == Kernel::VMAPermission::ReadWrite && |             vma->second.meminfo_state != Kernel::MemoryState::Private) { | ||||||
|            vma->second.meminfo_state == Kernel::MemoryState::Private; |             return false; | ||||||
|  |         } | ||||||
|  |         if (vma->second.base + vma->second.size >= buffer_ptr + size) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         vma = std::next(vma); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RO::Initialize(Kernel::HLERequestContext& ctx) { | void RO::Initialize(Kernel::HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ void Apply() { | ||||||
| 
 | 
 | ||||||
|     auto& system = Core::System::GetInstance(); |     auto& system = Core::System::GetInstance(); | ||||||
|     if (system.IsPoweredOn()) { |     if (system.IsPoweredOn()) { | ||||||
|  |         system.CoreTiming().UpdateClockSpeed(values.cpu_clock_percentage); | ||||||
|         Core::DSP().SetSink(values.sink_id, values.audio_device_id); |         Core::DSP().SetSink(values.sink_id, values.audio_device_id); | ||||||
|         Core::DSP().EnableStretching(values.enable_audio_stretching); |         Core::DSP().EnableStretching(values.enable_audio_stretching); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -128,6 +128,7 @@ struct Values { | ||||||
| 
 | 
 | ||||||
|     // Core
 |     // Core
 | ||||||
|     bool use_cpu_jit; |     bool use_cpu_jit; | ||||||
|  |     int cpu_clock_percentage; | ||||||
| 
 | 
 | ||||||
|     // Data Storage
 |     // Data Storage
 | ||||||
|     bool use_virtual_sd; |     bool use_virtual_sd; | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ static std::shared_ptr<Memory::PageTable> page_table = nullptr; | ||||||
| TestEnvironment::TestEnvironment(bool mutable_memory_) | TestEnvironment::TestEnvironment(bool mutable_memory_) | ||||||
|     : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { |     : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | ||||||
| 
 | 
 | ||||||
|     timing = std::make_unique<Core::Timing>(1); |     timing = std::make_unique<Core::Timing>(1, 100); | ||||||
|     memory = std::make_unique<Memory::MemorySystem>(); |     memory = std::make_unique<Memory::MemorySystem>(); | ||||||
|     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0, 1, 0); |     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0, 1, 0); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ static void AdvanceAndCheck(Core::Timing& timing, u32 idx, int downcount, int ex | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
| 
 | 
 | ||||||
|     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); |     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); | ||||||
|     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); |     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); | ||||||
|  | @ -90,7 +90,7 @@ void FifoCallback(u64 userdata, s64 cycles_late) { | ||||||
| TEST_CASE("CoreTiming[SharedSlot]", "[core]") { | TEST_CASE("CoreTiming[SharedSlot]", "[core]") { | ||||||
|     using namespace SharedSlotTest; |     using namespace SharedSlotTest; | ||||||
| 
 | 
 | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
| 
 | 
 | ||||||
|     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>); |     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>); | ||||||
|     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>); |     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>); | ||||||
|  | @ -118,7 +118,7 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE("CoreTiming[PredictableLateness]", "[core]") { | TEST_CASE("CoreTiming[PredictableLateness]", "[core]") { | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
| 
 | 
 | ||||||
|     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); |     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); | ||||||
|     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); |     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); | ||||||
|  | @ -149,7 +149,7 @@ static void RescheduleCallback(Core::Timing& timing, u64 userdata, s64 cycles_la | ||||||
| TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { | TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { | ||||||
|     using namespace ChainSchedulingTest; |     using namespace ChainSchedulingTest; | ||||||
| 
 | 
 | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
| 
 | 
 | ||||||
|     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); |     Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); | ||||||
|     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); |     Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { | TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); |     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); | ||||||
|     auto [server, client] = kernel.CreateSessionPair(); |     auto [server, client] = kernel.CreateSessionPair(); | ||||||
|  | @ -239,7 +239,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); |     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); | ||||||
|     auto [server, client] = kernel.CreateSessionPair(); |     auto [server, client] = kernel.CreateSessionPair(); | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| 
 | 
 | ||||||
| TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | ||||||
|     Core::Timing timing(1); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); |     Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0); | ||||||
|     SECTION("these regions should not be mapped on an empty process") { |     SECTION("these regions should not be mapped on an empty process") { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue