summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--externals/cmake-modules/FindSDL2.cmake8
-rw-r--r--src/citra_qt/config.cpp2
-rw-r--r--src/citra_qt/game_list.cpp4
-rw-r--r--src/common/emu_window.h52
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp7
-rw-r--r--src/core/file_sys/archive_extsavedata.h3
-rw-r--r--src/core/hle/kernel/session.h12
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp12
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp8
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp1
-rw-r--r--src/core/hle/service/hid/hid.cpp110
-rw-r--r--src/core/hle/service/hid/hid.h78
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp20
-rw-r--r--src/core/hle/service/hid/hid_user.cpp20
-rw-r--r--src/core/hle/service/soc_u.cpp13
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/video_core/command_processor.cpp46
-rw-r--r--src/video_core/pica.cpp15
-rw-r--r--src/video_core/pica.h15
-rw-r--r--src/video_core/pica_state.h15
-rw-r--r--src/video_core/primitive_assembly.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/shader/shader.cpp18
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], &param, 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));
}