diff options
23 files changed, 372 insertions, 94 deletions
| diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake index 0af86840a..9b8daa0d1 100644 --- a/externals/cmake-modules/FindSDL2.cmake +++ b/externals/cmake-modules/FindSDL2.cmake @@ -134,11 +134,17 @@ SET(SDL2_SEARCH_PATHS      ${SDL2_PATH}  ) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) +    set(VC_LIB_PATH_SUFFIX lib/x64) +else() +    set(VC_LIB_PATH_SUFFIX lib/x86) +endif() +  FIND_LIBRARY(SDL2_LIBRARY_TEMP      NAMES SDL2      HINTS      $ENV{SDL2DIR} -    PATH_SUFFIXES lib64 lib +    PATH_SUFFIXES lib64 lib ${VC_LIB_PATH_SUFFIX}      PATHS ${SDL2_SEARCH_PATHS}  ) diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 8e247ff5c..d1a19ade9 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -16,7 +16,7 @@ Config::Config() {      // TODO: Don't hardcode the path; let the frontend decide where to put the config files.      qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";      FileUtil::CreateFullPath(qt_config_loc); -    qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat); +    qt_config = new QSettings(QString::fromLocal8Bit(qt_config_loc.c_str()), QSettings::IniFormat);      Reload();  } diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index 1f8d69a03..a0b216b0a 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -66,7 +66,7 @@ void GameList::ValidateEntry(const QModelIndex& item)      if (file_path.isEmpty())          return; -    std::string std_file_path = file_path.toStdString(); +    std::string std_file_path(file_path.toLocal8Bit());      if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path))          return;      emit GameChosen(file_path); @@ -148,7 +148,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d              emit EntryReady({                  new GameListItem(QString::fromStdString(Loader::GetFileTypeString(filetype))), -                new GameListItemPath(QString::fromStdString(physical_name)), +                new GameListItemPath(QString::fromLocal8Bit(physical_name.c_str())),                  new GameListItemSize(FileUtil::GetSize(physical_name)),              });          } diff --git a/src/common/emu_window.h b/src/common/emu_window.h index a0ae4c9fa..7c3486dea 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h @@ -105,7 +105,7 @@ public:       * @todo Fix this function to be thread-safe.       * @return PadState object indicating the current pad state       */ -    const Service::HID::PadState GetPadState() const { +    Service::HID::PadState GetPadState() const {          return pad_state;      } @@ -116,11 +116,59 @@ public:       * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and       *         `pressed` is true if the touch screen is currently being pressed       */ -    const std::tuple<u16, u16, bool> GetTouchState() const { +    std::tuple<u16, u16, bool> GetTouchState() const {          return std::make_tuple(touch_x, touch_y, touch_pressed);      }      /** +     * Gets the current accelerometer state (acceleration along each three axis). +     * Axis explained: +     *   +x is the same direction as LEFT on D-pad. +     *   +y is normal to the touch screen, pointing outward. +     *   +z is the same direction as UP on D-pad. +     * Units: +     *   1 unit of return value = 1/512 g (measured by hw test), +     *   where g is the gravitational acceleration (9.8 m/sec2). +     * @note This should be called by the core emu thread to get a state set by the window thread. +     * @todo Implement accelerometer input in front-end. +     * @return std::tuple of (x, y, z) +     */ +    std::tuple<s16, s16, s16> GetAccelerometerState() const { +        // stubbed +        return std::make_tuple(0, -512, 0); +    } + +    /** +     * Gets the current gyroscope state (angular rates about each three axis). +     * Axis explained: +     *   +x is the same direction as LEFT on D-pad. +     *   +y is normal to the touch screen, pointing outward. +     *   +z is the same direction as UP on D-pad. +     * Orientation is determined by right-hand rule. +     * Units: +     *   1 unit of return value = (1/coef) deg/sec, +     *   where coef is the return value of GetGyroscopeRawToDpsCoefficient(). +     * @note This should be called by the core emu thread to get a state set by the window thread. +     * @todo Implement gyroscope input in front-end. +     * @return std::tuple of (x, y, z) +     */ +    std::tuple<s16, s16, s16> GetGyroscopeState() const { +        // stubbed +        return std::make_tuple(0, 0, 0); +    } + +    /** +     * Gets the coefficient for units conversion of gyroscope state. +     * The conversion formula is r = coefficient * v, +     * where v is angular rate in deg/sec, +     * and r is the gyroscope state. +     * @return float-type coefficient +     */ +    f32 GetGyroscopeRawToDpsCoefficient() const { +        return 14.375f; // taken from hw test, and gyroscope's document +    } + +    /**       * Returns currently active configuration.       * @note Accesses to the returned object need not be consistent because it may be modified in another thread       */ diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp index 2d814345a..5550c112e 100644 --- a/src/core/arm/skyeye_common/armstate.cpp +++ b/src/core/arm/skyeye_common/armstate.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <algorithm>  #include "common/swap.h"  #include "common/logging/log.h"  #include "core/memory.h" @@ -48,8 +49,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)              Spsr[UNDEFBANK] = Spsr_copy;              break;          case FIQ32MODE: -            Reg_firq[0] = Reg[13]; -            Reg_firq[1] = Reg[14]; +            std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin());              Spsr[FIQBANK] = Spsr_copy;              break;          } @@ -85,8 +85,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)              Bank = UNDEFBANK;              break;          case FIQ32MODE: -            Reg[13] = Reg_firq[0]; -            Reg[14] = Reg_firq[1]; +            std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8);              Spsr_copy = Spsr[FIQBANK];              Bank = FIQBANK;              break; diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index 287a6fee1..e9a72850d 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -45,13 +45,14 @@ public:      void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size);  private: +    bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive +      /**       * This holds the full directory path for this archive, it is only set after a successful call       * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.       * See GetExtSaveDataPath for the code that extracts this data from an archive path.       */      std::string mount_point; -    bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive  };  /** diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index adaffcafe..6ddaf970e 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -16,23 +16,23 @@  namespace IPC { -inline u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) { +constexpr u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) {      return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0);  } -inline u32 MoveHandleDesc(unsigned int num_handles = 1) { +constexpr u32 MoveHandleDesc(unsigned int num_handles = 1) {      return 0x0 | ((num_handles - 1) << 26);  } -inline u32 CopyHandleDesc(unsigned int num_handles = 1) { +constexpr u32 CopyHandleDesc(unsigned int num_handles = 1) {      return 0x10 | ((num_handles - 1) << 26);  } -inline u32 CallingPidDesc() { +constexpr u32 CallingPidDesc() {      return 0x20;  } -inline u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { +constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) {      return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10);  } @@ -42,7 +42,7 @@ enum MappedBufferPermissions {      RW = R | W,  }; -inline u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { +constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {      return 0x8 | (size << 4) | (u32)perms;  } diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 0559a07b2..b18060f6d 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -9,6 +9,18 @@ namespace Service {  namespace CFG {  const Interface::FunctionInfo FunctionTable[] = { +    // cfg common +    {0x00010082, GetConfigInfoBlk2,                    "GetConfigInfoBlk2"}, +    {0x00020000, SecureInfoGetRegion,                  "SecureInfoGetRegion"}, +    {0x00030040, GenHashConsoleUnique,                 "GenHashConsoleUnique"}, +    {0x00040000, GetRegionCanadaUSA,                   "GetRegionCanadaUSA"}, +    {0x00050000, GetSystemModel,                       "GetSystemModel"}, +    {0x00060000, GetModelNintendo2DS,                  "GetModelNintendo2DS"}, +    {0x00070040, nullptr,                              "WriteToFirstByteCfgSavegame"}, +    {0x00080080, nullptr,                              "GoThroughTable"}, +    {0x00090040, GetCountryCodeString,                 "GetCountryCodeString"}, +    {0x000A0040, GetCountryCodeID,                     "GetCountryCodeID"}, +    // cfg:i      {0x04010082, GetConfigInfoBlk8,                    "GetConfigInfoBlk8"},      {0x04020082, nullptr,                              "SetConfigInfoBlk4"},      {0x04030000, UpdateConfigNANDSavegame,             "UpdateConfigNANDSavegame"}, diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index b03d290e5..e001f7687 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -9,10 +9,18 @@ namespace Service {  namespace CFG {  const Interface::FunctionInfo FunctionTable[] = { +    // cfg common      {0x00010082, GetConfigInfoBlk2,                    "GetConfigInfoBlk2"},      {0x00020000, SecureInfoGetRegion,                  "SecureInfoGetRegion"},      {0x00030040, GenHashConsoleUnique,                 "GenHashConsoleUnique"}, +    {0x00040000, GetRegionCanadaUSA,                   "GetRegionCanadaUSA"},      {0x00050000, GetSystemModel,                       "GetSystemModel"}, +    {0x00060000, GetModelNintendo2DS,                  "GetModelNintendo2DS"}, +    {0x00070040, nullptr,                              "WriteToFirstByteCfgSavegame"}, +    {0x00080080, nullptr,                              "GoThroughTable"}, +    {0x00090040, GetCountryCodeString,                 "GetCountryCodeString"}, +    {0x000A0040, GetCountryCodeID,                     "GetCountryCodeID"}, +    // cfg:s      {0x04010082, GetConfigInfoBlk8,                    "GetConfigInfoBlk8"},      {0x04020082, nullptr,                              "SetConfigInfoBlk4"},      {0x04030000, UpdateConfigNANDSavegame,             "UpdateConfigNANDSavegame"}, diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index 89ae96c9e..606f7b2eb 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -9,6 +9,7 @@ namespace Service {  namespace CFG {  const Interface::FunctionInfo FunctionTable[] = { +    // cfg common      {0x00010082, GetConfigInfoBlk2,     "GetConfigInfoBlk2"},      {0x00020000, SecureInfoGetRegion,   "SecureInfoGetRegion"},      {0x00030040, GenHashConsoleUnique,  "GenHashConsoleUnique"}, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index cb4fd38e2..1053d0f40 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -33,6 +33,11 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad;  static u32 next_pad_index;  static u32 next_touch_index; +static u32 next_accelerometer_index; +static u32 next_gyroscope_index; + +static int enable_accelerometer_count = 0; // positive means enabled +static int enable_gyroscope_count = 0; // positive means enabled  const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{      Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, @@ -78,17 +83,17 @@ void Update() {      PadState changed = { { (state.hex ^ old_state.hex) } };      // Get the current Pad entry -    PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index]; +    PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];      // Update entry properties -    pad_entry->current_state.hex = state.hex; -    pad_entry->delta_additions.hex = changed.hex & state.hex; -    pad_entry->delta_removals.hex = changed.hex & old_state.hex;; +    pad_entry.current_state.hex = state.hex; +    pad_entry.delta_additions.hex = changed.hex & state.hex; +    pad_entry.delta_removals.hex = changed.hex & old_state.hex;;      // Set circle Pad -    pad_entry->circle_pad_x = state.circle_left  ? -MAX_CIRCLEPAD_POS : +    pad_entry.circle_pad_x = state.circle_left  ? -MAX_CIRCLEPAD_POS :                                state.circle_right ?  MAX_CIRCLEPAD_POS : 0x0; -    pad_entry->circle_pad_y = state.circle_down  ? -MAX_CIRCLEPAD_POS : +    pad_entry.circle_pad_y = state.circle_down  ? -MAX_CIRCLEPAD_POS :                                state.circle_up    ?  MAX_CIRCLEPAD_POS : 0x0;      // If we just updated index 0, provide a new timestamp @@ -101,11 +106,11 @@ void Update() {      next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();      // Get the current touch entry -    TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; +    TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];      bool pressed = false; -    std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState(); -    touch_entry->valid.Assign(pressed ? 1 : 0); +    std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState(); +    touch_entry.valid.Assign(pressed ? 1 : 0);      // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which      // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being @@ -120,6 +125,58 @@ void Update() {      // Signal both handles when there's an update to Pad or touch      event_pad_or_touch_1->Signal();      event_pad_or_touch_2->Signal(); + +    // Update accelerometer +    if (enable_accelerometer_count > 0) { +        mem->accelerometer.index = next_accelerometer_index; +        next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); + +        AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index]; +        std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) +            = VideoCore::g_emu_window->GetAccelerometerState(); + +        // Make up "raw" entry +        // TODO(wwylele): +        // From hardware testing, the raw_entry values are approximately, +        // but not exactly, as twice as corresponding entries (or with a minus sign). +        // It may caused by system calibration to the accelerometer. +        // Figure out how it works, or, if no game reads raw_entry, +        // the following three lines can be removed and leave raw_entry unimplemented. +        mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x; +        mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; +        mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; + +        // If we just updated index 0, provide a new timestamp +        if (mem->accelerometer.index == 0) { +            mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks; +            mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks(); +        } + +        event_accelerometer->Signal(); +    } + +    // Update gyroscope +    if (enable_gyroscope_count > 0) { +        mem->gyroscope.index = next_gyroscope_index; +        next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); + +        GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; +        std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) +            = VideoCore::g_emu_window->GetGyroscopeState(); + +        // Make up "raw" entry +        mem->gyroscope.raw_entry.x = gyroscope_entry.x; +        mem->gyroscope.raw_entry.z = -gyroscope_entry.y; +        mem->gyroscope.raw_entry.y = gyroscope_entry.z; + +        // If we just updated index 0, provide a new timestamp +        if (mem->gyroscope.index == 0) { +            mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks; +            mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks(); +        } + +        event_gyroscope->Signal(); +    }  }  void GetIPCHandles(Service::Interface* self) { @@ -139,40 +196,69 @@ void GetIPCHandles(Service::Interface* self) {  void EnableAccelerometer(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); +    ++enable_accelerometer_count;      event_accelerometer->Signal();      cmd_buff[1] = RESULT_SUCCESS.raw; -    LOG_WARNING(Service_HID, "(STUBBED) called"); +    LOG_DEBUG(Service_HID, "called");  }  void DisableAccelerometer(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); +    --enable_accelerometer_count;      event_accelerometer->Signal();      cmd_buff[1] = RESULT_SUCCESS.raw; -    LOG_WARNING(Service_HID, "(STUBBED) called"); +    LOG_DEBUG(Service_HID, "called");  }  void EnableGyroscopeLow(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); +    ++enable_gyroscope_count;      event_gyroscope->Signal();      cmd_buff[1] = RESULT_SUCCESS.raw; -    LOG_WARNING(Service_HID, "(STUBBED) called"); +    LOG_DEBUG(Service_HID, "called");  }  void DisableGyroscopeLow(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); +    --enable_gyroscope_count;      event_gyroscope->Signal();      cmd_buff[1] = RESULT_SUCCESS.raw; +    LOG_DEBUG(Service_HID, "called"); +} + +void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); + +    cmd_buff[1] = RESULT_SUCCESS.raw; + +    f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient(); +    memcpy(&cmd_buff[2], &coef, 4); +} + +void GetGyroscopeLowCalibrateParam(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); + +    cmd_buff[1] = RESULT_SUCCESS.raw; + +    const s16 param_unit = 6700; // an approximate value taken from hw +    GyroscopeCalibrateParam param = { +        { 0, param_unit, -param_unit }, +        { 0, param_unit, -param_unit }, +        { 0, param_unit, -param_unit }, +    }; +    memcpy(&cmd_buff[2], ¶m, sizeof(param)); +      LOG_WARNING(Service_HID, "(STUBBED) called");  } diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 517f4f2ae..170d19ea8 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -78,6 +78,24 @@ struct TouchDataEntry {  };  /** + * Structure of a single entry of accelerometer state history within HID shared memory + */ +struct AccelerometerDataEntry { +    s16 x; +    s16 y; +    s16 z; +}; + +/** + * Structure of a single entry of gyroscope state history within HID shared memory + */ +struct GyroscopeDataEntry { +    s16 x; +    s16 y; +    s16 z; +}; + +/**   * Structure of data stored in HID shared memory   */  struct SharedMem { @@ -112,6 +130,46 @@ struct SharedMem {          std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates      } touch; + +    /// Accelerometer data +    struct { +        s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 +        s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` +        u32 index; ///< Index of the last updated accelerometer entry + +        INSERT_PADDING_WORDS(0x1); + +        AccelerometerDataEntry raw_entry; +        INSERT_PADDING_BYTES(2); + +        std::array<AccelerometerDataEntry, 8> entries; +    } accelerometer; + +    /// Gyroscope data +    struct { +        s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 +        s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` +        u32 index; ///< Index of the last updated accelerometer entry + +        INSERT_PADDING_WORDS(0x1); + +        GyroscopeDataEntry raw_entry; +        INSERT_PADDING_BYTES(2); + +        std::array<GyroscopeDataEntry, 32> entries; +    } gyroscope; +}; + +/** + * Structure of calibrate params that GetGyroscopeLowCalibrateParam returns + */ +struct GyroscopeCalibrateParam { +    struct { +        // TODO (wwylele): figure out the exact meaning of these params +        s16 zero_point; +        s16 positive_unit_point; +        s16 negative_unit_point; +    } x, y, z;  };  // TODO: MSVC does not support using offsetof() on non-static data members even though this @@ -222,6 +280,26 @@ void DisableGyroscopeLow(Interface* self);   */  void GetSoundVolume(Interface* self); +/** + * HID::GetGyroscopeLowRawToDpsCoefficient service function + *  Inputs: + *      None + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + *      2 : float output value + */ +void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self); + +/** + * HID::GetGyroscopeLowCalibrateParam service function + *  Inputs: + *      None + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + *      2~6 (18 bytes) : struct GyroscopeCalibrateParam + */ +void GetGyroscopeLowCalibrateParam(Service::Interface* self); +  /// Checks for user input updates  void Update(); diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index c50f597eb..046e65b11 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -9,16 +9,16 @@ namespace Service {  namespace HID {  const Interface::FunctionInfo FunctionTable[] = { -    {0x000A0000, GetIPCHandles,              "GetIPCHandles"}, -    {0x000B0000, nullptr,                    "StartAnalogStickCalibration"}, -    {0x000E0000, nullptr,                    "GetAnalogStickCalibrateParam"}, -    {0x00110000, EnableAccelerometer,        "EnableAccelerometer"}, -    {0x00120000, DisableAccelerometer,       "DisableAccelerometer"}, -    {0x00130000, EnableGyroscopeLow,         "EnableGyroscopeLow"}, -    {0x00140000, DisableGyroscopeLow,        "DisableGyroscopeLow"}, -    {0x00150000, nullptr,                    "GetGyroscopeLowRawToDpsCoefficient"}, -    {0x00160000, nullptr,                    "GetGyroscopeLowCalibrateParam"}, -    {0x00170000, GetSoundVolume,             "GetSoundVolume"}, +    {0x000A0000, GetIPCHandles,                      "GetIPCHandles"}, +    {0x000B0000, nullptr,                            "StartAnalogStickCalibration"}, +    {0x000E0000, nullptr,                            "GetAnalogStickCalibrateParam"}, +    {0x00110000, EnableAccelerometer,                "EnableAccelerometer"}, +    {0x00120000, DisableAccelerometer,               "DisableAccelerometer"}, +    {0x00130000, EnableGyroscopeLow,                 "EnableGyroscopeLow"}, +    {0x00140000, DisableGyroscopeLow,                "DisableGyroscopeLow"}, +    {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"}, +    {0x00160000, GetGyroscopeLowCalibrateParam,      "GetGyroscopeLowCalibrateParam"}, +    {0x00170000, GetSoundVolume,                     "GetSoundVolume"},  };  HID_SPVR_Interface::HID_SPVR_Interface() { diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index bbdde2abb..bb157b83d 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -9,16 +9,16 @@ namespace Service {  namespace HID {  const Interface::FunctionInfo FunctionTable[] = { -    {0x000A0000, GetIPCHandles,             "GetIPCHandles"}, -    {0x000B0000, nullptr,                   "StartAnalogStickCalibration"}, -    {0x000E0000, nullptr,                   "GetAnalogStickCalibrateParam"}, -    {0x00110000, EnableAccelerometer,       "EnableAccelerometer"}, -    {0x00120000, DisableAccelerometer,      "DisableAccelerometer"}, -    {0x00130000, EnableGyroscopeLow,        "EnableGyroscopeLow"}, -    {0x00140000, DisableGyroscopeLow,       "DisableGyroscopeLow"}, -    {0x00150000, nullptr,                   "GetGyroscopeLowRawToDpsCoefficient"}, -    {0x00160000, nullptr,                   "GetGyroscopeLowCalibrateParam"}, -    {0x00170000, GetSoundVolume,            "GetSoundVolume"}, +    {0x000A0000, GetIPCHandles,                      "GetIPCHandles"}, +    {0x000B0000, nullptr,                            "StartAnalogStickCalibration"}, +    {0x000E0000, nullptr,                            "GetAnalogStickCalibrateParam"}, +    {0x00110000, EnableAccelerometer,                "EnableAccelerometer"}, +    {0x00120000, DisableAccelerometer,               "DisableAccelerometer"}, +    {0x00130000, EnableGyroscopeLow,                 "EnableGyroscopeLow"}, +    {0x00140000, DisableGyroscopeLow,                "DisableGyroscopeLow"}, +    {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"}, +    {0x00160000, GetGyroscopeLowCalibrateParam,      "GetGyroscopeLowCalibrateParam"}, +    {0x00170000, GetSoundVolume,                     "GetSoundVolume"},  };  HID_U_Interface::HID_U_Interface() { diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index b52e52d4a..ff0af8f12 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -5,6 +5,7 @@  #include <algorithm>  #include <cstring>  #include <unordered_map> +#include <vector>  #include "common/assert.h"  #include "common/bit_field.h" @@ -593,17 +594,13 @@ static void Poll(Service::Interface* self) {      // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)      // so we have to copy the data -    pollfd* platform_pollfd = new pollfd[nfds]; -    for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) -        platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); +    std::vector<pollfd> platform_pollfd(nfds); +    std::transform(input_fds, input_fds + nfds, platform_pollfd.begin(), CTRPollFD::ToPlatform); -    int ret = ::poll(platform_pollfd, nfds, timeout); +    const int ret = ::poll(platform_pollfd.data(), nfds, timeout);      // Now update the output pollfd structure -    for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) -        output_fds[current_fds] = CTRPollFD::FromPlatform(platform_pollfd[current_fds]); - -    delete[] platform_pollfd; +    std::transform(platform_pollfd.begin(), platform_pollfd.end(), output_fds, CTRPollFD::FromPlatform);      int result = 0;      if (ret == SOCKET_ERROR_VALUE) diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index a7f2715ba..84a4ce5fc 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -74,7 +74,7 @@ enum class ResultStatus {      ErrorEncrypted,  }; -static inline u32 MakeMagic(char a, char b, char c, char d) { +constexpr u32 MakeMagic(char a, char b, char c, char d) {      return a | b << 8 | c << 16 | d << 24;  } diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 4b59984ad..028b59348 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -75,12 +75,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {              GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);              break; +        case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): +            g_state.primitive_assembler.Reconfigure(regs.triangle_topology); +            break; + +        case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): +            g_state.primitive_assembler.Reset(); +            break; +          case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): -            if (regs.vs_default_attributes_setup.index == 15) { -                // Reset immediate primitive state -                g_state.immediate.primitive_assembler.Reconfigure(regs.triangle_topology); -                g_state.immediate.attribute_id = 0; -            } +            g_state.immediate.current_attribute = 0; +            default_attr_counter = 0;              break;          // Load default vertex input attributes @@ -105,7 +110,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {                      break;                  } -                Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; +                Math::Vec4<float24> attribute;                  // NOTE: The destination component order indeed is "backwards"                  attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); @@ -119,26 +124,29 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {                  // TODO: Verify that this actually modifies the register!                  if (setup.index < 15) { +                    g_state.vs.default_attributes[setup.index] = attribute;                      setup.index++;                  } else {                      // Put each attribute into an immediate input buffer.                      // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is                      // sent to the primitive assembler. -                    auto& immediate_input = g_state.immediate.input; -                    auto& immediate_attribute_id = g_state.immediate.attribute_id; -                    const auto& attribute_config = regs.vertex_attributes; +                    auto& immediate_input = g_state.immediate.input_vertex; +                    auto& immediate_attribute_id = g_state.immediate.current_attribute;                      immediate_input.attr[immediate_attribute_id++] = attribute; -                    if (immediate_attribute_id >= attribute_config.GetNumTotalAttributes()) { +                    if (immediate_attribute_id >= regs.vs.num_input_attributes+1) {                          immediate_attribute_id = 0;                          Shader::UnitState<false> shader_unit;                          Shader::Setup(shader_unit); +                        if (g_debug_context) +                            g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, static_cast<void*>(&immediate_input)); +                          // Send to vertex shader -                        Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, attribute_config.GetNumTotalAttributes()); +                        Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1);                          // Send to renderer                          using Pica::Shader::OutputVertex; @@ -146,7 +154,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {                              VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2);                          }; -                        g_state.immediate.primitive_assembler.SubmitVertex(output, AddTriangle); +                        g_state.primitive_assembler.SubmitVertex(output, AddTriangle);                      }                  }              } @@ -154,9 +162,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {          }          case PICA_REG_INDEX(gpu_mode): -            if (regs.gpu_mode == Regs::GPUMode::Configuring && regs.vs_default_attributes_setup.index == 15) { +            if (regs.gpu_mode == Regs::GPUMode::Configuring) {                  // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring                  VideoCore::g_renderer->Rasterizer()->DrawTriangles(); + +                if (g_debug_context) { +                    g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); +                }              }              break; @@ -241,7 +253,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {              DebugUtils::GeometryDumper geometry_dumper;              PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());  #endif -            PrimitiveAssembler<Shader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); +            PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler;              if (g_debug_context) {                  for (int i = 0; i < 3; ++i) { @@ -412,16 +424,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {                                                            range.second, range.first);              } -            VideoCore::g_renderer->Rasterizer()->DrawTriangles(); -  #if PICA_DUMP_GEOMETRY              geometry_dumper.Dump();  #endif -            if (g_debug_context) { -                g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); -            } -              break;          } diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index 32ad72674..ccbaf071b 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp @@ -493,12 +493,25 @@ std::string Regs::GetCommandName(int index) {  }  void Init() { +    g_state.Reset();  }  void Shutdown() {      Shader::Shutdown(); +} + +template <typename T> +void Zero(T& o) { +    memset(&o, 0, sizeof(o)); +} -    memset(&g_state, 0, sizeof(State)); +void State::Reset() { +    Zero(regs); +    Zero(vs); +    Zero(gs); +    Zero(cmd_list); +    Zero(immediate); +    primitive_assembler.Reconfigure(Regs::TriangleTopology::List);  }  } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 337cff8ce..16f9e4006 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -71,7 +71,7 @@ struct Regs {      BitField<0, 24, u32> viewport_depth_range; // float24      BitField<0, 24, u32> viewport_depth_far_plane; // float24 -    INSERT_PADDING_WORDS(0x1); +    BitField<0, 3, u32> vs_output_total;      union VSOutputAttributes {          // Maps components of output vertex attributes to semantics @@ -1123,7 +1123,12 @@ struct Regs {              BitField<24, 8, u32> w;          } int_uniforms[4]; -        INSERT_PADDING_WORDS(0x5); +        INSERT_PADDING_WORDS(0x4); + +        union { +            // Number of input attributes to shader unit - 1 +            BitField<0, 4, u32> num_input_attributes; +        };          // Offset to shader program entry point (in words)          BitField<0, 16, u32> main_offset; @@ -1157,8 +1162,10 @@ struct Regs {              }          } input_register_map; -        // OUTMAP_MASK, 0x28E, CODETRANSFER_END -        INSERT_PADDING_WORDS(0x3); +        BitField<0, 16, u32> output_mask; + +        // 0x28E, CODETRANSFER_END +        INSERT_PADDING_WORDS(0x2);          struct {              enum Format : u32 diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index c7616bc55..323290054 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h @@ -12,6 +12,8 @@ namespace Pica {  /// Struct used to describe current Pica state  struct State { +    void Reset(); +      /// Pica registers      Regs regs; @@ -46,13 +48,14 @@ struct State {      /// Struct used to describe immediate mode rendering state      struct ImmediateModeState { -        Shader::InputVertex input; -        // This is constructed with a dummy triangle topology -        PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; -        int attribute_id = 0; - -        ImmediateModeState() : primitive_assembler(Regs::TriangleTopology::List) {} +        // Used to buffer partial vertices for immediate-mode rendering. +        Shader::InputVertex input_vertex; +        // Index of the next attribute to be loaded into `input_vertex`. +        int current_attribute = 0;      } immediate; + +    // This is constructed with a dummy triangle topology +    PrimitiveAssembler<Shader::OutputVertex> primitive_assembler;  };  extern State g_state; ///< Current Pica state diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h index cc6e5fde5..9396b4c85 100644 --- a/src/video_core/primitive_assembly.h +++ b/src/video_core/primitive_assembly.h @@ -20,7 +20,7 @@ struct PrimitiveAssembler {                                                 VertexType& v1,                                                 VertexType& v2)>; -    PrimitiveAssembler(Regs::TriangleTopology topology); +    PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List);      /*       * Queues a vertex, builds primitives from the vertex queue according to the given diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b3dc6aa19..1fadcf5ae 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -190,6 +190,9 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,  }  void RasterizerOpenGL::DrawTriangles() { +    if (vertex_batch.empty()) +        return; +      SyncFramebuffer();      SyncDrawState(); diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 509558fc0..eb1db0778 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -121,15 +121,23 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr      OutputVertex ret;      // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to      // figure out what those circumstances are and enable the remaining outputs then. -    for (int i = 0; i < 7; ++i) { -        const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here +    unsigned index = 0; +    for (unsigned i = 0; i < 7; ++i) { + +        if (index >= g_state.regs.vs_output_total) +            break; + +        if ((g_state.regs.vs.output_mask & (1 << i)) == 0) +            continue; + +        const auto& output_register_map = g_state.regs.vs_output_attributes[index]; // TODO: Don't hardcode VS here          u32 semantics[4] = {              output_register_map.map_x, output_register_map.map_y,              output_register_map.map_z, output_register_map.map_w          }; -        for (int comp = 0; comp < 4; ++comp) { +        for (unsigned comp = 0; comp < 4; ++comp) {              float24* out = ((float24*)&ret) + semantics[comp];              if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {                  *out = state.registers.output[i][comp]; @@ -139,10 +147,12 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr                  memset(out, 0, sizeof(*out));              }          } + +        index++;      }      // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation -    for (int i = 0; i < 4; ++i) { +    for (unsigned i = 0; i < 4; ++i) {          ret.color[i] = float24::FromFloat32(              std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));      } | 
