summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/arm_interface.h53
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp35
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h10
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp27
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h10
-rw-r--r--src/core/gdbstub/gdbstub.cpp50
-rw-r--r--src/core/hle/kernel/mutex.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp8
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp5
-rw-r--r--src/video_core/engines/shader_bytecode.h195
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp162
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/default_ini.h2
14 files changed, 435 insertions, 134 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 0b2af2a9b..867e34932 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -10,7 +10,7 @@
namespace Core {
-/// Generic ARM11 CPU interface
+/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
public:
virtual ~ARM_Interface() {}
@@ -19,9 +19,9 @@ public:
std::array<u64, 31> cpu_registers;
u64 sp;
u64 pc;
- u64 cpsr;
- std::array<u128, 32> fpu_registers;
- u64 fpscr;
+ u64 pstate;
+ std::array<u128, 32> vector_registers;
+ u64 fpcr;
};
/// Runs the CPU until an event happens
@@ -69,42 +69,50 @@ public:
*/
virtual void SetReg(int index, u64 value) = 0;
- virtual u128 GetExtReg(int index) const = 0;
-
- virtual void SetExtReg(int index, u128 value) = 0;
-
/**
- * Gets the value of a VFP register
- * @param index Register index (0-31)
- * @return Returns the value in the register
+ * Gets the value of a specified vector register.
+ *
+ * @param index The index of the vector register.
+ * @return the value within the vector register.
*/
- virtual u32 GetVFPReg(int index) const = 0;
+ virtual u128 GetVectorReg(int index) const = 0;
/**
- * Sets a VFP register to the given value
- * @param index Register index (0-31)
- * @param value Value to set register to
+ * Sets a given value into a vector register.
+ *
+ * @param index The index of the vector register.
+ * @param value The new value to place in the register.
*/
- virtual void SetVFPReg(int index, u32 value) = 0;
+ virtual void SetVectorReg(int index, u128 value) = 0;
/**
- * Get the current CPSR register
- * @return Returns the value of the CPSR register
+ * Get the current PSTATE register
+ * @return Returns the value of the PSTATE register
*/
- virtual u32 GetCPSR() const = 0;
+ virtual u32 GetPSTATE() const = 0;
/**
- * Set the current CPSR register
- * @param cpsr Value to set CPSR to
+ * Set the current PSTATE register
+ * @param pstate Value to set PSTATE to
*/
- virtual void SetCPSR(u32 cpsr) = 0;
+ virtual void SetPSTATE(u32 pstate) = 0;
virtual VAddr GetTlsAddress() const = 0;
virtual void SetTlsAddress(VAddr address) = 0;
+ /**
+ * Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
+ *
+ * @return the value within the register.
+ */
virtual u64 GetTPIDR_EL0() const = 0;
+ /**
+ * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register.
+ *
+ * @param value The new value to place in the register.
+ */
virtual void SetTPIDR_EL0(u64 value) = 0;
/**
@@ -119,6 +127,7 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
+ /// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 0c175d872..3f072c51f 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -194,29 +194,20 @@ void ARM_Dynarmic::SetReg(int index, u64 value) {
jit->SetRegister(index, value);
}
-u128 ARM_Dynarmic::GetExtReg(int index) const {
+u128 ARM_Dynarmic::GetVectorReg(int index) const {
return jit->GetVector(index);
}
-void ARM_Dynarmic::SetExtReg(int index, u128 value) {
+void ARM_Dynarmic::SetVectorReg(int index, u128 value) {
jit->SetVector(index, value);
}
-u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const {
- UNIMPLEMENTED();
- return {};
-}
-
-void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) {
- UNIMPLEMENTED();
-}
-
-u32 ARM_Dynarmic::GetCPSR() const {
+u32 ARM_Dynarmic::GetPSTATE() const {
return jit->GetPstate();
}
-void ARM_Dynarmic::SetCPSR(u32 cpsr) {
- jit->SetPstate(cpsr);
+void ARM_Dynarmic::SetPSTATE(u32 pstate) {
+ jit->SetPstate(pstate);
}
u64 ARM_Dynarmic::GetTlsAddress() const {
@@ -239,18 +230,18 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
- ctx.cpsr = jit->GetPstate();
- ctx.fpu_registers = jit->GetVectors();
- ctx.fpscr = jit->GetFpcr();
+ ctx.pstate = jit->GetPstate();
+ ctx.vector_registers = jit->GetVectors();
+ ctx.fpcr = jit->GetFpcr();
}
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
- jit->SetPstate(static_cast<u32>(ctx.cpsr));
- jit->SetVectors(ctx.fpu_registers);
- jit->SetFpcr(static_cast<u32>(ctx.fpscr));
+ jit->SetPstate(static_cast<u32>(ctx.pstate));
+ jit->SetVectors(ctx.vector_registers);
+ jit->SetFpcr(static_cast<u32>(ctx.fpcr));
}
void ARM_Dynarmic::PrepareReschedule() {
@@ -304,8 +295,8 @@ bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr va
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
- Memory::Write64(vaddr, value[0]);
- Memory::Write64(vaddr, value[1]);
+ Memory::Write64(vaddr + 0, value[0]);
+ Memory::Write64(vaddr + 8, value[1]);
});
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 56c60c853..e61382d3d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -29,14 +29,12 @@ public:
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
- u128 GetExtReg(int index) const override;
- void SetExtReg(int index, u128 value) override;
- u32 GetVFPReg(int index) const override;
- void SetVFPReg(int index, u32 value) override;
- u32 GetCPSR() const override;
+ u128 GetVectorReg(int index) const override;
+ void SetVectorReg(int index, u128 value) override;
+ u32 GetPSTATE() const override;
+ void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
- void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 4e02b7cd4..e218a0b15 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -131,33 +131,24 @@ void ARM_Unicorn::SetReg(int regn, u64 val) {
CHECKED(uc_reg_write(uc, treg, &val));
}
-u128 ARM_Unicorn::GetExtReg(int /*index*/) const {
+u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
UNIMPLEMENTED();
static constexpr u128 res{};
return res;
}
-void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) {
+void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
UNIMPLEMENTED();
}
-u32 ARM_Unicorn::GetVFPReg(int /*index*/) const {
- UNIMPLEMENTED();
- return {};
-}
-
-void ARM_Unicorn::SetVFPReg(int /*index*/, u32 /*value*/) {
- UNIMPLEMENTED();
-}
-
-u32 ARM_Unicorn::GetCPSR() const {
+u32 ARM_Unicorn::GetPSTATE() const {
u64 nzcv{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
return static_cast<u32>(nzcv);
}
-void ARM_Unicorn::SetCPSR(u32 cpsr) {
- u64 nzcv = cpsr;
+void ARM_Unicorn::SetPSTATE(u32 pstate) {
+ u64 nzcv = pstate;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
}
@@ -219,7 +210,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
+ CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (auto i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
@@ -234,7 +225,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
for (int i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
- tregs[i] = &ctx.fpu_registers[i];
+ tregs[i] = &ctx.vector_registers[i];
}
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
@@ -246,7 +237,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
+ CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (int i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
@@ -261,7 +252,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
for (auto i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
- tregs[i] = (void*)&ctx.fpu_registers[i];
+ tregs[i] = (void*)&ctx.vector_registers[i];
}
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index d6f7cf4ab..75761950b 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -22,12 +22,10 @@ public:
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
- u128 GetExtReg(int index) const override;
- void SetExtReg(int index, u128 value) override;
- u32 GetVFPReg(int index) const override;
- void SetVFPReg(int index, u32 value) override;
- u32 GetCPSR() const override;
- void SetCPSR(u32 cpsr) override;
+ u128 GetVectorReg(int index) const override;
+ void SetVectorReg(int index, u128 value) override;
+ u32 GetPSTATE() const override;
+ void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index cfaf20a88..1b04f68bf 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -65,9 +65,9 @@ constexpr u32 MSG_WAITALL = 8;
constexpr u32 LR_REGISTER = 30;
constexpr u32 SP_REGISTER = 31;
constexpr u32 PC_REGISTER = 32;
-constexpr u32 CPSR_REGISTER = 33;
+constexpr u32 PSTATE_REGISTER = 33;
constexpr u32 UC_ARM64_REG_Q0 = 34;
-constexpr u32 FPSCR_REGISTER = 66;
+constexpr u32 FPCR_REGISTER = 66;
// TODO/WiP - Used while working on support for FPU
constexpr u32 TODO_DUMMY_REG_997 = 997;
@@ -116,7 +116,7 @@ constexpr char target_xml[] =
<reg name="pc" bitsize="64" type="code_ptr"/>
- <flags id="cpsr_flags" size="4">
+ <flags id="pstate_flags" size="4">
<field name="SP" start="0" end="0"/>
<field name="" start="1" end="1"/>
<field name="EL" start="2" end="3"/>
@@ -135,7 +135,7 @@ constexpr char target_xml[] =
<field name="Z" start="30" end="30"/>
<field name="N" start="31" end="31"/>
</flags>
- <reg name="cpsr" bitsize="32" type="cpsr_flags"/>
+ <reg name="pstate" bitsize="32" type="pstate_flags"/>
</feature>
<feature name="org.gnu.gdb.aarch64.fpu">
</feature>
@@ -227,10 +227,10 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
return thread->context.sp;
} else if (id == PC_REGISTER) {
return thread->context.pc;
- } else if (id == CPSR_REGISTER) {
- return thread->context.cpsr;
- } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0];
+ } else if (id == PSTATE_REGISTER) {
+ return thread->context.pstate;
+ } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
+ return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0];
} else {
return 0;
}
@@ -247,10 +247,10 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
thread->context.sp = val;
} else if (id == PC_REGISTER) {
thread->context.pc = val;
- } else if (id == CPSR_REGISTER) {
- thread->context.cpsr = val;
- } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val;
+ } else if (id == PSTATE_REGISTER) {
+ thread->context.pstate = val;
+ } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
+ thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
}
}
@@ -781,11 +781,11 @@ static void ReadRegister() {
LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == PC_REGISTER) {
LongToGdbHex(reply, RegRead(id, current_thread));
- } else if (id == CPSR_REGISTER) {
- IntToGdbHex(reply, (u32)RegRead(id, current_thread));
- } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
+ } else if (id == PSTATE_REGISTER) {
+ IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
+ } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
LongToGdbHex(reply, RegRead(id, current_thread));
- } else if (id == FPSCR_REGISTER) {
+ } else if (id == FPCR_REGISTER) {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
} else {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
@@ -811,7 +811,7 @@ static void ReadRegisters() {
bufptr += 16;
- IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
+ IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread)));
bufptr += 8;
@@ -843,11 +843,11 @@ static void WriteRegister() {
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == PC_REGISTER) {
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
- } else if (id == CPSR_REGISTER) {
+ } else if (id == PSTATE_REGISTER) {
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
- } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
+ } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
- } else if (id == FPSCR_REGISTER) {
+ } else if (id == FPCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
} else {
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
@@ -866,16 +866,16 @@ static void WriteRegisters() {
if (command_buffer[0] != 'G')
return SendReply("E01");
- for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
+ for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) {
if (reg <= SP_REGISTER) {
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == PC_REGISTER) {
RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
- } else if (reg == CPSR_REGISTER) {
- RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
- } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) {
+ } else if (reg == PSTATE_REGISTER) {
+ RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
+ } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
- } else if (reg == FPSCR_REGISTER) {
+ } else if (reg == FPCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else {
UNIMPLEMENTED();
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 36bf0b677..51f4544be 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -62,7 +62,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
Handle requesting_thread_handle) {
// The mutex address must be 4-byte aligned
if ((address % sizeof(u32)) != 0) {
- return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
+ return ERR_INVALID_ADDRESS;
}
SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
@@ -100,7 +100,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
ResultCode Mutex::Release(VAddr address) {
// The mutex address must be 4-byte aligned
if ((address % sizeof(u32)) != 0) {
- return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
+ return ERR_INVALID_ADDRESS;
}
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c5c1697ee..371fc439e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -280,6 +280,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
"requesting_current_thread_handle=0x{:08X}",
holding_thread_handle, mutex_addr, requesting_thread_handle);
+ if (Memory::IsKernelVirtualAddress(mutex_addr)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
requesting_thread_handle);
@@ -289,6 +293,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
+ if (Memory::IsKernelVirtualAddress(mutex_addr)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
return Mutex::Release(mutex_addr);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 89cd5f401..d4183d6e3 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -217,8 +217,8 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
context.cpu_registers[0] = arg;
context.pc = entry_point;
context.sp = stack_top;
- context.cpsr = 0;
- context.fpscr = 0;
+ context.pstate = 0;
+ context.fpcr = 0;
}
ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 0071ca613..bcb3475db 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -25,7 +25,7 @@ const UUID& UUID::Generate() {
ProfileManager::ProfileManager() {
// TODO(ogniK): Create the default user we have for now until loading/saving users is added
auto user_uuid = UUID{1, 0};
- CreateNewUser(user_uuid, Settings::values.username);
+ ASSERT(CreateNewUser(user_uuid, Settings::values.username).IsSuccess());
OpenUser(user_uuid);
}
@@ -91,7 +91,8 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern
/// specifically by allowing an std::string for the username. This is required specifically since
/// we're loading a string straight from the config
ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) {
- ProfileUsername username_output;
+ ProfileUsername username_output{};
+
if (username.size() > username_output.size()) {
std::copy_n(username.begin(), username_output.size(), username_output.begin());
} else {
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 6e555ea03..7e1de0fa1 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -240,6 +240,41 @@ enum class FlowCondition : u64 {
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
};
+enum class ControlCode : u64 {
+ F = 0,
+ LT = 1,
+ EQ = 2,
+ LE = 3,
+ GT = 4,
+ NE = 5,
+ GE = 6,
+ Num = 7,
+ Nan = 8,
+ LTU = 9,
+ EQU = 10,
+ LEU = 11,
+ GTU = 12,
+ NEU = 13,
+ GEU = 14,
+ //
+ OFF = 16,
+ LO = 17,
+ SFF = 18,
+ LS = 19,
+ HI = 20,
+ SFT = 21,
+ HS = 22,
+ OFT = 23,
+ CSM_TA = 24,
+ CSM_TR = 25,
+ CSM_MX = 26,
+ FCSM_TA = 27,
+ FCSM_TR = 28,
+ FCSM_MX = 29,
+ RLE = 30,
+ RGT = 31,
+};
+
enum class PredicateResultMode : u64 {
None = 0x0,
NotZero = 0x3,
@@ -271,6 +306,15 @@ enum class TextureProcessMode : u64 {
LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
};
+enum class TextureMiscMode : u64 {
+ DC,
+ AOFFI, // Uses Offset
+ NDV,
+ NODEP,
+ MZ,
+ PTP,
+};
+
enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
@@ -546,6 +590,15 @@ union Instruction {
} pset;
union {
+ BitField<0, 3, u64> pred0;
+ BitField<3, 3, u64> pred3;
+ BitField<8, 5, ControlCode> cc; // flag in cc
+ BitField<39, 3, u64> pred39;
+ BitField<42, 1, u64> neg_pred39;
+ BitField<45, 4, PredOperation> op; // op with pred39
+ } csetp;
+
+ union {
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred;
BitField<43, 1, u64> neg_a;
@@ -590,42 +643,127 @@ union Instruction {
BitField<28, 1, u64> array;
BitField<29, 2, TextureType> texture_type;
BitField<31, 4, u64> component_mask;
+ BitField<49, 1, u64> nodep_flag;
+ BitField<50, 1, u64> dc_flag;
+ BitField<54, 1, u64> aoffi_flag;
BitField<55, 3, TextureProcessMode> process_mode;
bool IsComponentEnabled(std::size_t component) const {
return ((1ull << component) & component_mask) != 0;
}
+
+ TextureProcessMode GetTextureProcessMode() const {
+ return process_mode;
+ }
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::DC:
+ return dc_flag != 0;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ case TextureMiscMode::AOFFI:
+ return aoffi_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
} tex;
union {
BitField<22, 6, TextureQueryType> query_type;
BitField<31, 4, u64> component_mask;
+ BitField<49, 1, u64> nodep_flag;
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
} txq;
union {
BitField<28, 1, u64> array;
BitField<29, 2, TextureType> texture_type;
BitField<31, 4, u64> component_mask;
+ BitField<35, 1, u64> ndv_flag;
+ BitField<49, 1, u64> nodep_flag;
bool IsComponentEnabled(std::size_t component) const {
return ((1ull << component) & component_mask) != 0;
}
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::NDV:
+ return (ndv_flag != 0);
+ case TextureMiscMode::NODEP:
+ return (nodep_flag != 0);
+ default:
+ break;
+ }
+ return false;
+ }
} tmml;
union {
BitField<28, 1, u64> array;
BitField<29, 2, TextureType> texture_type;
+ BitField<35, 1, u64> ndv_flag;
+ BitField<49, 1, u64> nodep_flag;
+ BitField<50, 1, u64> dc_flag;
+ BitField<54, 2, u64> info;
BitField<56, 2, u64> component;
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::NDV:
+ return ndv_flag != 0;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ case TextureMiscMode::DC:
+ return dc_flag != 0;
+ case TextureMiscMode::AOFFI:
+ return info == 1;
+ case TextureMiscMode::PTP:
+ return info == 2;
+ default:
+ break;
+ }
+ return false;
+ }
} tld4;
union {
+ BitField<49, 1, u64> nodep_flag;
+ BitField<50, 1, u64> dc_flag;
+ BitField<51, 1, u64> aoffi_flag;
BitField<52, 2, u64> component;
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::DC:
+ return dc_flag != 0;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ case TextureMiscMode::AOFFI:
+ return aoffi_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
} tld4s;
union {
BitField<0, 8, Register> gpr0;
BitField<28, 8, Register> gpr28;
- BitField<49, 1, u64> nodep;
+ BitField<49, 1, u64> nodep_flag;
BitField<50, 3, u64> component_mask_selector;
BitField<53, 4, u64> texture_info;
@@ -645,6 +783,37 @@ union Instruction {
UNREACHABLE();
}
+ TextureProcessMode GetTextureProcessMode() const {
+ switch (texture_info) {
+ case 0:
+ case 2:
+ case 6:
+ case 8:
+ case 9:
+ case 11:
+ return TextureProcessMode::LZ;
+ case 3:
+ case 5:
+ case 13:
+ return TextureProcessMode::LL;
+ default:
+ break;
+ }
+ return TextureProcessMode::None;
+ }
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::DC:
+ return (texture_info >= 4 && texture_info <= 6) || texture_info == 9;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
+
bool IsArrayTexture() const {
// TEXS only supports Texture2D arrays.
return texture_info >= 7 && texture_info <= 9;
@@ -673,6 +842,7 @@ union Instruction {
} texs;
union {
+ BitField<49, 1, u64> nodep_flag;
BitField<53, 4, u64> texture_info;
TextureType GetTextureType() const {
@@ -693,6 +863,26 @@ union Instruction {
UNREACHABLE();
}
+ TextureProcessMode GetTextureProcessMode() const {
+ if (texture_info == 1 || texture_info == 5 || texture_info == 12)
+ return TextureProcessMode::LL;
+ return TextureProcessMode::LZ;
+ }
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::AOFFI:
+ return texture_info == 12 || texture_info == 4;
+ case TextureMiscMode::MZ:
+ return texture_info == 5;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
+
bool IsArrayTexture() const {
// TEXS only supports Texture2D arrays.
return texture_info == 8;
@@ -735,6 +925,7 @@ union Instruction {
BitField<36, 5, u64> index;
} cbuf36;
+ BitField<47, 1, u64> generates_cc;
BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr;
@@ -859,6 +1050,7 @@ public:
ISET_IMM,
PSETP,
PSET,
+ CSETP,
XMAD_IMM,
XMAD_CR,
XMAD_RC,
@@ -1095,6 +1287,7 @@ private:
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
+ INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index a1638c12e..b3e95187e 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -236,6 +236,14 @@ private:
const std::string& suffix;
};
+enum class InternalFlag : u64 {
+ ZeroFlag = 0,
+ CarryFlag = 1,
+ OverflowFlag = 2,
+ NaNFlag = 3,
+ Amount
+};
+
/**
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
@@ -329,13 +337,19 @@ public:
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
const std::string& value, u64 dest_num_components,
u64 value_num_components, bool is_saturated = false,
- u64 dest_elem = 0, Register::Size size = Register::Size::Word) {
+ u64 dest_elem = 0, Register::Size size = Register::Size::Word,
+ bool sets_cc = false) {
ASSERT_MSG(!is_saturated, "Unimplemented");
const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')',
dest_num_components, value_num_components, dest_elem);
+
+ if (sets_cc) {
+ const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
+ SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
+ }
}
/**
@@ -352,6 +366,26 @@ public:
shader.AddLine(dest + " = " + src + ';');
}
+ std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
+ switch (cc) {
+ case Tegra::Shader::ControlCode::NEU:
+ return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
+ default:
+ LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc));
+ UNREACHABLE();
+ return "false";
+ }
+ }
+
+ std::string GetInternalFlag(const InternalFlag ii) const {
+ const u32 code = static_cast<u32>(ii);
+ return "internalFlag_" + std::to_string(code) + suffix;
+ }
+
+ void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
+ shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
+ }
+
/**
* Writes code that does a output attribute assignment to register operation. Output attributes
* are stored as floats, so this may require conversion.
@@ -415,6 +449,12 @@ public:
}
declarations.AddNewLine();
+ for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
+ const InternalFlag code = static_cast<InternalFlag>(ii);
+ declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
+ }
+ declarations.AddNewLine();
+
for (const auto element : declr_input_attribute) {
// TODO(bunnei): Use proper number of elements for these
u32 idx =
@@ -938,8 +978,6 @@ private:
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
- ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented");
-
std::size_t written_components = 0;
for (u32 component = 0; component < 4; ++component) {
if (!instr.texs.IsComponentEnabled(component)) {
@@ -1622,7 +1660,8 @@ private:
}
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
- 1, instr.alu.saturate_d, 0, instr.conversion.dest_size);
+ 1, instr.alu.saturate_d, 0, instr.conversion.dest_size,
+ instr.generates_cc.Value() != 0);
break;
}
case OpCode::Id::I2F_R:
@@ -1761,8 +1800,8 @@ private:
Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
Tegra::Shader::IpaSampleMode::Default};
- u32 next_element = instr.attribute.fmt20.element;
- u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
+ u64 next_element = instr.attribute.fmt20.element;
+ u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
const auto LoadNextElement = [&](u32 reg_offset) {
regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
@@ -1826,8 +1865,8 @@ private:
ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
"Unaligned attribute loads are not supported");
- u32 next_element = instr.attribute.fmt20.element;
- u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
+ u64 next_element = instr.attribute.fmt20.element;
+ u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
const auto StoreNextElement = [&](u32 reg_offset) {
regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
@@ -1853,6 +1892,13 @@ private:
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
std::string coord;
+ ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
+ "AOFFI is not implemented");
+ ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
+ "DC is not implemented");
+
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
@@ -1935,6 +1981,11 @@ private:
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
bool is_array{instr.texs.IsArrayTexture()};
+ ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
+ "DC is not implemented");
+
switch (texture_type) {
case Tegra::Shader::TextureType::Texture2D: {
if (is_array) {
@@ -1971,6 +2022,13 @@ private:
ASSERT(instr.tlds.IsArrayTexture() == false);
std::string coord;
+ ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
+ "AOFFI is not implemented");
+ ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ),
+ "MZ is not implemented");
+
switch (instr.tlds.GetTextureType()) {
case Tegra::Shader::TextureType::Texture2D: {
if (instr.tlds.IsArrayTexture()) {
@@ -1999,6 +2057,17 @@ private:
ASSERT(instr.tld4.array == 0);
std::string coord;
+ ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
+ "AOFFI is not implemented");
+ ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
+ "DC is not implemented");
+ ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
+ "NDV is not implemented");
+ ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP),
+ "PTP is not implemented");
+
switch (instr.tld4.texture_type) {
case Tegra::Shader::TextureType::Texture2D: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
@@ -2036,6 +2105,13 @@ private:
break;
}
case OpCode::Id::TLD4S: {
+ ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
+ "AOFFI is not implemented");
+ ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
+ "DC is not implemented");
+
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
@@ -2048,6 +2124,9 @@ private:
break;
}
case OpCode::Id::TXQ: {
+ ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+
// TODO: the new commits on the texture refactor, change the way samplers work.
// Sadly, not all texture instructions specify the type of texture their sampler
// uses. This must be fixed at a later instance.
@@ -2068,6 +2147,11 @@ private:
break;
}
case OpCode::Id::TMML: {
+ ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
+ "NODEP is not implemented");
+ ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
+ "NDV is not implemented");
+
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const bool is_array = instr.tmml.array != 0;
@@ -2234,31 +2318,55 @@ private:
break;
}
case OpCode::Type::PredicateSetPredicate: {
- const std::string op_a =
- GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
- const std::string op_b =
- GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
+ switch (opcode->GetId()) {
+ case OpCode::Id::PSETP: {
+ const std::string op_a =
+ GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
+ const std::string op_b =
+ GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
- // We can't use the constant predicate as destination.
- ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+ // We can't use the constant predicate as destination.
+ ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
- const std::string second_pred =
- GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
+ const std::string second_pred =
+ GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
- const std::string combiner = GetPredicateCombiner(instr.psetp.op);
+ const std::string combiner = GetPredicateCombiner(instr.psetp.op);
- const std::string predicate =
- '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
+ const std::string predicate =
+ '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
- // Set the primary predicate to the result of Predicate OP SecondPredicate
- SetPredicate(instr.psetp.pred3,
- '(' + predicate + ") " + combiner + " (" + second_pred + ')');
+ // Set the primary predicate to the result of Predicate OP SecondPredicate
+ SetPredicate(instr.psetp.pred3,
+ '(' + predicate + ") " + combiner + " (" + second_pred + ')');
- if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
- // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
- // if enabled
- SetPredicate(instr.psetp.pred0,
- "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
+ if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+ // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
+ // if enabled
+ SetPredicate(instr.psetp.pred0,
+ "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
+ }
+ break;
+ }
+ case OpCode::Id::CSETP: {
+ const std::string pred =
+ GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
+ const std::string combiner = GetPredicateCombiner(instr.csetp.op);
+ const std::string controlCode = regs.GetControlCode(instr.csetp.cc);
+ if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
+ SetPredicate(instr.csetp.pred3,
+ '(' + controlCode + ") " + combiner + " (" + pred + ')');
+ }
+ if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+ SetPredicate(instr.csetp.pred0,
+ "!(" + controlCode + ") " + combiner + " (" + pred + ')');
+ }
+ break;
+ }
+ default: {
+ LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
}
break;
}
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 991abda2e..7ec1f5110 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -125,6 +125,10 @@ void Config::ReadValues() {
// System
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
+ Settings::values.username = sdl2_config->Get("System", "username", "yuzu");
+ if (Settings::values.username.empty()) {
+ Settings::values.username = "yuzu";
+ }
// Miscellaneous
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 002a4ec15..d35c441e9 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -176,7 +176,7 @@ use_docked_mode =
# Sets the account username, max length is 32 characters
# yuzu (default)
-username =
+username = yuzu
# Sets the systems language index
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,