diff options
25 files changed, 582 insertions, 221 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index ed3b7defc..83b75e61f 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -3,9 +3,12 @@  // Refer to the license.txt file included.  #include "audio_core/algorithm/interpolate.h" +#include "audio_core/audio_out.h"  #include "audio_core/audio_renderer.h" +#include "audio_core/codec.h"  #include "common/assert.h"  #include "common/logging/log.h" +#include "core/hle/kernel/event.h"  #include "core/memory.h"  namespace AudioCore { @@ -13,6 +16,41 @@ namespace AudioCore {  constexpr u32 STREAM_SAMPLE_RATE{48000};  constexpr u32 STREAM_NUM_CHANNELS{2}; +class AudioRenderer::VoiceState { +public: +    bool IsPlaying() const { +        return is_in_use && info.play_state == PlayState::Started; +    } + +    const VoiceOutStatus& GetOutStatus() const { +        return out_status; +    } + +    const VoiceInfo& GetInfo() const { +        return info; +    } + +    VoiceInfo& Info() { +        return info; +    } + +    void SetWaveIndex(std::size_t index); +    std::vector<s16> DequeueSamples(std::size_t sample_count); +    void UpdateState(); +    void RefreshBuffer(); + +private: +    bool is_in_use{}; +    bool is_refresh_pending{}; +    std::size_t wave_index{}; +    std::size_t offset{}; +    Codec::ADPCMState adpcm_state{}; +    InterpolationState interp_state{}; +    std::vector<s16> samples; +    VoiceOutStatus out_status{}; +    VoiceInfo info{}; +}; +  AudioRenderer::AudioRenderer(AudioRendererParameter params,                               Kernel::SharedPtr<Kernel::Event> buffer_event)      : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { @@ -27,6 +65,8 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params,      QueueMixedBuffer(2);  } +AudioRenderer::~AudioRenderer() = default; +  u32 AudioRenderer::GetSampleRate() const {      return worker_params.sample_rate;  } diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index c8d2cd188..2c4f5ab75 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h @@ -8,16 +8,20 @@  #include <memory>  #include <vector> -#include "audio_core/algorithm/interpolate.h" -#include "audio_core/audio_out.h" -#include "audio_core/codec.h"  #include "audio_core/stream.h" +#include "common/common_funcs.h"  #include "common/common_types.h"  #include "common/swap.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/object.h" + +namespace Kernel { +class Event; +}  namespace AudioCore { +class AudioOut; +  enum class PlayState : u8 {      Started = 0,      Stopped = 1, @@ -158,6 +162,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size  class AudioRenderer {  public:      AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event); +    ~AudioRenderer(); +      std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);      void QueueMixedBuffer(Buffer::Tag tag);      void ReleaseAndQueueBuffers(); @@ -166,45 +172,12 @@ public:      u32 GetMixBufferCount() const;  private: -    class VoiceState { -    public: -        bool IsPlaying() const { -            return is_in_use && info.play_state == PlayState::Started; -        } - -        const VoiceOutStatus& GetOutStatus() const { -            return out_status; -        } - -        const VoiceInfo& GetInfo() const { -            return info; -        } - -        VoiceInfo& Info() { -            return info; -        } - -        void SetWaveIndex(std::size_t index); -        std::vector<s16> DequeueSamples(std::size_t sample_count); -        void UpdateState(); -        void RefreshBuffer(); - -    private: -        bool is_in_use{}; -        bool is_refresh_pending{}; -        std::size_t wave_index{}; -        std::size_t offset{}; -        Codec::ADPCMState adpcm_state{}; -        InterpolationState interp_state{}; -        std::vector<s16> samples; -        VoiceOutStatus out_status{}; -        VoiceInfo info{}; -    }; +    class VoiceState;      AudioRendererParameter worker_params;      Kernel::SharedPtr<Kernel::Event> buffer_event;      std::vector<VoiceState> voices; -    std::unique_ptr<AudioCore::AudioOut> audio_out; +    std::unique_ptr<AudioOut> audio_out;      AudioCore::StreamPtr stream;  }; diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 386f2ec66..449db2416 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -7,6 +7,7 @@  #include "audio_core/sink.h"  #include "audio_core/sink_details.h" +#include "audio_core/sink_stream.h"  #include "audio_core/stream.h"  #include "common/assert.h"  #include "common/logging/log.h" diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 3a435982d..27db1112f 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h @@ -11,13 +11,16 @@  #include <queue>  #include "audio_core/buffer.h" -#include "audio_core/sink_stream.h" -#include "common/assert.h"  #include "common/common_types.h" -#include "core/core_timing.h" + +namespace CoreTiming { +struct EventType; +}  namespace AudioCore { +class SinkStream; +  /**   * Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut   */ diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h index c2286fba1..decd760f1 100644 --- a/src/audio_core/time_stretch.h +++ b/src/audio_core/time_stretch.h @@ -4,7 +4,6 @@  #pragma once -#include <array>  #include <cstddef>  #include <SoundTouch.h>  #include "common/common_types.h" 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/core_cpu.cpp b/src/core/core_cpu.cpp index 15d60cc8a..21568ad50 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -9,6 +9,7 @@  #ifdef ARCHITECTURE_x86_64  #include "core/arm/dynarmic/arm_dynarmic.h"  #endif +#include "core/arm/exclusive_monitor.h"  #include "core/arm/unicorn/arm_unicorn.h"  #include "core/core_cpu.h"  #include "core/core_timing.h" @@ -66,6 +67,8 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,      scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());  } +Cpu::~Cpu() = default; +  std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {      if (Settings::values.use_cpu_jit) {  #ifdef ARCHITECTURE_x86_64 diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 1d229b42f..685532965 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -6,11 +6,10 @@  #include <atomic>  #include <condition_variable> +#include <cstddef>  #include <memory>  #include <mutex> -#include <string>  #include "common/common_types.h" -#include "core/arm/exclusive_monitor.h"  namespace Kernel {  class Scheduler; @@ -19,6 +18,7 @@ class Scheduler;  namespace Core {  class ARM_Interface; +class ExclusiveMonitor;  constexpr unsigned NUM_CPU_CORES{4}; @@ -43,6 +43,7 @@ class Cpu {  public:      Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,          std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index); +    ~Cpu();      void RunLoop(bool tight_loop = true); 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/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 1eda5f879..fea9ba5ea 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -13,7 +13,9 @@  namespace Kernel { -#define PARAM(n) Core::CurrentArmInterface().GetReg(n) +static inline u64 Param(int n) { +    return Core::CurrentArmInterface().GetReg(n); +}  /**   * HLE a function return from the current ARM userland process @@ -28,23 +30,23 @@ static inline void FuncReturn(u64 res) {  template <ResultCode func(u64)>  void SvcWrap() { -    FuncReturn(func(PARAM(0)).raw); +    FuncReturn(func(Param(0)).raw);  }  template <ResultCode func(u32)>  void SvcWrap() { -    FuncReturn(func((u32)PARAM(0)).raw); +    FuncReturn(func((u32)Param(0)).raw);  }  template <ResultCode func(u32, u32)>  void SvcWrap() { -    FuncReturn(func((u32)PARAM(0), (u32)PARAM(1)).raw); +    FuncReturn(func((u32)Param(0), (u32)Param(1)).raw);  }  template <ResultCode func(u32*, u32)>  void SvcWrap() {      u32 param_1 = 0; -    u32 retval = func(¶m_1, (u32)PARAM(1)).raw; +    u32 retval = func(¶m_1, (u32)Param(1)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  } @@ -52,39 +54,39 @@ void SvcWrap() {  template <ResultCode func(u32*, u64)>  void SvcWrap() {      u32 param_1 = 0; -    u32 retval = func(¶m_1, PARAM(1)).raw; +    u32 retval = func(¶m_1, Param(1)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  }  template <ResultCode func(u64, s32)>  void SvcWrap() { -    FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); +    FuncReturn(func(Param(0), (s32)Param(1)).raw);  }  template <ResultCode func(u64*, u64)>  void SvcWrap() {      u64 param_1 = 0; -    u32 retval = func(¶m_1, PARAM(1)).raw; +    u32 retval = func(¶m_1, Param(1)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  }  template <ResultCode func(u32, u64)>  void SvcWrap() { -    FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), PARAM(1)).raw); +    FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw);  }  template <ResultCode func(u32, u32, u64)>  void SvcWrap() { -    FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw); +    FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw);  }  template <ResultCode func(u32, u32*, u64*)>  void SvcWrap() {      u32 param_1 = 0;      u64 param_2 = 0; -    ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); +    ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2);      Core::CurrentArmInterface().SetReg(1, param_1);      Core::CurrentArmInterface().SetReg(2, param_2);      FuncReturn(retval.raw); @@ -93,46 +95,46 @@ void SvcWrap() {  template <ResultCode func(u64, u64, u32, u32)>  void SvcWrap() {      FuncReturn( -        func(PARAM(0), PARAM(1), (u32)(PARAM(3) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw); +        func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw);  }  template <ResultCode func(u32, u64, u32)>  void SvcWrap() { -    FuncReturn(func((u32)PARAM(0), PARAM(1), (u32)PARAM(2)).raw); +    FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw);  }  template <ResultCode func(u64, u64, u64)>  void SvcWrap() { -    FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw); +    FuncReturn(func(Param(0), Param(1), Param(2)).raw);  }  template <ResultCode func(u32, u64, u64, u32)>  void SvcWrap() { -    FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw); +    FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw);  }  template <ResultCode func(u32, u64, u64)>  void SvcWrap() { -    FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw); +    FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw);  }  template <ResultCode func(u32*, u64, u64, s64)>  void SvcWrap() {      u32 param_1 = 0; -    ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)); +    ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3));      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval.raw);  }  template <ResultCode func(u64, u64, u32, s64)>  void SvcWrap() { -    FuncReturn(func(PARAM(0), PARAM(1), (u32)PARAM(2), (s64)PARAM(3)).raw); +    FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw);  }  template <ResultCode func(u64*, u64, u64, u64)>  void SvcWrap() {      u64 param_1 = 0; -    u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw; +    u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  } @@ -141,7 +143,7 @@ template <ResultCode func(u32*, u64, u64, u64, u32, s32)>  void SvcWrap() {      u32 param_1 = 0;      u32 retval = -        func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF)) +        func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF))              .raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval); @@ -151,13 +153,13 @@ template <ResultCode func(MemoryInfo*, PageInfo*, u64)>  void SvcWrap() {      MemoryInfo memory_info = {};      PageInfo page_info = {}; -    u32 retval = func(&memory_info, &page_info, PARAM(2)).raw; +    u32 retval = func(&memory_info, &page_info, Param(2)).raw; -    Memory::Write64(PARAM(0), memory_info.base_address); -    Memory::Write64(PARAM(0) + 8, memory_info.size); -    Memory::Write32(PARAM(0) + 16, memory_info.type); -    Memory::Write32(PARAM(0) + 20, memory_info.attributes); -    Memory::Write32(PARAM(0) + 24, memory_info.permission); +    Memory::Write64(Param(0), memory_info.base_address); +    Memory::Write64(Param(0) + 8, memory_info.size); +    Memory::Write32(Param(0) + 16, memory_info.type); +    Memory::Write32(Param(0) + 20, memory_info.attributes); +    Memory::Write32(Param(0) + 24, memory_info.permission);      FuncReturn(retval);  } @@ -165,7 +167,7 @@ void SvcWrap() {  template <ResultCode func(u32*, u64, u64, u32)>  void SvcWrap() {      u32 param_1 = 0; -    u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; +    u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  } @@ -174,7 +176,7 @@ template <ResultCode func(Handle*, u64, u32, u32)>  void SvcWrap() {      u32 param_1 = 0;      u32 retval = -        func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; +        func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw;      Core::CurrentArmInterface().SetReg(1, param_1);      FuncReturn(retval);  } @@ -182,14 +184,14 @@ void SvcWrap() {  template <ResultCode func(u64, u32, s32, s64)>  void SvcWrap() {      FuncReturn( -        func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)) +        func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3))              .raw);  }  template <ResultCode func(u64, u32, s32, s32)>  void SvcWrap() { -    FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), -                    (s32)(PARAM(3) & 0xFFFFFFFF)) +    FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), +                    (s32)(Param(3) & 0xFFFFFFFF))                     .raw);  } @@ -219,20 +221,17 @@ void SvcWrap() {  template <void func(s64)>  void SvcWrap() { -    func((s64)PARAM(0)); +    func((s64)Param(0));  }  template <void func(u64, u64 len)>  void SvcWrap() { -    func(PARAM(0), PARAM(1)); +    func(Param(0), Param(1));  }  template <void func(u64, u64, u64)>  void SvcWrap() { -    func(PARAM(0), PARAM(1), PARAM(2)); +    func(Param(0), Param(1), Param(2));  } -#undef PARAM -#undef FuncReturn -  } // namespace Kernel 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/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d1f7007ec..9c975325a 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -20,6 +20,7 @@  #include "core/hle/service/nvflinger/nvflinger.h"  #include "core/hle/service/pm/pm.h"  #include "core/hle/service/set/set.h" +#include "core/hle/service/vi/vi.h"  #include "core/settings.h"  namespace Service::AM { @@ -334,7 +335,7 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"          {51, nullptr, "SetVrModeEnabled"},          {52, nullptr, "SwitchLcdBacklight"},          {55, nullptr, "IsInControllerFirmwareUpdateSection"}, -        {60, nullptr, "GetDefaultDisplayResolution"}, +        {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},          {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent,           "GetDefaultDisplayResolutionChangeEvent"},          {62, nullptr, "GetHdcpAuthenticationState"}, @@ -393,6 +394,21 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLEReque      LOG_WARNING(Service_AM, "(STUBBED) called");  } +void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { +    IPC::ResponseBuilder rb{ctx, 4}; +    rb.Push(RESULT_SUCCESS); + +    if (Settings::values.use_docked_mode) { +        rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); +        rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); +    } else { +        rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); +        rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); +    } + +    LOG_DEBUG(Service_AM, "called"); +} +  void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {      const bool use_docked_mode{Settings::values.use_docked_mode};      IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index fd9ae296b..b39b0d838 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -123,6 +123,7 @@ private:      void GetOperationMode(Kernel::HLERequestContext& ctx);      void GetPerformanceMode(Kernel::HLERequestContext& ctx);      void GetBootMode(Kernel::HLERequestContext& ctx); +    void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);      Kernel::SharedPtr<Kernel::Event> event;  }; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ab2f17db9..256c49bfc 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -313,7 +313,7 @@ public:              {64, nullptr, "DeactivateJoySixAxisSensor"},              {65, nullptr, "GetJoySixAxisSensorLifoHandle"},              {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, -            {67, nullptr, "StopSixAxisSensor"}, +            {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},              {68, nullptr, "IsSixAxisSensorFusionEnabled"},              {69, nullptr, "EnableSixAxisSensorFusion"},              {70, nullptr, "SetSixAxisSensorFusionParameters"}, @@ -329,7 +329,7 @@ public:              {80, nullptr, "GetGyroscopeZeroDriftMode"},              {81, nullptr, "ResetGyroscopeZeroDriftMode"},              {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, -            {91, nullptr, "ActivateGesture"}, +            {91, &Hid::ActivateGesture, "ActivateGesture"},              {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},              {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},              {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, @@ -364,8 +364,8 @@ public:              {208, nullptr, "GetActualVibrationGcErmCommand"},              {209, nullptr, "BeginPermitVibrationSession"},              {210, nullptr, "EndPermitVibrationSession"}, -            {300, nullptr, "ActivateConsoleSixAxisSensor"}, -            {301, nullptr, "StartConsoleSixAxisSensor"}, +            {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, +            {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},              {302, nullptr, "StopConsoleSixAxisSensor"},              {303, nullptr, "ActivateSevenSixAxisSensor"},              {304, nullptr, "StartSevenSixAxisSensor"}, @@ -579,6 +579,30 @@ private:          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service_HID, "(STUBBED) called");      } + +    void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_HID, "(STUBBED) called"); +    } + +    void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_HID, "(STUBBED) called"); +    } + +    void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_HID, "(STUBBED) called"); +    } + +    void ActivateGesture(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_HID, "(STUBBED) called"); +    }  };  class HidDbg final : public ServiceFramework<HidDbg> { 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,  | 
