early-access version 3241
This commit is contained in:
parent
3b9e1ccd4b
commit
7c2fb8c0da
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user