Compare commits

..

1 Commits

Author SHA1 Message Date
95fabb3d75 Android #122 2023-11-04 00:57:13 +00:00
18 changed files with 92 additions and 124 deletions

View File

@ -252,7 +252,7 @@ object NativeLibrary {
external fun reloadKeys(): Boolean external fun reloadKeys(): Boolean
external fun initializeSystem(reload: Boolean) external fun initializeSystem()
external fun defaultCPUCore(): Int external fun defaultCPUCore(): Int

View File

@ -11,7 +11,6 @@ import java.io.File
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
@ -50,7 +49,6 @@ class YuzuApplication : Application() {
DirectoryInitialization.start() DirectoryInitialization.start()
GpuDriverHelper.initializeDriverParameters() GpuDriverHelper.initializeDriverParameters()
NativeLibrary.logDeviceInfo() NativeLibrary.logDeviceInfo()
Log.logDeviceInfo()
createNotificationChannels() createNotificationChannels()
} }

View File

@ -107,7 +107,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) {
if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) { if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) {
Toast.makeText( Toast.makeText(
this, this,
getString( getString(

View File

@ -403,7 +403,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} else { } else {
firmwarePath.deleteRecursively() firmwarePath.deleteRecursively()
cacheFirmwareDir.copyRecursively(firmwarePath, true) cacheFirmwareDir.copyRecursively(firmwarePath, true)
NativeLibrary.initializeSystem(true) NativeLibrary.initializeSystem()
getString(R.string.save_file_imported_success) getString(R.string.save_file_imported_success)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -649,7 +649,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
// Reinitialize relevant data // Reinitialize relevant data
NativeLibrary.initializeSystem(true) NativeLibrary.initializeSystem()
gamesViewModel.reloadGames(false) gamesViewModel.reloadGames(false)
return@newInstance getString(R.string.user_data_import_success) return@newInstance getString(R.string.user_data_import_success)

View File

@ -15,7 +15,7 @@ object DirectoryInitialization {
fun start() { fun start() {
if (!areDirectoriesReady) { if (!areDirectoriesReady) {
initializeInternalStorage() initializeInternalStorage()
NativeLibrary.initializeSystem(false) NativeLibrary.initializeSystem()
areDirectoriesReady = true areDirectoriesReady = true
} }
} }

View File

@ -3,8 +3,6 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.os.Build
object Log { object Log {
// Tracks whether we should share the old log or the current log // Tracks whether we should share the old log or the current log
var gameLaunched = false var gameLaunched = false
@ -18,14 +16,4 @@ object Log {
external fun error(message: String) external fun error(message: String)
external fun critical(message: String) external fun critical(message: String)
fun logDeviceInfo() {
info("Device Manufacturer - ${Build.MANUFACTURER}")
info("Device Model - ${Build.MODEL}")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
info("SoC Manufacturer - ${Build.SOC_MANUFACTURER}")
info("SoC Model - ${Build.SOC_MODEL}")
}
info("Total System Memory - ${MemoryUtil.getDeviceRAM()}")
}
} }

View File

@ -27,7 +27,7 @@ object MemoryUtil {
const val Pb = Tb * 1024 const val Pb = Tb * 1024
const val Eb = Pb * 1024 const val Eb = Pb * 1024
private fun bytesToSizeUnit(size: Float, roundUp: Boolean = false): String = private fun bytesToSizeUnit(size: Float): String =
when { when {
size < Kb -> { size < Kb -> {
context.getString( context.getString(
@ -39,59 +39,63 @@ object MemoryUtil {
size < Mb -> { size < Mb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Kb) else (size / Kb).hundredths, (size / Kb).hundredths,
context.getString(R.string.memory_kilobyte) context.getString(R.string.memory_kilobyte)
) )
} }
size < Gb -> { size < Gb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Mb) else (size / Mb).hundredths, (size / Mb).hundredths,
context.getString(R.string.memory_megabyte) context.getString(R.string.memory_megabyte)
) )
} }
size < Tb -> { size < Tb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Gb) else (size / Gb).hundredths, (size / Gb).hundredths,
context.getString(R.string.memory_gigabyte) context.getString(R.string.memory_gigabyte)
) )
} }
size < Pb -> { size < Pb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Tb) else (size / Tb).hundredths, (size / Tb).hundredths,
context.getString(R.string.memory_terabyte) context.getString(R.string.memory_terabyte)
) )
} }
size < Eb -> { size < Eb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Pb) else (size / Pb).hundredths, (size / Pb).hundredths,
context.getString(R.string.memory_petabyte) context.getString(R.string.memory_petabyte)
) )
} }
else -> { else -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
if (roundUp) ceil(size / Eb) else (size / Eb).hundredths, (size / Eb).hundredths,
context.getString(R.string.memory_exabyte) context.getString(R.string.memory_exabyte)
) )
} }
} }
val totalMemory: Float // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
// the potential error created by memInfo.totalMem
private val totalMemory: Float
get() { get() {
val memInfo = ActivityManager.MemoryInfo() val memInfo = ActivityManager.MemoryInfo()
with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
getMemoryInfo(memInfo) getMemoryInfo(memInfo)
} }
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { return ceil(
memInfo.advertisedMem.toFloat() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
} else { memInfo.advertisedMem.toFloat()
memInfo.totalMem.toFloat() } else {
} memInfo.totalMem.toFloat()
}
)
} }
fun isLessThan(minimum: Int, size: Float): Boolean = fun isLessThan(minimum: Int, size: Float): Boolean =
@ -105,7 +109,5 @@ object MemoryUtil {
else -> totalMemory < Kb && totalMemory < minimum else -> totalMemory < Kb && totalMemory < minimum
} }
// Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory)
// the potential error created by memInfo.totalMem
fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory, true)
} }

View File

@ -247,13 +247,11 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath)
} }
} }
void EmulationSession::InitializeSystem(bool reload) { void EmulationSession::InitializeSystem() {
if (!reload) { // Initialize logging system
// Initialize logging system Common::Log::Initialize();
Common::Log::Initialize(); Common::Log::SetColorConsoleBackendEnabled(true);
Common::Log::SetColorConsoleBackendEnabled(true); Common::Log::Start();
Common::Log::Start();
}
// Initialize filesystem. // Initialize filesystem.
m_system.SetFilesystem(m_vfs); m_system.SetFilesystem(m_vfs);
@ -669,15 +667,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
} }
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz) {
jboolean reload) {
// Create the default config.ini. // Create the default config.ini.
Config{}; Config{};
// Initialize the emulated system. // Initialize the emulated system.
if (!reload) { EmulationSession::GetInstance().System().Initialize();
EmulationSession::GetInstance().System().Initialize(); EmulationSession::GetInstance().InitializeSystem();
}
EmulationSession::GetInstance().InitializeSystem(reload);
} }
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) {

View File

@ -43,7 +43,7 @@ public:
const Core::PerfStatsResults& PerfStats() const; const Core::PerfStatsResults& PerfStats() const;
void ConfigureFilesystemProvider(const std::string& filepath); void ConfigureFilesystemProvider(const std::string& filepath);
void InitializeSystem(bool reload); void InitializeSystem();
Core::SystemResultStatus InitializeEmulation(const std::string& filepath); Core::SystemResultStatus InitializeEmulation(const std::string& filepath);
bool IsHandheldOnly(); bool IsHandheldOnly();

View File

@ -30,9 +30,9 @@ bool IsValidMultiStreamChannelCount(u32 channel_count) {
return channel_count <= OpusStreamCountMax; return channel_count <= OpusStreamCountMax;
} }
bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_count) { bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 sterero_stream_count) {
return IsValidMultiStreamChannelCount(total_stream_count) && total_stream_count > 0 && return IsValidMultiStreamChannelCount(total_stream_count) && total_stream_count > 0 &&
stereo_stream_count >= 0 && stereo_stream_count <= total_stream_count; sterero_stream_count > 0 && sterero_stream_count <= total_stream_count;
} }
} // namespace } // namespace

View File

@ -24,7 +24,7 @@ bool IsValidSampleRate(u32 sample_rate) {
} }
bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) { bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) {
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 && return total_stream_count > 0 && stereo_stream_count > 0 &&
stereo_stream_count <= total_stream_count && stereo_stream_count <= total_stream_count &&
total_stream_count + stereo_stream_count <= channel_count; total_stream_count + stereo_stream_count <= channel_count;
} }

View File

@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#ifdef ANDROID
#include <sys/system_properties.h>
#endif
#include "common/arm64/native_clock.h" #include "common/arm64/native_clock.h"
namespace Common::Arm64 { namespace Common::Arm64 {
@ -68,23 +65,7 @@ bool NativeClock::IsNative() const {
u64 NativeClock::GetHostCNTFRQ() { u64 NativeClock::GetHostCNTFRQ() {
u64 cntfrq_el0 = 0; u64 cntfrq_el0 = 0;
std::string_view board{""}; asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0));
#ifdef ANDROID
char buffer[PROP_VALUE_MAX];
int len{__system_property_get("ro.product.board", buffer)};
board = std::string_view(buffer, static_cast<size_t>(len));
#endif
if (board == "s5e9925") { // Exynos 2200
cntfrq_el0 = 25600000;
} else if (board == "exynos2100") { // Exynos 2100
cntfrq_el0 = 26000000;
} else if (board == "exynos9810") { // Exynos 9810
cntfrq_el0 = 26000000;
} else if (board == "s5e8825") { // Exynos 1280
cntfrq_el0 = 26000000;
} else {
asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0));
}
return cntfrq_el0; return cntfrq_el0;
} }

View File

@ -1353,7 +1353,7 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
bool is_enabled; bool unintended_home_button_input_protection;
INSERT_PADDING_BYTES_NOINIT(3); INSERT_PADDING_BYTES_NOINIT(3);
Core::HID::NpadIdType npad_id; Core::HID::NpadIdType npad_id;
u64 applet_resource_user_id; u64 applet_resource_user_id;
@ -1364,11 +1364,13 @@ void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
parameters.is_enabled, parameters.npad_id); parameters.unintended_home_button_input_protection, parameters.npad_id);
LOG_DEBUG(Service_HID, LOG_WARNING(Service_HID,
"(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); "applet_resource_user_id={}",
parameters.unintended_home_button_input_protection, parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);

View File

@ -39,18 +39,6 @@ bool IsConnectionBased(Type type) {
} }
} }
template <typename T>
T GetValue(std::span<const u8> buffer) {
T t{};
std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size()));
return t;
}
template <typename T>
void PutValue(std::span<u8> buffer, const T& t) {
std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size()));
}
} // Anonymous namespace } // Anonymous namespace
void BSD::PollWork::Execute(BSD* bsd) { void BSD::PollWork::Execute(BSD* bsd) {
@ -328,12 +316,22 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>(); const u32 level = rp.Pop<u32>();
const OptName optname = static_cast<OptName>(rp.Pop<u32>()); const OptName optname = static_cast<OptName>(rp.Pop<u32>());
const auto optval = ctx.ReadBuffer();
const auto buffer = ctx.ReadBuffer();
const u8* optval = buffer.empty() ? nullptr : buffer.data();
size_t optlen = buffer.size();
std::array<u64, 2> values;
if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) {
std::memcpy(values.data(), buffer.data(), sizeof(values));
optlen = sizeof(values);
optval = reinterpret_cast<const u8*>(values.data());
}
LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level,
static_cast<u32>(optname), optval.size()); static_cast<u32>(optname), optlen);
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval));
} }
void BSD::Shutdown(HLERequestContext& ctx) { void BSD::Shutdown(HLERequestContext& ctx) {
@ -523,19 +521,18 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) { s32 nfds, s32 timeout) {
if (nfds <= 0) {
// When no entries are provided, -1 is returned with errno zero
return {-1, Errno::SUCCESS};
}
if (read_buffer.size() < nfds * sizeof(PollFD)) {
return {-1, Errno::INVAL};
}
if (write_buffer.size() < nfds * sizeof(PollFD)) { if (write_buffer.size() < nfds * sizeof(PollFD)) {
return {-1, Errno::INVAL}; return {-1, Errno::INVAL};
} }
if (nfds == 0) {
// When no entries are provided, -1 is returned with errno zero
return {-1, Errno::SUCCESS};
}
const size_t length = std::min(read_buffer.size(), write_buffer.size());
std::vector<PollFD> fds(nfds); std::vector<PollFD> fds(nfds);
std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD)); std::memcpy(fds.data(), read_buffer.data(), length);
if (timeout >= 0) { if (timeout >= 0) {
const s64 seconds = timeout / 1000; const s64 seconds = timeout / 1000;
@ -583,7 +580,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
for (size_t i = 0; i < num; ++i) { for (size_t i = 0; i < num; ++i) {
fds[i].revents = Translate(host_pollfds[i].revents); fds[i].revents = Translate(host_pollfds[i].revents);
} }
std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD)); std::memcpy(write_buffer.data(), fds.data(), length);
return Translate(result); return Translate(result);
} }
@ -611,7 +608,8 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
new_descriptor.is_connection_based = descriptor.is_connection_based; new_descriptor.is_connection_based = descriptor.is_connection_based;
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
PutValue(write_buffer, guest_addr_in); const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size());
std::memcpy(write_buffer.data(), &guest_addr_in, length);
return {new_fd, Errno::SUCCESS}; return {new_fd, Errno::SUCCESS};
} }
@ -621,7 +619,8 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
return Errno::BADF; return Errno::BADF;
} }
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
auto addr_in = GetValue<SockAddrIn>(addr); SockAddrIn addr_in;
std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
} }
@ -632,7 +631,8 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
} }
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
auto addr_in = GetValue<SockAddrIn>(addr); SockAddrIn addr_in;
std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
} }
@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
ASSERT(write_buffer.size() >= sizeof(guest_addrin)); ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin));
PutValue(write_buffer, guest_addrin); std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
return Translate(bsd_errno); return Translate(bsd_errno);
} }
@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
ASSERT(write_buffer.size() >= sizeof(guest_addrin)); ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin));
PutValue(write_buffer, guest_addrin); std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
return Translate(bsd_errno); return Translate(bsd_errno);
} }
@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
optval.size() == sizeof(Errno), { return Errno::INVAL; }, optval.size() == sizeof(Errno), { return Errno::INVAL; },
"Incorrect getsockopt option size"); "Incorrect getsockopt option size");
optval.resize(sizeof(Errno)); optval.resize(sizeof(Errno));
PutValue(optval, translated_pending_err); memcpy(optval.data(), &translated_pending_err, sizeof(Errno));
} }
return Translate(getsockopt_err); return Translate(getsockopt_err);
} }
@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
} }
} }
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) { Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@ -748,15 +748,17 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8
Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
if (optname == OptName::LINGER) { if (optname == OptName::LINGER) {
ASSERT(optval.size() == sizeof(Linger)); ASSERT(optlen == sizeof(Linger));
auto linger = GetValue<Linger>(optval); Linger linger;
std::memcpy(&linger, optval, sizeof(linger));
ASSERT(linger.onoff == 0 || linger.onoff == 1); ASSERT(linger.onoff == 0 || linger.onoff == 1);
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
} }
ASSERT(optval.size() == sizeof(u32)); ASSERT(optlen == sizeof(u32));
auto value = GetValue<u32>(optval); u32 value;
std::memcpy(&value, optval, sizeof(value));
switch (optname) { switch (optname) {
case OptName::REUSEADDR: case OptName::REUSEADDR:
@ -860,7 +862,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
} else { } else {
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
const SockAddrIn result = Translate(addr_in); const SockAddrIn result = Translate(addr_in);
PutValue(addr, result); std::memcpy(addr.data(), &result, sizeof(result));
} }
} }
@ -884,7 +886,8 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
Network::SockAddrIn* p_addr_in = nullptr; Network::SockAddrIn* p_addr_in = nullptr;
if (!addr.empty()) { if (!addr.empty()) {
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
auto guest_addr_in = GetValue<SockAddrIn>(addr); SockAddrIn guest_addr_in;
std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
addr_in = Translate(guest_addr_in); addr_in = Translate(guest_addr_in);
p_addr_in = &addr_in; p_addr_in = &addr_in;
} }

View File

@ -163,7 +163,7 @@ private:
Errno ListenImpl(s32 fd, s32 backlog); Errno ListenImpl(s32 fd, s32 backlog);
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval); Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
Errno ShutdownImpl(s32 fd, s32 how); Errno ShutdownImpl(s32 fd, s32 how);
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,

View File

@ -156,6 +156,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
// Ui General // Ui General
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");

View File

@ -2174,7 +2174,6 @@ void GMainWindow::ShutdownGame() {
return; return;
} }
play_time_manager->Stop();
OnShutdownBegin(); OnShutdownBegin();
OnEmulationStopTimeExpired(); OnEmulationStopTimeExpired();
OnEmulationStopped(); OnEmulationStopped();
@ -3485,7 +3484,7 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
} }
void GMainWindow::OnExit() { void GMainWindow::OnExit() {
ShutdownGame(); OnStopGame();
} }
void GMainWindow::OnSaveConfig() { void GMainWindow::OnSaveConfig() {
@ -4848,12 +4847,7 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe
} }
bool GMainWindow::ConfirmClose() { bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) {
UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) {
return true;
}
if (!system->GetExitLocked() &&
UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) {
return true; return true;
} }
const auto text = tr("Are you sure you want to close yuzu?"); const auto text = tr("Are you sure you want to close yuzu?");
@ -4958,7 +4952,7 @@ bool GMainWindow::ConfirmChangeGame() {
} }
bool GMainWindow::ConfirmForceLockedExit() { bool GMainWindow::ConfirmForceLockedExit() {
if (emu_thread == nullptr) { if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) {
return true; return true;
} }
const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"

View File

@ -93,6 +93,10 @@ struct Values {
Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
Setting<bool> confirm_before_closing{
linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
true, true};
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
ConfirmStop::Ask_Always, ConfirmStop::Ask_Always,
"confirmStop", "confirmStop",