diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/arm_interface.h | 53 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.cpp | 35 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.h | 10 | ||||
| -rw-r--r-- | src/core/arm/unicorn/arm_unicorn.cpp | 27 | ||||
| -rw-r--r-- | src/core/arm/unicorn/arm_unicorn.h | 10 | ||||
| -rw-r--r-- | src/core/gdbstub/gdbstub.cpp | 50 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/acc/profile_manager.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 195 | ||||
| -rw-r--r-- | src/video_core/engines/shader_header.h | 103 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 185 | ||||
| -rw-r--r-- | src/yuzu_cmd/config.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu_cmd/default_ini.h | 2 |
16 files changed, 542 insertions, 154 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 @@ | |||
| 10 | 10 | ||
| 11 | namespace Core { | 11 | namespace Core { |
| 12 | 12 | ||
| 13 | /// Generic ARM11 CPU interface | 13 | /// Generic ARMv8 CPU interface |
| 14 | class ARM_Interface : NonCopyable { | 14 | class ARM_Interface : NonCopyable { |
| 15 | public: | 15 | public: |
| 16 | virtual ~ARM_Interface() {} | 16 | virtual ~ARM_Interface() {} |
| @@ -19,9 +19,9 @@ public: | |||
| 19 | std::array<u64, 31> cpu_registers; | 19 | std::array<u64, 31> cpu_registers; |
| 20 | u64 sp; | 20 | u64 sp; |
| 21 | u64 pc; | 21 | u64 pc; |
| 22 | u64 cpsr; | 22 | u64 pstate; |
| 23 | std::array<u128, 32> fpu_registers; | 23 | std::array<u128, 32> vector_registers; |
| 24 | u64 fpscr; | 24 | u64 fpcr; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | /// Runs the CPU until an event happens | 27 | /// Runs the CPU until an event happens |
| @@ -69,42 +69,50 @@ public: | |||
| 69 | */ | 69 | */ |
| 70 | virtual void SetReg(int index, u64 value) = 0; | 70 | virtual void SetReg(int index, u64 value) = 0; |
| 71 | 71 | ||
| 72 | virtual u128 GetExtReg(int index) const = 0; | ||
| 73 | |||
| 74 | virtual void SetExtReg(int index, u128 value) = 0; | ||
| 75 | |||
| 76 | /** | 72 | /** |
| 77 | * Gets the value of a VFP register | 73 | * Gets the value of a specified vector register. |
| 78 | * @param index Register index (0-31) | 74 | * |
| 79 | * @return Returns the value in the register | 75 | * @param index The index of the vector register. |
| 76 | * @return the value within the vector register. | ||
| 80 | */ | 77 | */ |
| 81 | virtual u32 GetVFPReg(int index) const = 0; | 78 | virtual u128 GetVectorReg(int index) const = 0; |
| 82 | 79 | ||
| 83 | /** | 80 | /** |
| 84 | * Sets a VFP register to the given value | 81 | * Sets a given value into a vector register. |
| 85 | * @param index Register index (0-31) | 82 | * |
| 86 | * @param value Value to set register to | 83 | * @param index The index of the vector register. |
| 84 | * @param value The new value to place in the register. | ||
| 87 | */ | 85 | */ |
| 88 | virtual void SetVFPReg(int index, u32 value) = 0; | 86 | virtual void SetVectorReg(int index, u128 value) = 0; |
| 89 | 87 | ||
| 90 | /** | 88 | /** |
| 91 | * Get the current CPSR register | 89 | * Get the current PSTATE register |
| 92 | * @return Returns the value of the CPSR register | 90 | * @return Returns the value of the PSTATE register |
| 93 | */ | 91 | */ |
| 94 | virtual u32 GetCPSR() const = 0; | 92 | virtual u32 GetPSTATE() const = 0; |
| 95 | 93 | ||
| 96 | /** | 94 | /** |
| 97 | * Set the current CPSR register | 95 | * Set the current PSTATE register |
| 98 | * @param cpsr Value to set CPSR to | 96 | * @param pstate Value to set PSTATE to |
| 99 | */ | 97 | */ |
| 100 | virtual void SetCPSR(u32 cpsr) = 0; | 98 | virtual void SetPSTATE(u32 pstate) = 0; |
| 101 | 99 | ||
| 102 | virtual VAddr GetTlsAddress() const = 0; | 100 | virtual VAddr GetTlsAddress() const = 0; |
| 103 | 101 | ||
| 104 | virtual void SetTlsAddress(VAddr address) = 0; | 102 | virtual void SetTlsAddress(VAddr address) = 0; |
| 105 | 103 | ||
| 104 | /** | ||
| 105 | * Gets the value within the TPIDR_EL0 (read/write software thread ID) register. | ||
| 106 | * | ||
| 107 | * @return the value within the register. | ||
| 108 | */ | ||
| 106 | virtual u64 GetTPIDR_EL0() const = 0; | 109 | virtual u64 GetTPIDR_EL0() const = 0; |
| 107 | 110 | ||
| 111 | /** | ||
| 112 | * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register. | ||
| 113 | * | ||
| 114 | * @param value The new value to place in the register. | ||
| 115 | */ | ||
| 108 | virtual void SetTPIDR_EL0(u64 value) = 0; | 116 | virtual void SetTPIDR_EL0(u64 value) = 0; |
| 109 | 117 | ||
| 110 | /** | 118 | /** |
| @@ -119,6 +127,7 @@ public: | |||
| 119 | */ | 127 | */ |
| 120 | virtual void LoadContext(const ThreadContext& ctx) = 0; | 128 | virtual void LoadContext(const ThreadContext& ctx) = 0; |
| 121 | 129 | ||
| 130 | /// Clears the exclusive monitor's state. | ||
| 122 | virtual void ClearExclusiveState() = 0; | 131 | virtual void ClearExclusiveState() = 0; |
| 123 | 132 | ||
| 124 | /// Prepare core for thread reschedule (if needed to correctly handle state) | 133 | /// 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) { | |||
| 194 | jit->SetRegister(index, value); | 194 | jit->SetRegister(index, value); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | u128 ARM_Dynarmic::GetExtReg(int index) const { | 197 | u128 ARM_Dynarmic::GetVectorReg(int index) const { |
| 198 | return jit->GetVector(index); | 198 | return jit->GetVector(index); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | void ARM_Dynarmic::SetExtReg(int index, u128 value) { | 201 | void ARM_Dynarmic::SetVectorReg(int index, u128 value) { |
| 202 | jit->SetVector(index, value); | 202 | jit->SetVector(index, value); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const { | 205 | u32 ARM_Dynarmic::GetPSTATE() const { |
| 206 | UNIMPLEMENTED(); | ||
| 207 | return {}; | ||
| 208 | } | ||
| 209 | |||
| 210 | void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) { | ||
| 211 | UNIMPLEMENTED(); | ||
| 212 | } | ||
| 213 | |||
| 214 | u32 ARM_Dynarmic::GetCPSR() const { | ||
| 215 | return jit->GetPstate(); | 206 | return jit->GetPstate(); |
| 216 | } | 207 | } |
| 217 | 208 | ||
| 218 | void ARM_Dynarmic::SetCPSR(u32 cpsr) { | 209 | void ARM_Dynarmic::SetPSTATE(u32 pstate) { |
| 219 | jit->SetPstate(cpsr); | 210 | jit->SetPstate(pstate); |
| 220 | } | 211 | } |
| 221 | 212 | ||
| 222 | u64 ARM_Dynarmic::GetTlsAddress() const { | 213 | u64 ARM_Dynarmic::GetTlsAddress() const { |
| @@ -239,18 +230,18 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { | |||
| 239 | ctx.cpu_registers = jit->GetRegisters(); | 230 | ctx.cpu_registers = jit->GetRegisters(); |
| 240 | ctx.sp = jit->GetSP(); | 231 | ctx.sp = jit->GetSP(); |
| 241 | ctx.pc = jit->GetPC(); | 232 | ctx.pc = jit->GetPC(); |
| 242 | ctx.cpsr = jit->GetPstate(); | 233 | ctx.pstate = jit->GetPstate(); |
| 243 | ctx.fpu_registers = jit->GetVectors(); | 234 | ctx.vector_registers = jit->GetVectors(); |
| 244 | ctx.fpscr = jit->GetFpcr(); | 235 | ctx.fpcr = jit->GetFpcr(); |
| 245 | } | 236 | } |
| 246 | 237 | ||
| 247 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { | 238 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { |
| 248 | jit->SetRegisters(ctx.cpu_registers); | 239 | jit->SetRegisters(ctx.cpu_registers); |
| 249 | jit->SetSP(ctx.sp); | 240 | jit->SetSP(ctx.sp); |
| 250 | jit->SetPC(ctx.pc); | 241 | jit->SetPC(ctx.pc); |
| 251 | jit->SetPstate(static_cast<u32>(ctx.cpsr)); | 242 | jit->SetPstate(static_cast<u32>(ctx.pstate)); |
| 252 | jit->SetVectors(ctx.fpu_registers); | 243 | jit->SetVectors(ctx.vector_registers); |
| 253 | jit->SetFpcr(static_cast<u32>(ctx.fpscr)); | 244 | jit->SetFpcr(static_cast<u32>(ctx.fpcr)); |
| 254 | } | 245 | } |
| 255 | 246 | ||
| 256 | void ARM_Dynarmic::PrepareReschedule() { | 247 | void ARM_Dynarmic::PrepareReschedule() { |
| @@ -304,8 +295,8 @@ bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr va | |||
| 304 | 295 | ||
| 305 | bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { | 296 | bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { |
| 306 | return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { | 297 | return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { |
| 307 | Memory::Write64(vaddr, value[0]); | 298 | Memory::Write64(vaddr + 0, value[0]); |
| 308 | Memory::Write64(vaddr, value[1]); | 299 | Memory::Write64(vaddr + 8, value[1]); |
| 309 | }); | 300 | }); |
| 310 | } | 301 | } |
| 311 | 302 | ||
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: | |||
| 29 | u64 GetPC() const override; | 29 | u64 GetPC() const override; |
| 30 | u64 GetReg(int index) const override; | 30 | u64 GetReg(int index) const override; |
| 31 | void SetReg(int index, u64 value) override; | 31 | void SetReg(int index, u64 value) override; |
| 32 | u128 GetExtReg(int index) const override; | 32 | u128 GetVectorReg(int index) const override; |
| 33 | void SetExtReg(int index, u128 value) override; | 33 | void SetVectorReg(int index, u128 value) override; |
| 34 | u32 GetVFPReg(int index) const override; | 34 | u32 GetPSTATE() const override; |
| 35 | void SetVFPReg(int index, u32 value) override; | 35 | void SetPSTATE(u32 pstate) override; |
| 36 | u32 GetCPSR() const override; | ||
| 37 | void Run() override; | 36 | void Run() override; |
| 38 | void Step() override; | 37 | void Step() override; |
| 39 | void SetCPSR(u32 cpsr) override; | ||
| 40 | VAddr GetTlsAddress() const override; | 38 | VAddr GetTlsAddress() const override; |
| 41 | void SetTlsAddress(VAddr address) override; | 39 | void SetTlsAddress(VAddr address) override; |
| 42 | void SetTPIDR_EL0(u64 value) override; | 40 | 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) { | |||
| 131 | CHECKED(uc_reg_write(uc, treg, &val)); | 131 | CHECKED(uc_reg_write(uc, treg, &val)); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | u128 ARM_Unicorn::GetExtReg(int /*index*/) const { | 134 | u128 ARM_Unicorn::GetVectorReg(int /*index*/) const { |
| 135 | UNIMPLEMENTED(); | 135 | UNIMPLEMENTED(); |
| 136 | static constexpr u128 res{}; | 136 | static constexpr u128 res{}; |
| 137 | return res; | 137 | return res; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) { | 140 | void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) { |
| 141 | UNIMPLEMENTED(); | 141 | UNIMPLEMENTED(); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | u32 ARM_Unicorn::GetVFPReg(int /*index*/) const { | 144 | u32 ARM_Unicorn::GetPSTATE() const { |
| 145 | UNIMPLEMENTED(); | ||
| 146 | return {}; | ||
| 147 | } | ||
| 148 | |||
| 149 | void ARM_Unicorn::SetVFPReg(int /*index*/, u32 /*value*/) { | ||
| 150 | UNIMPLEMENTED(); | ||
| 151 | } | ||
| 152 | |||
| 153 | u32 ARM_Unicorn::GetCPSR() const { | ||
| 154 | u64 nzcv{}; | 145 | u64 nzcv{}; |
| 155 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv)); | 146 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv)); |
| 156 | return static_cast<u32>(nzcv); | 147 | return static_cast<u32>(nzcv); |
| 157 | } | 148 | } |
| 158 | 149 | ||
| 159 | void ARM_Unicorn::SetCPSR(u32 cpsr) { | 150 | void ARM_Unicorn::SetPSTATE(u32 pstate) { |
| 160 | u64 nzcv = cpsr; | 151 | u64 nzcv = pstate; |
| 161 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv)); | 152 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv)); |
| 162 | } | 153 | } |
| 163 | 154 | ||
| @@ -219,7 +210,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) { | |||
| 219 | 210 | ||
| 220 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp)); | 211 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp)); |
| 221 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc)); | 212 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc)); |
| 222 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.cpsr)); | 213 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); |
| 223 | 214 | ||
| 224 | for (auto i = 0; i < 29; ++i) { | 215 | for (auto i = 0; i < 29; ++i) { |
| 225 | uregs[i] = UC_ARM64_REG_X0 + i; | 216 | uregs[i] = UC_ARM64_REG_X0 + i; |
| @@ -234,7 +225,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) { | |||
| 234 | 225 | ||
| 235 | for (int i = 0; i < 32; ++i) { | 226 | for (int i = 0; i < 32; ++i) { |
| 236 | uregs[i] = UC_ARM64_REG_Q0 + i; | 227 | uregs[i] = UC_ARM64_REG_Q0 + i; |
| 237 | tregs[i] = &ctx.fpu_registers[i]; | 228 | tregs[i] = &ctx.vector_registers[i]; |
| 238 | } | 229 | } |
| 239 | 230 | ||
| 240 | CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); | 231 | CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); |
| @@ -246,7 +237,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { | |||
| 246 | 237 | ||
| 247 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp)); | 238 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp)); |
| 248 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc)); | 239 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc)); |
| 249 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.cpsr)); | 240 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); |
| 250 | 241 | ||
| 251 | for (int i = 0; i < 29; ++i) { | 242 | for (int i = 0; i < 29; ++i) { |
| 252 | uregs[i] = UC_ARM64_REG_X0 + i; | 243 | uregs[i] = UC_ARM64_REG_X0 + i; |
| @@ -261,7 +252,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { | |||
| 261 | 252 | ||
| 262 | for (auto i = 0; i < 32; ++i) { | 253 | for (auto i = 0; i < 32; ++i) { |
| 263 | uregs[i] = UC_ARM64_REG_Q0 + i; | 254 | uregs[i] = UC_ARM64_REG_Q0 + i; |
| 264 | tregs[i] = (void*)&ctx.fpu_registers[i]; | 255 | tregs[i] = (void*)&ctx.vector_registers[i]; |
| 265 | } | 256 | } |
| 266 | 257 | ||
| 267 | CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32)); | 258 | 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: | |||
| 22 | u64 GetPC() const override; | 22 | u64 GetPC() const override; |
| 23 | u64 GetReg(int index) const override; | 23 | u64 GetReg(int index) const override; |
| 24 | void SetReg(int index, u64 value) override; | 24 | void SetReg(int index, u64 value) override; |
| 25 | u128 GetExtReg(int index) const override; | 25 | u128 GetVectorReg(int index) const override; |
| 26 | void SetExtReg(int index, u128 value) override; | 26 | void SetVectorReg(int index, u128 value) override; |
| 27 | u32 GetVFPReg(int index) const override; | 27 | u32 GetPSTATE() const override; |
| 28 | void SetVFPReg(int index, u32 value) override; | 28 | void SetPSTATE(u32 pstate) override; |
| 29 | u32 GetCPSR() const override; | ||
| 30 | void SetCPSR(u32 cpsr) override; | ||
| 31 | VAddr GetTlsAddress() const override; | 29 | VAddr GetTlsAddress() const override; |
| 32 | void SetTlsAddress(VAddr address) override; | 30 | void SetTlsAddress(VAddr address) override; |
| 33 | void SetTPIDR_EL0(u64 value) override; | 31 | 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; | |||
| 65 | constexpr u32 LR_REGISTER = 30; | 65 | constexpr u32 LR_REGISTER = 30; |
| 66 | constexpr u32 SP_REGISTER = 31; | 66 | constexpr u32 SP_REGISTER = 31; |
| 67 | constexpr u32 PC_REGISTER = 32; | 67 | constexpr u32 PC_REGISTER = 32; |
| 68 | constexpr u32 CPSR_REGISTER = 33; | 68 | constexpr u32 PSTATE_REGISTER = 33; |
| 69 | constexpr u32 UC_ARM64_REG_Q0 = 34; | 69 | constexpr u32 UC_ARM64_REG_Q0 = 34; |
| 70 | constexpr u32 FPSCR_REGISTER = 66; | 70 | constexpr u32 FPCR_REGISTER = 66; |
| 71 | 71 | ||
| 72 | // TODO/WiP - Used while working on support for FPU | 72 | // TODO/WiP - Used while working on support for FPU |
| 73 | constexpr u32 TODO_DUMMY_REG_997 = 997; | 73 | constexpr u32 TODO_DUMMY_REG_997 = 997; |
| @@ -116,7 +116,7 @@ constexpr char target_xml[] = | |||
| 116 | 116 | ||
| 117 | <reg name="pc" bitsize="64" type="code_ptr"/> | 117 | <reg name="pc" bitsize="64" type="code_ptr"/> |
| 118 | 118 | ||
| 119 | <flags id="cpsr_flags" size="4"> | 119 | <flags id="pstate_flags" size="4"> |
| 120 | <field name="SP" start="0" end="0"/> | 120 | <field name="SP" start="0" end="0"/> |
| 121 | <field name="" start="1" end="1"/> | 121 | <field name="" start="1" end="1"/> |
| 122 | <field name="EL" start="2" end="3"/> | 122 | <field name="EL" start="2" end="3"/> |
| @@ -135,7 +135,7 @@ constexpr char target_xml[] = | |||
| 135 | <field name="Z" start="30" end="30"/> | 135 | <field name="Z" start="30" end="30"/> |
| 136 | <field name="N" start="31" end="31"/> | 136 | <field name="N" start="31" end="31"/> |
| 137 | </flags> | 137 | </flags> |
| 138 | <reg name="cpsr" bitsize="32" type="cpsr_flags"/> | 138 | <reg name="pstate" bitsize="32" type="pstate_flags"/> |
| 139 | </feature> | 139 | </feature> |
| 140 | <feature name="org.gnu.gdb.aarch64.fpu"> | 140 | <feature name="org.gnu.gdb.aarch64.fpu"> |
| 141 | </feature> | 141 | </feature> |
| @@ -227,10 +227,10 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) { | |||
| 227 | return thread->context.sp; | 227 | return thread->context.sp; |
| 228 | } else if (id == PC_REGISTER) { | 228 | } else if (id == PC_REGISTER) { |
| 229 | return thread->context.pc; | 229 | return thread->context.pc; |
| 230 | } else if (id == CPSR_REGISTER) { | 230 | } else if (id == PSTATE_REGISTER) { |
| 231 | return thread->context.cpsr; | 231 | return thread->context.pstate; |
| 232 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | 232 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { |
| 233 | return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; | 233 | return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0]; |
| 234 | } else { | 234 | } else { |
| 235 | return 0; | 235 | return 0; |
| 236 | } | 236 | } |
| @@ -247,10 +247,10 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 247 | thread->context.sp = val; | 247 | thread->context.sp = val; |
| 248 | } else if (id == PC_REGISTER) { | 248 | } else if (id == PC_REGISTER) { |
| 249 | thread->context.pc = val; | 249 | thread->context.pc = val; |
| 250 | } else if (id == CPSR_REGISTER) { | 250 | } else if (id == PSTATE_REGISTER) { |
| 251 | thread->context.cpsr = val; | 251 | thread->context.pstate = val; |
| 252 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | 252 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { |
| 253 | thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; | 253 | thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; |
| 254 | } | 254 | } |
| 255 | } | 255 | } |
| 256 | 256 | ||
| @@ -781,11 +781,11 @@ static void ReadRegister() { | |||
| 781 | LongToGdbHex(reply, RegRead(id, current_thread)); | 781 | LongToGdbHex(reply, RegRead(id, current_thread)); |
| 782 | } else if (id == PC_REGISTER) { | 782 | } else if (id == PC_REGISTER) { |
| 783 | LongToGdbHex(reply, RegRead(id, current_thread)); | 783 | LongToGdbHex(reply, RegRead(id, current_thread)); |
| 784 | } else if (id == CPSR_REGISTER) { | 784 | } else if (id == PSTATE_REGISTER) { |
| 785 | IntToGdbHex(reply, (u32)RegRead(id, current_thread)); | 785 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); |
| 786 | } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | 786 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 787 | LongToGdbHex(reply, RegRead(id, current_thread)); | 787 | LongToGdbHex(reply, RegRead(id, current_thread)); |
| 788 | } else if (id == FPSCR_REGISTER) { | 788 | } else if (id == FPCR_REGISTER) { |
| 789 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | 789 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); |
| 790 | } else { | 790 | } else { |
| 791 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); | 791 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); |
| @@ -811,7 +811,7 @@ static void ReadRegisters() { | |||
| 811 | 811 | ||
| 812 | bufptr += 16; | 812 | bufptr += 16; |
| 813 | 813 | ||
| 814 | IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); | 814 | IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread))); |
| 815 | 815 | ||
| 816 | bufptr += 8; | 816 | bufptr += 8; |
| 817 | 817 | ||
| @@ -843,11 +843,11 @@ static void WriteRegister() { | |||
| 843 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 843 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); |
| 844 | } else if (id == PC_REGISTER) { | 844 | } else if (id == PC_REGISTER) { |
| 845 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 845 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); |
| 846 | } else if (id == CPSR_REGISTER) { | 846 | } else if (id == PSTATE_REGISTER) { |
| 847 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | 847 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |
| 848 | } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | 848 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 849 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 849 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); |
| 850 | } else if (id == FPSCR_REGISTER) { | 850 | } else if (id == FPCR_REGISTER) { |
| 851 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | 851 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); |
| 852 | } else { | 852 | } else { |
| 853 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); | 853 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); |
| @@ -866,16 +866,16 @@ static void WriteRegisters() { | |||
| 866 | if (command_buffer[0] != 'G') | 866 | if (command_buffer[0] != 'G') |
| 867 | return SendReply("E01"); | 867 | return SendReply("E01"); |
| 868 | 868 | ||
| 869 | for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { | 869 | for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) { |
| 870 | if (reg <= SP_REGISTER) { | 870 | if (reg <= SP_REGISTER) { |
| 871 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 871 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 872 | } else if (reg == PC_REGISTER) { | 872 | } else if (reg == PC_REGISTER) { |
| 873 | RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 873 | RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 874 | } else if (reg == CPSR_REGISTER) { | 874 | } else if (reg == PSTATE_REGISTER) { |
| 875 | RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); | 875 | RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); |
| 876 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { | 876 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { |
| 877 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 877 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 878 | } else if (reg == FPSCR_REGISTER) { | 878 | } else if (reg == FPCR_REGISTER) { |
| 879 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 879 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 880 | } else { | 880 | } else { |
| 881 | UNIMPLEMENTED(); | 881 | 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 | |||
| 62 | Handle requesting_thread_handle) { | 62 | Handle requesting_thread_handle) { |
| 63 | // The mutex address must be 4-byte aligned | 63 | // The mutex address must be 4-byte aligned |
| 64 | if ((address % sizeof(u32)) != 0) { | 64 | if ((address % sizeof(u32)) != 0) { |
| 65 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); | 65 | return ERR_INVALID_ADDRESS; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); | 68 | 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 | |||
| 100 | ResultCode Mutex::Release(VAddr address) { | 100 | ResultCode Mutex::Release(VAddr address) { |
| 101 | // The mutex address must be 4-byte aligned | 101 | // The mutex address must be 4-byte aligned |
| 102 | if ((address % sizeof(u32)) != 0) { | 102 | if ((address % sizeof(u32)) != 0) { |
| 103 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); | 103 | return ERR_INVALID_ADDRESS; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); | 106 | 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, | |||
| 280 | "requesting_current_thread_handle=0x{:08X}", | 280 | "requesting_current_thread_handle=0x{:08X}", |
| 281 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 281 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 282 | 282 | ||
| 283 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | ||
| 284 | return ERR_INVALID_ADDRESS_STATE; | ||
| 285 | } | ||
| 286 | |||
| 283 | auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); | 287 | auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); |
| 284 | return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, | 288 | return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, |
| 285 | requesting_thread_handle); | 289 | requesting_thread_handle); |
| @@ -289,6 +293,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 289 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | 293 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { |
| 290 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); | 294 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); |
| 291 | 295 | ||
| 296 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | ||
| 297 | return ERR_INVALID_ADDRESS_STATE; | ||
| 298 | } | ||
| 299 | |||
| 292 | return Mutex::Release(mutex_addr); | 300 | return Mutex::Release(mutex_addr); |
| 293 | } | 301 | } |
| 294 | 302 | ||
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 | |||
| 217 | context.cpu_registers[0] = arg; | 217 | context.cpu_registers[0] = arg; |
| 218 | context.pc = entry_point; | 218 | context.pc = entry_point; |
| 219 | context.sp = stack_top; | 219 | context.sp = stack_top; |
| 220 | context.cpsr = 0; | 220 | context.pstate = 0; |
| 221 | context.fpscr = 0; | 221 | context.fpcr = 0; |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, | 224 | 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() { | |||
| 25 | ProfileManager::ProfileManager() { | 25 | ProfileManager::ProfileManager() { |
| 26 | // TODO(ogniK): Create the default user we have for now until loading/saving users is added | 26 | // TODO(ogniK): Create the default user we have for now until loading/saving users is added |
| 27 | auto user_uuid = UUID{1, 0}; | 27 | auto user_uuid = UUID{1, 0}; |
| 28 | CreateNewUser(user_uuid, Settings::values.username); | 28 | ASSERT(CreateNewUser(user_uuid, Settings::values.username).IsSuccess()); |
| 29 | OpenUser(user_uuid); | 29 | OpenUser(user_uuid); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| @@ -91,7 +91,8 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern | |||
| 91 | /// specifically by allowing an std::string for the username. This is required specifically since | 91 | /// specifically by allowing an std::string for the username. This is required specifically since |
| 92 | /// we're loading a string straight from the config | 92 | /// we're loading a string straight from the config |
| 93 | ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) { | 93 | ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) { |
| 94 | ProfileUsername username_output; | 94 | ProfileUsername username_output{}; |
| 95 | |||
| 95 | if (username.size() > username_output.size()) { | 96 | if (username.size() > username_output.size()) { |
| 96 | std::copy_n(username.begin(), username_output.size(), username_output.begin()); | 97 | std::copy_n(username.begin(), username_output.size(), username_output.begin()); |
| 97 | } else { | 98 | } else { |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 4a79ce39c..f5ae57039 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -14,6 +14,7 @@ add_library(video_core STATIC | |||
| 14 | engines/maxwell_dma.cpp | 14 | engines/maxwell_dma.cpp |
| 15 | engines/maxwell_dma.h | 15 | engines/maxwell_dma.h |
| 16 | engines/shader_bytecode.h | 16 | engines/shader_bytecode.h |
| 17 | engines/shader_header.h | ||
| 17 | gpu.cpp | 18 | gpu.cpp |
| 18 | gpu.h | 19 | gpu.h |
| 19 | macro_interpreter.cpp | 20 | macro_interpreter.cpp |
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 { | |||
| 240 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? | 240 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| 243 | enum class ControlCode : u64 { | ||
| 244 | F = 0, | ||
| 245 | LT = 1, | ||
| 246 | EQ = 2, | ||
| 247 | LE = 3, | ||
| 248 | GT = 4, | ||
| 249 | NE = 5, | ||
| 250 | GE = 6, | ||
| 251 | Num = 7, | ||
| 252 | Nan = 8, | ||
| 253 | LTU = 9, | ||
| 254 | EQU = 10, | ||
| 255 | LEU = 11, | ||
| 256 | GTU = 12, | ||
| 257 | NEU = 13, | ||
| 258 | GEU = 14, | ||
| 259 | // | ||
| 260 | OFF = 16, | ||
| 261 | LO = 17, | ||
| 262 | SFF = 18, | ||
| 263 | LS = 19, | ||
| 264 | HI = 20, | ||
| 265 | SFT = 21, | ||
| 266 | HS = 22, | ||
| 267 | OFT = 23, | ||
| 268 | CSM_TA = 24, | ||
| 269 | CSM_TR = 25, | ||
| 270 | CSM_MX = 26, | ||
| 271 | FCSM_TA = 27, | ||
| 272 | FCSM_TR = 28, | ||
| 273 | FCSM_MX = 29, | ||
| 274 | RLE = 30, | ||
| 275 | RGT = 31, | ||
| 276 | }; | ||
| 277 | |||
| 243 | enum class PredicateResultMode : u64 { | 278 | enum class PredicateResultMode : u64 { |
| 244 | None = 0x0, | 279 | None = 0x0, |
| 245 | NotZero = 0x3, | 280 | NotZero = 0x3, |
| @@ -271,6 +306,15 @@ enum class TextureProcessMode : u64 { | |||
| 271 | LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL | 306 | LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL |
| 272 | }; | 307 | }; |
| 273 | 308 | ||
| 309 | enum class TextureMiscMode : u64 { | ||
| 310 | DC, | ||
| 311 | AOFFI, // Uses Offset | ||
| 312 | NDV, | ||
| 313 | NODEP, | ||
| 314 | MZ, | ||
| 315 | PTP, | ||
| 316 | }; | ||
| 317 | |||
| 274 | enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; | 318 | enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; |
| 275 | enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; | 319 | enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; |
| 276 | 320 | ||
| @@ -546,6 +590,15 @@ union Instruction { | |||
| 546 | } pset; | 590 | } pset; |
| 547 | 591 | ||
| 548 | union { | 592 | union { |
| 593 | BitField<0, 3, u64> pred0; | ||
| 594 | BitField<3, 3, u64> pred3; | ||
| 595 | BitField<8, 5, ControlCode> cc; // flag in cc | ||
| 596 | BitField<39, 3, u64> pred39; | ||
| 597 | BitField<42, 1, u64> neg_pred39; | ||
| 598 | BitField<45, 4, PredOperation> op; // op with pred39 | ||
| 599 | } csetp; | ||
| 600 | |||
| 601 | union { | ||
| 549 | BitField<39, 3, u64> pred39; | 602 | BitField<39, 3, u64> pred39; |
| 550 | BitField<42, 1, u64> neg_pred; | 603 | BitField<42, 1, u64> neg_pred; |
| 551 | BitField<43, 1, u64> neg_a; | 604 | BitField<43, 1, u64> neg_a; |
| @@ -590,42 +643,127 @@ union Instruction { | |||
| 590 | BitField<28, 1, u64> array; | 643 | BitField<28, 1, u64> array; |
| 591 | BitField<29, 2, TextureType> texture_type; | 644 | BitField<29, 2, TextureType> texture_type; |
| 592 | BitField<31, 4, u64> component_mask; | 645 | BitField<31, 4, u64> component_mask; |
| 646 | BitField<49, 1, u64> nodep_flag; | ||
| 647 | BitField<50, 1, u64> dc_flag; | ||
| 648 | BitField<54, 1, u64> aoffi_flag; | ||
| 593 | BitField<55, 3, TextureProcessMode> process_mode; | 649 | BitField<55, 3, TextureProcessMode> process_mode; |
| 594 | 650 | ||
| 595 | bool IsComponentEnabled(std::size_t component) const { | 651 | bool IsComponentEnabled(std::size_t component) const { |
| 596 | return ((1ull << component) & component_mask) != 0; | 652 | return ((1ull << component) & component_mask) != 0; |
| 597 | } | 653 | } |
| 654 | |||
| 655 | TextureProcessMode GetTextureProcessMode() const { | ||
| 656 | return process_mode; | ||
| 657 | } | ||
| 658 | |||
| 659 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 660 | switch (mode) { | ||
| 661 | case TextureMiscMode::DC: | ||
| 662 | return dc_flag != 0; | ||
| 663 | case TextureMiscMode::NODEP: | ||
| 664 | return nodep_flag != 0; | ||
| 665 | case TextureMiscMode::AOFFI: | ||
| 666 | return aoffi_flag != 0; | ||
| 667 | default: | ||
| 668 | break; | ||
| 669 | } | ||
| 670 | return false; | ||
| 671 | } | ||
| 598 | } tex; | 672 | } tex; |
| 599 | 673 | ||
| 600 | union { | 674 | union { |
| 601 | BitField<22, 6, TextureQueryType> query_type; | 675 | BitField<22, 6, TextureQueryType> query_type; |
| 602 | BitField<31, 4, u64> component_mask; | 676 | BitField<31, 4, u64> component_mask; |
| 677 | BitField<49, 1, u64> nodep_flag; | ||
| 678 | |||
| 679 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 680 | switch (mode) { | ||
| 681 | case TextureMiscMode::NODEP: | ||
| 682 | return nodep_flag != 0; | ||
| 683 | default: | ||
| 684 | break; | ||
| 685 | } | ||
| 686 | return false; | ||
| 687 | } | ||
| 603 | } txq; | 688 | } txq; |
| 604 | 689 | ||
| 605 | union { | 690 | union { |
| 606 | BitField<28, 1, u64> array; | 691 | BitField<28, 1, u64> array; |
| 607 | BitField<29, 2, TextureType> texture_type; | 692 | BitField<29, 2, TextureType> texture_type; |
| 608 | BitField<31, 4, u64> component_mask; | 693 | BitField<31, 4, u64> component_mask; |
| 694 | BitField<35, 1, u64> ndv_flag; | ||
| 695 | BitField<49, 1, u64> nodep_flag; | ||
| 609 | 696 | ||
| 610 | bool IsComponentEnabled(std::size_t component) const { | 697 | bool IsComponentEnabled(std::size_t component) const { |
| 611 | return ((1ull << component) & component_mask) != 0; | 698 | return ((1ull << component) & component_mask) != 0; |
| 612 | } | 699 | } |
| 700 | |||
| 701 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 702 | switch (mode) { | ||
| 703 | case TextureMiscMode::NDV: | ||
| 704 | return (ndv_flag != 0); | ||
| 705 | case TextureMiscMode::NODEP: | ||
| 706 | return (nodep_flag != 0); | ||
| 707 | default: | ||
| 708 | break; | ||
| 709 | } | ||
| 710 | return false; | ||
| 711 | } | ||
| 613 | } tmml; | 712 | } tmml; |
| 614 | 713 | ||
| 615 | union { | 714 | union { |
| 616 | BitField<28, 1, u64> array; | 715 | BitField<28, 1, u64> array; |
| 617 | BitField<29, 2, TextureType> texture_type; | 716 | BitField<29, 2, TextureType> texture_type; |
| 717 | BitField<35, 1, u64> ndv_flag; | ||
| 718 | BitField<49, 1, u64> nodep_flag; | ||
| 719 | BitField<50, 1, u64> dc_flag; | ||
| 720 | BitField<54, 2, u64> info; | ||
| 618 | BitField<56, 2, u64> component; | 721 | BitField<56, 2, u64> component; |
| 722 | |||
| 723 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 724 | switch (mode) { | ||
| 725 | case TextureMiscMode::NDV: | ||
| 726 | return ndv_flag != 0; | ||
| 727 | case TextureMiscMode::NODEP: | ||
| 728 | return nodep_flag != 0; | ||
| 729 | case TextureMiscMode::DC: | ||
| 730 | return dc_flag != 0; | ||
| 731 | case TextureMiscMode::AOFFI: | ||
| 732 | return info == 1; | ||
| 733 | case TextureMiscMode::PTP: | ||
| 734 | return info == 2; | ||
| 735 | default: | ||
| 736 | break; | ||
| 737 | } | ||
| 738 | return false; | ||
| 739 | } | ||
| 619 | } tld4; | 740 | } tld4; |
| 620 | 741 | ||
| 621 | union { | 742 | union { |
| 743 | BitField<49, 1, u64> nodep_flag; | ||
| 744 | BitField<50, 1, u64> dc_flag; | ||
| 745 | BitField<51, 1, u64> aoffi_flag; | ||
| 622 | BitField<52, 2, u64> component; | 746 | BitField<52, 2, u64> component; |
| 747 | |||
| 748 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 749 | switch (mode) { | ||
| 750 | case TextureMiscMode::DC: | ||
| 751 | return dc_flag != 0; | ||
| 752 | case TextureMiscMode::NODEP: | ||
| 753 | return nodep_flag != 0; | ||
| 754 | case TextureMiscMode::AOFFI: | ||
| 755 | return aoffi_flag != 0; | ||
| 756 | default: | ||
| 757 | break; | ||
| 758 | } | ||
| 759 | return false; | ||
| 760 | } | ||
| 623 | } tld4s; | 761 | } tld4s; |
| 624 | 762 | ||
| 625 | union { | 763 | union { |
| 626 | BitField<0, 8, Register> gpr0; | 764 | BitField<0, 8, Register> gpr0; |
| 627 | BitField<28, 8, Register> gpr28; | 765 | BitField<28, 8, Register> gpr28; |
| 628 | BitField<49, 1, u64> nodep; | 766 | BitField<49, 1, u64> nodep_flag; |
| 629 | BitField<50, 3, u64> component_mask_selector; | 767 | BitField<50, 3, u64> component_mask_selector; |
| 630 | BitField<53, 4, u64> texture_info; | 768 | BitField<53, 4, u64> texture_info; |
| 631 | 769 | ||
| @@ -645,6 +783,37 @@ union Instruction { | |||
| 645 | UNREACHABLE(); | 783 | UNREACHABLE(); |
| 646 | } | 784 | } |
| 647 | 785 | ||
| 786 | TextureProcessMode GetTextureProcessMode() const { | ||
| 787 | switch (texture_info) { | ||
| 788 | case 0: | ||
| 789 | case 2: | ||
| 790 | case 6: | ||
| 791 | case 8: | ||
| 792 | case 9: | ||
| 793 | case 11: | ||
| 794 | return TextureProcessMode::LZ; | ||
| 795 | case 3: | ||
| 796 | case 5: | ||
| 797 | case 13: | ||
| 798 | return TextureProcessMode::LL; | ||
| 799 | default: | ||
| 800 | break; | ||
| 801 | } | ||
| 802 | return TextureProcessMode::None; | ||
| 803 | } | ||
| 804 | |||
| 805 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 806 | switch (mode) { | ||
| 807 | case TextureMiscMode::DC: | ||
| 808 | return (texture_info >= 4 && texture_info <= 6) || texture_info == 9; | ||
| 809 | case TextureMiscMode::NODEP: | ||
| 810 | return nodep_flag != 0; | ||
| 811 | default: | ||
| 812 | break; | ||
| 813 | } | ||
| 814 | return false; | ||
| 815 | } | ||
| 816 | |||
| 648 | bool IsArrayTexture() const { | 817 | bool IsArrayTexture() const { |
| 649 | // TEXS only supports Texture2D arrays. | 818 | // TEXS only supports Texture2D arrays. |
| 650 | return texture_info >= 7 && texture_info <= 9; | 819 | return texture_info >= 7 && texture_info <= 9; |
| @@ -673,6 +842,7 @@ union Instruction { | |||
| 673 | } texs; | 842 | } texs; |
| 674 | 843 | ||
| 675 | union { | 844 | union { |
| 845 | BitField<49, 1, u64> nodep_flag; | ||
| 676 | BitField<53, 4, u64> texture_info; | 846 | BitField<53, 4, u64> texture_info; |
| 677 | 847 | ||
| 678 | TextureType GetTextureType() const { | 848 | TextureType GetTextureType() const { |
| @@ -693,6 +863,26 @@ union Instruction { | |||
| 693 | UNREACHABLE(); | 863 | UNREACHABLE(); |
| 694 | } | 864 | } |
| 695 | 865 | ||
| 866 | TextureProcessMode GetTextureProcessMode() const { | ||
| 867 | if (texture_info == 1 || texture_info == 5 || texture_info == 12) | ||
| 868 | return TextureProcessMode::LL; | ||
| 869 | return TextureProcessMode::LZ; | ||
| 870 | } | ||
| 871 | |||
| 872 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 873 | switch (mode) { | ||
| 874 | case TextureMiscMode::AOFFI: | ||
| 875 | return texture_info == 12 || texture_info == 4; | ||
| 876 | case TextureMiscMode::MZ: | ||
| 877 | return texture_info == 5; | ||
| 878 | case TextureMiscMode::NODEP: | ||
| 879 | return nodep_flag != 0; | ||
| 880 | default: | ||
| 881 | break; | ||
| 882 | } | ||
| 883 | return false; | ||
| 884 | } | ||
| 885 | |||
| 696 | bool IsArrayTexture() const { | 886 | bool IsArrayTexture() const { |
| 697 | // TEXS only supports Texture2D arrays. | 887 | // TEXS only supports Texture2D arrays. |
| 698 | return texture_info == 8; | 888 | return texture_info == 8; |
| @@ -735,6 +925,7 @@ union Instruction { | |||
| 735 | BitField<36, 5, u64> index; | 925 | BitField<36, 5, u64> index; |
| 736 | } cbuf36; | 926 | } cbuf36; |
| 737 | 927 | ||
| 928 | BitField<47, 1, u64> generates_cc; | ||
| 738 | BitField<61, 1, u64> is_b_imm; | 929 | BitField<61, 1, u64> is_b_imm; |
| 739 | BitField<60, 1, u64> is_b_gpr; | 930 | BitField<60, 1, u64> is_b_gpr; |
| 740 | BitField<59, 1, u64> is_c_gpr; | 931 | BitField<59, 1, u64> is_c_gpr; |
| @@ -859,6 +1050,7 @@ public: | |||
| 859 | ISET_IMM, | 1050 | ISET_IMM, |
| 860 | PSETP, | 1051 | PSETP, |
| 861 | PSET, | 1052 | PSET, |
| 1053 | CSETP, | ||
| 862 | XMAD_IMM, | 1054 | XMAD_IMM, |
| 863 | XMAD_CR, | 1055 | XMAD_CR, |
| 864 | XMAD_RC, | 1056 | XMAD_RC, |
| @@ -1095,6 +1287,7 @@ private: | |||
| 1095 | INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), | 1287 | INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), |
| 1096 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), | 1288 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), |
| 1097 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), | 1289 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), |
| 1290 | INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), | ||
| 1098 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), | 1291 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), |
| 1099 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), | 1292 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), |
| 1100 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), | 1293 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), |
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h new file mode 100644 index 000000000..a885ee3cf --- /dev/null +++ b/src/video_core/engines/shader_header.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Tegra::Shader { | ||
| 12 | |||
| 13 | enum class OutputTopology : u32 { | ||
| 14 | PointList = 1, | ||
| 15 | LineStrip = 6, | ||
| 16 | TriangleStrip = 7, | ||
| 17 | }; | ||
| 18 | |||
| 19 | // Documentation in: | ||
| 20 | // http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html#ImapTexture | ||
| 21 | struct Header { | ||
| 22 | union { | ||
| 23 | BitField<0, 5, u32> sph_type; | ||
| 24 | BitField<5, 5, u32> version; | ||
| 25 | BitField<10, 4, u32> shader_type; | ||
| 26 | BitField<14, 1, u32> mrt_enable; | ||
| 27 | BitField<15, 1, u32> kills_pixels; | ||
| 28 | BitField<16, 1, u32> does_global_store; | ||
| 29 | BitField<17, 4, u32> sass_version; | ||
| 30 | BitField<21, 5, u32> reserved; | ||
| 31 | BitField<26, 1, u32> does_load_or_store; | ||
| 32 | BitField<27, 1, u32> does_fp64; | ||
| 33 | BitField<28, 4, u32> stream_out_mask; | ||
| 34 | } common0; | ||
| 35 | |||
| 36 | union { | ||
| 37 | BitField<0, 24, u32> shader_local_memory_low_size; | ||
| 38 | BitField<24, 8, u32> per_patch_attribute_count; | ||
| 39 | } common1; | ||
| 40 | |||
| 41 | union { | ||
| 42 | BitField<0, 24, u32> shader_local_memory_high_size; | ||
| 43 | BitField<24, 8, u32> threads_per_input_primitive; | ||
| 44 | } common2; | ||
| 45 | |||
| 46 | union { | ||
| 47 | BitField<0, 24, u32> shader_local_memory_crs_size; | ||
| 48 | BitField<24, 4, OutputTopology> output_topology; | ||
| 49 | BitField<28, 4, u32> reserved; | ||
| 50 | } common3; | ||
| 51 | |||
| 52 | union { | ||
| 53 | BitField<0, 12, u32> max_output_vertices; | ||
| 54 | BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. | ||
| 55 | BitField<24, 4, u32> reserved; | ||
| 56 | BitField<12, 8, u32> store_req_end; // NOTE: not used by geometry shaders. | ||
| 57 | } common4; | ||
| 58 | |||
| 59 | union { | ||
| 60 | struct { | ||
| 61 | INSERT_PADDING_BYTES(3); // ImapSystemValuesA | ||
| 62 | INSERT_PADDING_BYTES(1); // ImapSystemValuesB | ||
| 63 | INSERT_PADDING_BYTES(16); // ImapGenericVector[32] | ||
| 64 | INSERT_PADDING_BYTES(2); // ImapColor | ||
| 65 | INSERT_PADDING_BYTES(2); // ImapSystemValuesC | ||
| 66 | INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10] | ||
| 67 | INSERT_PADDING_BYTES(1); // ImapReserved | ||
| 68 | INSERT_PADDING_BYTES(3); // OmapSystemValuesA | ||
| 69 | INSERT_PADDING_BYTES(1); // OmapSystemValuesB | ||
| 70 | INSERT_PADDING_BYTES(16); // OmapGenericVector[32] | ||
| 71 | INSERT_PADDING_BYTES(2); // OmapColor | ||
| 72 | INSERT_PADDING_BYTES(2); // OmapSystemValuesC | ||
| 73 | INSERT_PADDING_BYTES(5); // OmapFixedFncTexture[10] | ||
| 74 | INSERT_PADDING_BYTES(1); // OmapReserved | ||
| 75 | } vtg; | ||
| 76 | |||
| 77 | struct { | ||
| 78 | INSERT_PADDING_BYTES(3); // ImapSystemValuesA | ||
| 79 | INSERT_PADDING_BYTES(1); // ImapSystemValuesB | ||
| 80 | INSERT_PADDING_BYTES(32); // ImapGenericVector[32] | ||
| 81 | INSERT_PADDING_BYTES(2); // ImapColor | ||
| 82 | INSERT_PADDING_BYTES(2); // ImapSystemValuesC | ||
| 83 | INSERT_PADDING_BYTES(10); // ImapFixedFncTexture[10] | ||
| 84 | INSERT_PADDING_BYTES(2); // ImapReserved | ||
| 85 | struct { | ||
| 86 | u32 target; | ||
| 87 | union { | ||
| 88 | BitField<0, 1, u32> sample_mask; | ||
| 89 | BitField<1, 1, u32> depth; | ||
| 90 | BitField<2, 30, u32> reserved; | ||
| 91 | }; | ||
| 92 | } omap; | ||
| 93 | bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { | ||
| 94 | const u32 bit = render_target * 4 + component; | ||
| 95 | return omap.target & (1 << bit); | ||
| 96 | } | ||
| 97 | } ps; | ||
| 98 | }; | ||
| 99 | }; | ||
| 100 | |||
| 101 | static_assert(sizeof(Header) == 0x50, "Incorrect structure size"); | ||
| 102 | |||
| 103 | } // namespace Tegra::Shader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 4e7d4a24e..b3e95187e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "video_core/engines/shader_bytecode.h" | 14 | #include "video_core/engines/shader_bytecode.h" |
| 15 | #include "video_core/engines/shader_header.h" | ||
| 15 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 16 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 16 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 17 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 17 | 18 | ||
| @@ -26,7 +27,7 @@ using Tegra::Shader::Sampler; | |||
| 26 | using Tegra::Shader::SubOp; | 27 | using Tegra::Shader::SubOp; |
| 27 | 28 | ||
| 28 | constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; | 29 | constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; |
| 29 | constexpr u32 PROGRAM_HEADER_SIZE = 0x50; | 30 | constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); |
| 30 | 31 | ||
| 31 | class DecompileFail : public std::runtime_error { | 32 | class DecompileFail : public std::runtime_error { |
| 32 | public: | 33 | public: |
| @@ -235,6 +236,14 @@ private: | |||
| 235 | const std::string& suffix; | 236 | const std::string& suffix; |
| 236 | }; | 237 | }; |
| 237 | 238 | ||
| 239 | enum class InternalFlag : u64 { | ||
| 240 | ZeroFlag = 0, | ||
| 241 | CarryFlag = 1, | ||
| 242 | OverflowFlag = 2, | ||
| 243 | NaNFlag = 3, | ||
| 244 | Amount | ||
| 245 | }; | ||
| 246 | |||
| 238 | /** | 247 | /** |
| 239 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state | 248 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state |
| 240 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and | 249 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and |
| @@ -328,13 +337,19 @@ public: | |||
| 328 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, | 337 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, |
| 329 | const std::string& value, u64 dest_num_components, | 338 | const std::string& value, u64 dest_num_components, |
| 330 | u64 value_num_components, bool is_saturated = false, | 339 | u64 value_num_components, bool is_saturated = false, |
| 331 | u64 dest_elem = 0, Register::Size size = Register::Size::Word) { | 340 | u64 dest_elem = 0, Register::Size size = Register::Size::Word, |
| 341 | bool sets_cc = false) { | ||
| 332 | ASSERT_MSG(!is_saturated, "Unimplemented"); | 342 | ASSERT_MSG(!is_saturated, "Unimplemented"); |
| 333 | 343 | ||
| 334 | const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; | 344 | const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; |
| 335 | 345 | ||
| 336 | SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', | 346 | SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', |
| 337 | dest_num_components, value_num_components, dest_elem); | 347 | dest_num_components, value_num_components, dest_elem); |
| 348 | |||
| 349 | if (sets_cc) { | ||
| 350 | const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; | ||
| 351 | SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); | ||
| 352 | } | ||
| 338 | } | 353 | } |
| 339 | 354 | ||
| 340 | /** | 355 | /** |
| @@ -351,6 +366,26 @@ public: | |||
| 351 | shader.AddLine(dest + " = " + src + ';'); | 366 | shader.AddLine(dest + " = " + src + ';'); |
| 352 | } | 367 | } |
| 353 | 368 | ||
| 369 | std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { | ||
| 370 | switch (cc) { | ||
| 371 | case Tegra::Shader::ControlCode::NEU: | ||
| 372 | return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; | ||
| 373 | default: | ||
| 374 | LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); | ||
| 375 | UNREACHABLE(); | ||
| 376 | return "false"; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | std::string GetInternalFlag(const InternalFlag ii) const { | ||
| 381 | const u32 code = static_cast<u32>(ii); | ||
| 382 | return "internalFlag_" + std::to_string(code) + suffix; | ||
| 383 | } | ||
| 384 | |||
| 385 | void SetInternalFlag(const InternalFlag ii, const std::string& value) const { | ||
| 386 | shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); | ||
| 387 | } | ||
| 388 | |||
| 354 | /** | 389 | /** |
| 355 | * Writes code that does a output attribute assignment to register operation. Output attributes | 390 | * Writes code that does a output attribute assignment to register operation. Output attributes |
| 356 | * are stored as floats, so this may require conversion. | 391 | * are stored as floats, so this may require conversion. |
| @@ -414,6 +449,12 @@ public: | |||
| 414 | } | 449 | } |
| 415 | declarations.AddNewLine(); | 450 | declarations.AddNewLine(); |
| 416 | 451 | ||
| 452 | for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { | ||
| 453 | const InternalFlag code = static_cast<InternalFlag>(ii); | ||
| 454 | declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); | ||
| 455 | } | ||
| 456 | declarations.AddNewLine(); | ||
| 457 | |||
| 417 | for (const auto element : declr_input_attribute) { | 458 | for (const auto element : declr_input_attribute) { |
| 418 | // TODO(bunnei): Use proper number of elements for these | 459 | // TODO(bunnei): Use proper number of elements for these |
| 419 | u32 idx = | 460 | u32 idx = |
| @@ -674,7 +715,7 @@ public: | |||
| 674 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) | 715 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) |
| 675 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), | 716 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), |
| 676 | stage(stage), suffix(suffix) { | 717 | stage(stage), suffix(suffix) { |
| 677 | 718 | std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); | |
| 678 | Generate(suffix); | 719 | Generate(suffix); |
| 679 | } | 720 | } |
| 680 | 721 | ||
| @@ -688,23 +729,6 @@ public: | |||
| 688 | } | 729 | } |
| 689 | 730 | ||
| 690 | private: | 731 | private: |
| 691 | // Shader program header for a Fragment Shader. | ||
| 692 | struct FragmentHeader { | ||
| 693 | INSERT_PADDING_WORDS(5); | ||
| 694 | INSERT_PADDING_WORDS(13); | ||
| 695 | u32 enabled_color_outputs; | ||
| 696 | union { | ||
| 697 | BitField<0, 1, u32> writes_samplemask; | ||
| 698 | BitField<1, 1, u32> writes_depth; | ||
| 699 | }; | ||
| 700 | |||
| 701 | bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { | ||
| 702 | const u32 bit = render_target * 4 + component; | ||
| 703 | return enabled_color_outputs & (1 << bit); | ||
| 704 | } | ||
| 705 | }; | ||
| 706 | static_assert(sizeof(FragmentHeader) == PROGRAM_HEADER_SIZE, "FragmentHeader size is wrong"); | ||
| 707 | |||
| 708 | /// Gets the Subroutine object corresponding to the specified address. | 732 | /// Gets the Subroutine object corresponding to the specified address. |
| 709 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { | 733 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { |
| 710 | const auto iter = subroutines.find(Subroutine{begin, end, suffix}); | 734 | const auto iter = subroutines.find(Subroutine{begin, end, suffix}); |
| @@ -954,8 +978,6 @@ private: | |||
| 954 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle | 978 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle |
| 955 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 | 979 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 |
| 956 | 980 | ||
| 957 | ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented"); | ||
| 958 | |||
| 959 | std::size_t written_components = 0; | 981 | std::size_t written_components = 0; |
| 960 | for (u32 component = 0; component < 4; ++component) { | 982 | for (u32 component = 0; component < 4; ++component) { |
| 961 | if (!instr.texs.IsComponentEnabled(component)) { | 983 | if (!instr.texs.IsComponentEnabled(component)) { |
| @@ -1010,10 +1032,8 @@ private: | |||
| 1010 | /// Writes the output values from a fragment shader to the corresponding GLSL output variables. | 1032 | /// Writes the output values from a fragment shader to the corresponding GLSL output variables. |
| 1011 | void EmitFragmentOutputsWrite() { | 1033 | void EmitFragmentOutputsWrite() { |
| 1012 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); | 1034 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); |
| 1013 | FragmentHeader header; | ||
| 1014 | std::memcpy(&header, program_code.data(), PROGRAM_HEADER_SIZE); | ||
| 1015 | 1035 | ||
| 1016 | ASSERT_MSG(header.writes_samplemask == 0, "Samplemask write is unimplemented"); | 1036 | ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); |
| 1017 | 1037 | ||
| 1018 | // Write the color outputs using the data in the shader registers, disabled | 1038 | // Write the color outputs using the data in the shader registers, disabled |
| 1019 | // rendertargets/components are skipped in the register assignment. | 1039 | // rendertargets/components are skipped in the register assignment. |
| @@ -1022,7 +1042,7 @@ private: | |||
| 1022 | ++render_target) { | 1042 | ++render_target) { |
| 1023 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. | 1043 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. |
| 1024 | for (u32 component = 0; component < 4; ++component) { | 1044 | for (u32 component = 0; component < 4; ++component) { |
| 1025 | if (header.IsColorComponentOutputEnabled(render_target, component)) { | 1045 | if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { |
| 1026 | shader.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, | 1046 | shader.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, |
| 1027 | regs.GetRegisterAsFloat(current_reg))); | 1047 | regs.GetRegisterAsFloat(current_reg))); |
| 1028 | ++current_reg; | 1048 | ++current_reg; |
| @@ -1030,7 +1050,7 @@ private: | |||
| 1030 | } | 1050 | } |
| 1031 | } | 1051 | } |
| 1032 | 1052 | ||
| 1033 | if (header.writes_depth) { | 1053 | if (header.ps.omap.depth) { |
| 1034 | // The depth output is always 2 registers after the last color output, and current_reg | 1054 | // The depth output is always 2 registers after the last color output, and current_reg |
| 1035 | // already contains one past the last color register. | 1055 | // already contains one past the last color register. |
| 1036 | 1056 | ||
| @@ -1640,7 +1660,8 @@ private: | |||
| 1640 | } | 1660 | } |
| 1641 | 1661 | ||
| 1642 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, | 1662 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, |
| 1643 | 1, instr.alu.saturate_d, 0, instr.conversion.dest_size); | 1663 | 1, instr.alu.saturate_d, 0, instr.conversion.dest_size, |
| 1664 | instr.generates_cc.Value() != 0); | ||
| 1644 | break; | 1665 | break; |
| 1645 | } | 1666 | } |
| 1646 | case OpCode::Id::I2F_R: | 1667 | case OpCode::Id::I2F_R: |
| @@ -1871,6 +1892,13 @@ private: | |||
| 1871 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; | 1892 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; |
| 1872 | std::string coord; | 1893 | std::string coord; |
| 1873 | 1894 | ||
| 1895 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 1896 | "NODEP is not implemented"); | ||
| 1897 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | ||
| 1898 | "AOFFI is not implemented"); | ||
| 1899 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 1900 | "DC is not implemented"); | ||
| 1901 | |||
| 1874 | switch (texture_type) { | 1902 | switch (texture_type) { |
| 1875 | case Tegra::Shader::TextureType::Texture1D: { | 1903 | case Tegra::Shader::TextureType::Texture1D: { |
| 1876 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 1904 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| @@ -1953,6 +1981,11 @@ private: | |||
| 1953 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; | 1981 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 1954 | bool is_array{instr.texs.IsArrayTexture()}; | 1982 | bool is_array{instr.texs.IsArrayTexture()}; |
| 1955 | 1983 | ||
| 1984 | ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 1985 | "NODEP is not implemented"); | ||
| 1986 | ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 1987 | "DC is not implemented"); | ||
| 1988 | |||
| 1956 | switch (texture_type) { | 1989 | switch (texture_type) { |
| 1957 | case Tegra::Shader::TextureType::Texture2D: { | 1990 | case Tegra::Shader::TextureType::Texture2D: { |
| 1958 | if (is_array) { | 1991 | if (is_array) { |
| @@ -1989,6 +2022,13 @@ private: | |||
| 1989 | ASSERT(instr.tlds.IsArrayTexture() == false); | 2022 | ASSERT(instr.tlds.IsArrayTexture() == false); |
| 1990 | std::string coord; | 2023 | std::string coord; |
| 1991 | 2024 | ||
| 2025 | ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 2026 | "NODEP is not implemented"); | ||
| 2027 | ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | ||
| 2028 | "AOFFI is not implemented"); | ||
| 2029 | ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ), | ||
| 2030 | "MZ is not implemented"); | ||
| 2031 | |||
| 1992 | switch (instr.tlds.GetTextureType()) { | 2032 | switch (instr.tlds.GetTextureType()) { |
| 1993 | case Tegra::Shader::TextureType::Texture2D: { | 2033 | case Tegra::Shader::TextureType::Texture2D: { |
| 1994 | if (instr.tlds.IsArrayTexture()) { | 2034 | if (instr.tlds.IsArrayTexture()) { |
| @@ -2017,6 +2057,17 @@ private: | |||
| 2017 | ASSERT(instr.tld4.array == 0); | 2057 | ASSERT(instr.tld4.array == 0); |
| 2018 | std::string coord; | 2058 | std::string coord; |
| 2019 | 2059 | ||
| 2060 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 2061 | "NODEP is not implemented"); | ||
| 2062 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | ||
| 2063 | "AOFFI is not implemented"); | ||
| 2064 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 2065 | "DC is not implemented"); | ||
| 2066 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), | ||
| 2067 | "NDV is not implemented"); | ||
| 2068 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), | ||
| 2069 | "PTP is not implemented"); | ||
| 2070 | |||
| 2020 | switch (instr.tld4.texture_type) { | 2071 | switch (instr.tld4.texture_type) { |
| 2021 | case Tegra::Shader::TextureType::Texture2D: { | 2072 | case Tegra::Shader::TextureType::Texture2D: { |
| 2022 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2073 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| @@ -2054,6 +2105,13 @@ private: | |||
| 2054 | break; | 2105 | break; |
| 2055 | } | 2106 | } |
| 2056 | case OpCode::Id::TLD4S: { | 2107 | case OpCode::Id::TLD4S: { |
| 2108 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 2109 | "NODEP is not implemented"); | ||
| 2110 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | ||
| 2111 | "AOFFI is not implemented"); | ||
| 2112 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 2113 | "DC is not implemented"); | ||
| 2114 | |||
| 2057 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 2115 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 2058 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 2116 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 2059 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 2117 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| @@ -2066,6 +2124,9 @@ private: | |||
| 2066 | break; | 2124 | break; |
| 2067 | } | 2125 | } |
| 2068 | case OpCode::Id::TXQ: { | 2126 | case OpCode::Id::TXQ: { |
| 2127 | ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 2128 | "NODEP is not implemented"); | ||
| 2129 | |||
| 2069 | // TODO: the new commits on the texture refactor, change the way samplers work. | 2130 | // TODO: the new commits on the texture refactor, change the way samplers work. |
| 2070 | // Sadly, not all texture instructions specify the type of texture their sampler | 2131 | // Sadly, not all texture instructions specify the type of texture their sampler |
| 2071 | // uses. This must be fixed at a later instance. | 2132 | // uses. This must be fixed at a later instance. |
| @@ -2086,6 +2147,11 @@ private: | |||
| 2086 | break; | 2147 | break; |
| 2087 | } | 2148 | } |
| 2088 | case OpCode::Id::TMML: { | 2149 | case OpCode::Id::TMML: { |
| 2150 | ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | ||
| 2151 | "NODEP is not implemented"); | ||
| 2152 | ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), | ||
| 2153 | "NDV is not implemented"); | ||
| 2154 | |||
| 2089 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 2155 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 2090 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2156 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2091 | const bool is_array = instr.tmml.array != 0; | 2157 | const bool is_array = instr.tmml.array != 0; |
| @@ -2252,31 +2318,55 @@ private: | |||
| 2252 | break; | 2318 | break; |
| 2253 | } | 2319 | } |
| 2254 | case OpCode::Type::PredicateSetPredicate: { | 2320 | case OpCode::Type::PredicateSetPredicate: { |
| 2255 | const std::string op_a = | 2321 | switch (opcode->GetId()) { |
| 2256 | GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); | 2322 | case OpCode::Id::PSETP: { |
| 2257 | const std::string op_b = | 2323 | const std::string op_a = |
| 2258 | GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | 2324 | GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); |
| 2325 | const std::string op_b = | ||
| 2326 | GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | ||
| 2259 | 2327 | ||
| 2260 | // We can't use the constant predicate as destination. | 2328 | // We can't use the constant predicate as destination. |
| 2261 | ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | 2329 | ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); |
| 2262 | 2330 | ||
| 2263 | const std::string second_pred = | 2331 | const std::string second_pred = |
| 2264 | GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); | 2332 | GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); |
| 2265 | 2333 | ||
| 2266 | const std::string combiner = GetPredicateCombiner(instr.psetp.op); | 2334 | const std::string combiner = GetPredicateCombiner(instr.psetp.op); |
| 2267 | 2335 | ||
| 2268 | const std::string predicate = | 2336 | const std::string predicate = |
| 2269 | '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; | 2337 | '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; |
| 2270 | 2338 | ||
| 2271 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 2339 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
| 2272 | SetPredicate(instr.psetp.pred3, | 2340 | SetPredicate(instr.psetp.pred3, |
| 2273 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | 2341 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); |
| 2274 | 2342 | ||
| 2275 | if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | 2343 | if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { |
| 2276 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | 2344 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, |
| 2277 | // if enabled | 2345 | // if enabled |
| 2278 | SetPredicate(instr.psetp.pred0, | 2346 | SetPredicate(instr.psetp.pred0, |
| 2279 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | 2347 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); |
| 2348 | } | ||
| 2349 | break; | ||
| 2350 | } | ||
| 2351 | case OpCode::Id::CSETP: { | ||
| 2352 | const std::string pred = | ||
| 2353 | GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); | ||
| 2354 | const std::string combiner = GetPredicateCombiner(instr.csetp.op); | ||
| 2355 | const std::string controlCode = regs.GetControlCode(instr.csetp.cc); | ||
| 2356 | if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 2357 | SetPredicate(instr.csetp.pred3, | ||
| 2358 | '(' + controlCode + ") " + combiner + " (" + pred + ')'); | ||
| 2359 | } | ||
| 2360 | if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 2361 | SetPredicate(instr.csetp.pred0, | ||
| 2362 | "!(" + controlCode + ") " + combiner + " (" + pred + ')'); | ||
| 2363 | } | ||
| 2364 | break; | ||
| 2365 | } | ||
| 2366 | default: { | ||
| 2367 | LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); | ||
| 2368 | UNREACHABLE(); | ||
| 2369 | } | ||
| 2280 | } | 2370 | } |
| 2281 | break; | 2371 | break; |
| 2282 | } | 2372 | } |
| @@ -2666,6 +2756,7 @@ private: | |||
| 2666 | private: | 2756 | private: |
| 2667 | const std::set<Subroutine>& subroutines; | 2757 | const std::set<Subroutine>& subroutines; |
| 2668 | const ProgramCode& program_code; | 2758 | const ProgramCode& program_code; |
| 2759 | Tegra::Shader::Header header; | ||
| 2669 | const u32 main_offset; | 2760 | const u32 main_offset; |
| 2670 | Maxwell3D::Regs::ShaderStage stage; | 2761 | Maxwell3D::Regs::ShaderStage stage; |
| 2671 | const std::string& suffix; | 2762 | const std::string& suffix; |
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() { | |||
| 125 | 125 | ||
| 126 | // System | 126 | // System |
| 127 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); | 127 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); |
| 128 | Settings::values.username = sdl2_config->Get("System", "username", "yuzu"); | ||
| 129 | if (Settings::values.username.empty()) { | ||
| 130 | Settings::values.username = "yuzu"; | ||
| 131 | } | ||
| 128 | 132 | ||
| 129 | // Miscellaneous | 133 | // Miscellaneous |
| 130 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); | 134 | 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 = | |||
| 176 | 176 | ||
| 177 | # Sets the account username, max length is 32 characters | 177 | # Sets the account username, max length is 32 characters |
| 178 | # yuzu (default) | 178 | # yuzu (default) |
| 179 | username = | 179 | username = yuzu |
| 180 | 180 | ||
| 181 | # Sets the systems language index | 181 | # Sets the systems language index |
| 182 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | 182 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, |