mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	core_timing: Allow configuring a fixed or random initial system tick value. (#7309)
* core_timing: Apply random base ticks value on startup. * core: Maintain consistent base system ticks in TAS movies. * frontend: Add setting to configure a fixed base system ticks value.
This commit is contained in:
		
							parent
							
								
									96aa1b3a08
								
							
						
					
					
						commit
						0165012ba4
					
				
					 14 changed files with 150 additions and 17 deletions
				
			
		|  | @ -379,7 +379,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | |||
| 
 | ||||
|     memory = std::make_unique<Memory::MemorySystem>(*this); | ||||
| 
 | ||||
|     timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue()); | ||||
|     timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue(), | ||||
|                                       movie.GetOverrideBaseTicks()); | ||||
| 
 | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>( | ||||
|         *memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps, | ||||
|  |  | |||
|  | @ -3,9 +3,11 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <random> | ||||
| #include <tuple> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/settings.h" | ||||
| #include "core/core_timing.h" | ||||
| 
 | ||||
| namespace Core { | ||||
|  | @ -19,15 +21,28 @@ bool Timing::Event::operator<(const Timing::Event& right) const { | |||
|     return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order); | ||||
| } | ||||
| 
 | ||||
| Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) { | ||||
| Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks) { | ||||
|     // Generate non-zero base tick count to simulate time the system ran before launching the game.
 | ||||
|     // This accounts for games that rely on the system tick to seed randomness.
 | ||||
|     const auto base_ticks = override_base_ticks >= 0 ? override_base_ticks : GenerateBaseTicks(); | ||||
| 
 | ||||
|     timers.resize(num_cores); | ||||
|     for (std::size_t i = 0; i < num_cores; ++i) { | ||||
|         timers[i] = std::make_shared<Timer>(); | ||||
|         timers[i] = std::make_shared<Timer>(base_ticks); | ||||
|     } | ||||
|     UpdateClockSpeed(cpu_clock_percentage); | ||||
|     current_timer = timers[0].get(); | ||||
| } | ||||
| 
 | ||||
| s64 Timing::GenerateBaseTicks() { | ||||
|     if (Settings::values.init_ticks_type.GetValue() == Settings::InitTicks::Fixed) { | ||||
|         return Settings::values.init_ticks_override.GetValue(); | ||||
|     } | ||||
|     // Bounded to 32 bits to make sure we don't generate too high of a counter and risk overflowing.
 | ||||
|     std::mt19937 random_gen(std::random_device{}()); | ||||
|     return random_gen(); | ||||
| } | ||||
| 
 | ||||
| void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) { | ||||
|     for (auto& timer : timers) { | ||||
|         timer->cpu_clock_scale = 100.0 / cpu_clock_percentage; | ||||
|  | @ -146,7 +161,7 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) { | |||
|     return timers[cpu_id]; | ||||
| } | ||||
| 
 | ||||
| Timing::Timer::Timer() = default; | ||||
| Timing::Timer::Timer(s64 base_ticks) : executed_ticks(base_ticks) {} | ||||
| 
 | ||||
| Timing::Timer::~Timer() { | ||||
|     MoveEvents(); | ||||
|  |  | |||
|  | @ -185,7 +185,7 @@ public: | |||
| 
 | ||||
|     class Timer { | ||||
|     public: | ||||
|         Timer(); | ||||
|         Timer(s64 base_ticks = 0); | ||||
|         ~Timer(); | ||||
| 
 | ||||
|         s64 GetMaxSliceLength() const; | ||||
|  | @ -249,7 +249,7 @@ public: | |||
|         friend class boost::serialization::access; | ||||
|     }; | ||||
| 
 | ||||
|     explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage); | ||||
|     explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks = -1); | ||||
| 
 | ||||
|     ~Timing(){}; | ||||
| 
 | ||||
|  | @ -290,6 +290,9 @@ public: | |||
|         event_queue_locked = false; | ||||
|     } | ||||
| 
 | ||||
|     /// Generates a random tick count to seed the system tick timer with.
 | ||||
|     static s64 GenerateBaseTicks(); | ||||
| 
 | ||||
| private: | ||||
|     // unordered_map stores each element separately as a linked list node so pointers to
 | ||||
|     // elements remain stable regardless of rehashes/resizing.
 | ||||
|  |  | |||
|  | @ -120,8 +120,9 @@ struct CTMHeader { | |||
|     std::array<char, 32> author; /// Author of the movie
 | ||||
|     u32_le rerecord_count;       /// Number of rerecords when making the movie
 | ||||
|     u64_le input_count;          /// Number of inputs (button and pad states) when making the movie
 | ||||
|     s64_le timing_base_ticks;    /// The base system tick count to initialize core timing with.
 | ||||
| 
 | ||||
|     std::array<u8, 164> reserved; /// Make heading 256 bytes so it has consistent size
 | ||||
|     std::array<u8, 156> reserved; /// Make heading 256 bytes so it has consistent size
 | ||||
| }; | ||||
| static_assert(sizeof(CTMHeader) == 256, "CTMHeader should be 256 bytes"); | ||||
| #pragma pack(pop) | ||||
|  | @ -158,6 +159,7 @@ void Movie::serialize(Archive& ar, const unsigned int file_version) { | |||
|     ar& recorded_input_; | ||||
| 
 | ||||
|     ar& init_time; | ||||
|     ar& base_ticks; | ||||
| 
 | ||||
|     if (Archive::is_loading::value) { | ||||
|         u64 savestate_movie_id; | ||||
|  | @ -453,6 +455,10 @@ u64 Movie::GetOverrideInitTime() const { | |||
|     return init_time; | ||||
| } | ||||
| 
 | ||||
| s64 Movie::GetOverrideBaseTicks() const { | ||||
|     return base_ticks; | ||||
| } | ||||
| 
 | ||||
| Movie::ValidationResult Movie::ValidateHeader(const CTMHeader& header) const { | ||||
|     if (header_magic_bytes != header.filetype) { | ||||
|         LOG_ERROR(Movie, "Playback file does not have valid header"); | ||||
|  | @ -487,6 +493,7 @@ void Movie::SaveMovie() { | |||
|     header.filetype = header_magic_bytes; | ||||
|     header.program_id = program_id; | ||||
|     header.clock_init_time = init_time; | ||||
|     header.timing_base_ticks = base_ticks; | ||||
|     header.id = id; | ||||
| 
 | ||||
|     std::memcpy(header.author.data(), record_movie_author.data(), | ||||
|  | @ -591,6 +598,7 @@ void Movie::PrepareForPlayback(const std::string& movie_file) { | |||
|         return; | ||||
| 
 | ||||
|     init_time = header.value().clock_init_time; | ||||
|     base_ticks = header.value().timing_base_ticks; | ||||
| } | ||||
| 
 | ||||
| void Movie::PrepareForRecording() { | ||||
|  | @ -605,6 +613,8 @@ void Movie::PrepareForRecording() { | |||
|     } else { | ||||
|         init_time = Settings::values.init_time.GetValue(); | ||||
|     } | ||||
| 
 | ||||
|     base_ticks = Timing::GenerateBaseTicks(); | ||||
| } | ||||
| 
 | ||||
| Movie::ValidationResult Movie::ValidateMovie(const std::string& movie_file) const { | ||||
|  | @ -661,6 +671,7 @@ void Movie::Shutdown() { | |||
|     current_byte = 0; | ||||
|     current_input = 0; | ||||
|     init_time = 0; | ||||
|     base_ticks = -1; | ||||
|     id = 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -74,6 +74,9 @@ public: | |||
|     /// Get the init time that would override the one in the settings
 | ||||
|     u64 GetOverrideInitTime() const; | ||||
| 
 | ||||
|     /// Get the base system ticks value that would override the one generated by core timing
 | ||||
|     s64 GetOverrideBaseTicks() const; | ||||
| 
 | ||||
|     struct MovieMetadata { | ||||
|         u64 program_id; | ||||
|         std::string author; | ||||
|  | @ -168,7 +171,8 @@ private: | |||
|     std::string record_movie_file; | ||||
|     std::string record_movie_author; | ||||
| 
 | ||||
|     u64 init_time; // Clock init time override for RNG consistency
 | ||||
|     u64 init_time;       // Clock init time override for RNG consistency
 | ||||
|     s64 base_ticks = -1; // Core timing base system ticks override for RNG consistency
 | ||||
| 
 | ||||
|     std::vector<u8> recorded_input; | ||||
|     std::size_t current_byte = 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue