early-access version 3241
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 3240. | ||||
| This is the source code for early-access 3241. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								dist/yuzu.ico
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/yuzu.ico
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										2
									
								
								dist/yuzu.svg
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/yuzu.svg
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1 @@ | ||||
| <svg id="svg815" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 614.4 682.67"><defs><style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{fill:#ff3c28;}.cls-4{fill:#0ab9e6;}</style><clipPath id="clip-path"><rect class="cls-1" x="-43" y="-46.67" width="699.6" height="777.33"/></clipPath></defs><title>Artboard 1</title><g id="g823"><g id="right"><g class="cls-2"><g id="g827"><g id="g833"><path id="path835" class="cls-3" d="M340.81,138V682.08c150.26,0,272.06-121.81,272.06-272.06S491.07,138,340.81,138M394,197.55a219.06,219.06,0,0,1,0,424.94V197.55"/></g></g></g></g><g id="left"><g class="cls-2"><g id="g839"><g id="g845"><path id="path847" class="cls-4" d="M272.79,1.92C122.53,1.92.73,123.73.73,274s121.8,272.07,272.06,272.07ZM219.65,61.51v425A219,219,0,0,1,118,119.18,217.51,217.51,0,0,1,219.65,61.51"/></g></g></g></g></g></svg> | ||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 612.15 680.17"><defs><style>.cls-1{fill:#c6c6c6;}.cls-2{fill:#ffdc00;}</style></defs><title>newAsset 7</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="g823"><g id="right"><g id="g827"><g id="g833"><path id="path835" class="cls-1" d="M340.08,136V680.17c150.26,0,272.07-121.81,272.07-272.07S490.34,136,340.08,136m53.14,59.6a219.06,219.06,0,0,1,0,424.94V195.63"/></g></g></g><g id="left"><g id="g839"><g id="g845"><path id="path847" class="cls-2" d="M272.07,0C121.81,0,0,121.81,0,272.07S121.81,544.13,272.07,544.13ZM218.93,59.6V484.54A219,219,0,0,1,117.26,117.26,217.44,217.44,0,0,1,218.93,59.6"/></g></g></g></g></g></g></svg> | ||||
| Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 717 B | 
| @@ -49,6 +49,7 @@ struct SteadyClockContext { | ||||
| static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); | ||||
| static_assert(std::is_trivially_copyable_v<SteadyClockContext>, | ||||
|               "SteadyClockContext must be trivially copyable"); | ||||
| using StandardSteadyClockTimePointType = SteadyClockContext; | ||||
|  | ||||
| struct SystemClockContext { | ||||
|     s64 offset; | ||||
|   | ||||
| @@ -26,23 +26,24 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, | ||||
|     const Clock::SteadyClockContext context{ | ||||
|         static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), | ||||
|         clock_source_id}; | ||||
|     shared_memory_format.standard_steady_clock_timepoint.StoreData( | ||||
|         system.Kernel().GetTimeSharedMem().GetPointer(), context); | ||||
|     StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context); | ||||
| } | ||||
|  | ||||
| void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { | ||||
|     shared_memory_format.standard_local_system_clock_context.StoreData( | ||||
|         system.Kernel().GetTimeSharedMem().GetPointer(), context); | ||||
|     StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); | ||||
| } | ||||
|  | ||||
| void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { | ||||
|     shared_memory_format.standard_network_system_clock_context.StoreData( | ||||
|         system.Kernel().GetTimeSharedMem().GetPointer(), context); | ||||
|     StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context); | ||||
| } | ||||
|  | ||||
| void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { | ||||
|     shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( | ||||
|         system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled); | ||||
|     StoreToLockFreeAtomicType( | ||||
|         &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled); | ||||
| } | ||||
|  | ||||
| SharedMemory::Format* SharedMemory::GetFormat() { | ||||
|     return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer()); | ||||
| } | ||||
|  | ||||
| } // namespace Service::Time | ||||
|   | ||||
| @@ -10,45 +10,68 @@ | ||||
|  | ||||
| namespace Service::Time { | ||||
|  | ||||
| // Note: this type is not safe for concurrent writes. | ||||
| template <typename T> | ||||
| struct LockFreeAtomicType { | ||||
|     u32 counter_; | ||||
|     std::array<T, 2> value_; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { | ||||
|     // Get the current counter. | ||||
|     auto counter = p->counter_; | ||||
|  | ||||
|     // Increment the counter. | ||||
|     ++counter; | ||||
|  | ||||
|     // Store the updated value. | ||||
|     p->value_[counter % 2] = value; | ||||
|  | ||||
|     // Fence memory. | ||||
|     std::atomic_thread_fence(std::memory_order_release); | ||||
|  | ||||
|     // Set the updated counter. | ||||
|     p->counter_ = counter; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { | ||||
|     while (true) { | ||||
|         // Get the counter. | ||||
|         auto counter = p->counter_; | ||||
|  | ||||
|         // Get the value. | ||||
|         auto value = p->value_[counter % 2]; | ||||
|  | ||||
|         // Fence memory. | ||||
|         std::atomic_thread_fence(std::memory_order_acquire); | ||||
|  | ||||
|         // Check that the counter matches. | ||||
|         if (counter == p->counter_) { | ||||
|             return value; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class SharedMemory final { | ||||
| public: | ||||
|     explicit SharedMemory(Core::System& system_); | ||||
|     ~SharedMemory(); | ||||
|  | ||||
|     // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? | ||||
|     template <typename T, std::size_t Offset> | ||||
|     struct MemoryBarrier { | ||||
|         static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); | ||||
|         u32_le read_attempt{}; | ||||
|         std::array<T, 2> data{}; | ||||
|  | ||||
|         // These are not actually memory barriers at the moment as we don't have multicore and all | ||||
|         // HLE is mutexed. This will need to properly be implemented when we start updating the time | ||||
|         // points on threads. As of right now, we'll be updated both values synchronously and just | ||||
|         // incrementing the read_attempt to indicate that we waited. | ||||
|         void StoreData(u8* shared_memory, T data_to_store) { | ||||
|             std::memcpy(this, shared_memory + Offset, sizeof(*this)); | ||||
|             read_attempt++; | ||||
|             data[read_attempt & 1] = data_to_store; | ||||
|             std::memcpy(shared_memory + Offset, this, sizeof(*this)); | ||||
|         } | ||||
|  | ||||
|         // For reading we're just going to read the last stored value. If there was no value stored | ||||
|         // it will just end up reading an empty value as intended. | ||||
|         T ReadData(u8* shared_memory) { | ||||
|             std::memcpy(this, shared_memory + Offset, sizeof(*this)); | ||||
|             return data[(read_attempt - 1) & 1]; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     // Shared memory format | ||||
|     struct Format { | ||||
|         MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint; | ||||
|         MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context; | ||||
|         MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context; | ||||
|         MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; | ||||
|         u32_le format_version; | ||||
|         LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint; | ||||
|         LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; | ||||
|         LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; | ||||
|         LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; | ||||
|         u32 format_version; | ||||
|     }; | ||||
|     static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); | ||||
|     static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); | ||||
|     static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); | ||||
|     static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == | ||||
|                   0xc8); | ||||
|     static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); | ||||
|  | ||||
|     void SetupStandardSteadyClock(const Common::UUID& clock_source_id, | ||||
| @@ -56,10 +79,10 @@ public: | ||||
|     void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); | ||||
|     void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); | ||||
|     void SetAutomaticCorrectionEnabled(bool is_enabled); | ||||
|     Format* GetFormat(); | ||||
|  | ||||
| private: | ||||
|     Core::System& system; | ||||
|     Format shared_memory_format{}; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Time | ||||
|   | ||||
| @@ -78,7 +78,6 @@ void EmuThread::run() { | ||||
|     gpu.Start(); | ||||
|  | ||||
|     m_system.GetCpuManager().OnGpuReady(); | ||||
|     m_system.RegisterExitCallback([this] { m_stop_source.request_stop(); }); | ||||
|  | ||||
|     if (m_system.DebuggerEnabled()) { | ||||
|         m_system.InitializeDebugger(); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ void DiscordImpl::Update() { | ||||
|         system.GetAppLoader().ReadTitle(title); | ||||
|     } | ||||
|     DiscordRichPresence presence{}; | ||||
|     presence.largeImageKey = "yuzu_logo"; | ||||
|     presence.largeImageKey = "yuzu_logo_ea"; | ||||
|     presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; | ||||
|     if (system.IsPoweredOn()) { | ||||
|         presence.state = title.c_str(); | ||||
|   | ||||
| @@ -1710,6 +1710,11 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | ||||
|     system->RegisterExecuteProgramCallback( | ||||
|         [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); | ||||
|  | ||||
|     system->RegisterExitCallback([this] { | ||||
|         emu_thread->ForceStop(); | ||||
|         render_window->Exit(); | ||||
|     }); | ||||
|  | ||||
|     connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | ||||
|     connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); | ||||
|     // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views | ||||
| @@ -4177,6 +4182,10 @@ bool GMainWindow::ConfirmForceLockedExit() { | ||||
| } | ||||
|  | ||||
| void GMainWindow::RequestGameExit() { | ||||
|     if (!system->IsPoweredOn()) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto& sm{system->ServiceManager()}; | ||||
|     auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); | ||||
|     auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user