early-access version 3342
This commit is contained in:
parent
4380e7cc36
commit
fa0158a9e2
18 changed files with 265 additions and 151 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 3341.
|
||||
This is the source code for early-access 3342.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -13,34 +13,34 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
|
|||
|
||||
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
|
||||
ScopedSetBlocking sb(this);
|
||||
std::vector<u8> buffer;
|
||||
DriverResult result{DriverResult::Success};
|
||||
JoystickLeftSpiCalibration spi_calibration{};
|
||||
bool has_user_calibration = false;
|
||||
calibration = {};
|
||||
|
||||
result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer);
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
|
||||
if (has_user_calibration) {
|
||||
result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer);
|
||||
} else {
|
||||
result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer);
|
||||
}
|
||||
result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
|
||||
}
|
||||
|
||||
// Read User defined calibration
|
||||
if (result == DriverResult::Success && has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
// Read Factory calibration
|
||||
if (result == DriverResult::Success && !has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
|
||||
calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
|
||||
calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
|
||||
calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
|
||||
calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
|
||||
calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
|
||||
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
|
||||
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
|
||||
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
|
||||
calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
|
||||
calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
|
||||
calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
|
||||
}
|
||||
|
||||
// Nintendo fix for drifting stick
|
||||
// result = ReadSPI(0x60, 0x86 ,buffer, 16);
|
||||
// calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
|
||||
|
||||
// Set a valid default calibration if data is missing
|
||||
ValidateCalibration(calibration);
|
||||
|
||||
|
@ -49,34 +49,34 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
|
|||
|
||||
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
|
||||
ScopedSetBlocking sb(this);
|
||||
std::vector<u8> buffer;
|
||||
DriverResult result{DriverResult::Success};
|
||||
JoystickRightSpiCalibration spi_calibration{};
|
||||
bool has_user_calibration = false;
|
||||
calibration = {};
|
||||
|
||||
result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer);
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
|
||||
if (has_user_calibration) {
|
||||
result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer);
|
||||
} else {
|
||||
result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer);
|
||||
}
|
||||
result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
|
||||
}
|
||||
|
||||
// Read User defined calibration
|
||||
if (result == DriverResult::Success && has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
// Read Factory calibration
|
||||
if (result == DriverResult::Success && !has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
|
||||
calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
|
||||
calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
|
||||
calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
|
||||
calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
|
||||
calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
|
||||
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
|
||||
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
|
||||
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
|
||||
calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
|
||||
calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
|
||||
calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
|
||||
}
|
||||
|
||||
// Nintendo fix for drifting stick
|
||||
// buffer = ReadSPI(0x60, 0x98 , 16);
|
||||
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
|
||||
|
||||
// Set a valid default calibration if data is missing
|
||||
ValidateCalibration(calibration);
|
||||
|
||||
|
@ -85,39 +85,41 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
|
|||
|
||||
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
|
||||
ScopedSetBlocking sb(this);
|
||||
std::vector<u8> buffer;
|
||||
DriverResult result{DriverResult::Success};
|
||||
ImuSpiCalibration spi_calibration{};
|
||||
bool has_user_calibration = false;
|
||||
calibration = {};
|
||||
|
||||
result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer);
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
|
||||
if (has_user_calibration) {
|
||||
result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer);
|
||||
} else {
|
||||
result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer);
|
||||
}
|
||||
result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
|
||||
}
|
||||
|
||||
// Read User defined calibration
|
||||
if (result == DriverResult::Success && has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
// Read Factory calibration
|
||||
if (result == DriverResult::Success && !has_user_calibration) {
|
||||
result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
|
||||
}
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
IMUCalibration device_calibration{};
|
||||
memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration));
|
||||
calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0];
|
||||
calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1];
|
||||
calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2];
|
||||
calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
|
||||
calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
|
||||
calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
|
||||
|
||||
calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0];
|
||||
calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1];
|
||||
calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2];
|
||||
calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0];
|
||||
calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1];
|
||||
calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2];
|
||||
|
||||
calibration.gyro[0].offset = device_calibration.gyroscope_offset[0];
|
||||
calibration.gyro[1].offset = device_calibration.gyroscope_offset[1];
|
||||
calibration.gyro[2].offset = device_calibration.gyroscope_offset[2];
|
||||
calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0];
|
||||
calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1];
|
||||
calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2];
|
||||
|
||||
calibration.gyro[0].scale = device_calibration.gyroscope_scale[0];
|
||||
calibration.gyro[1].scale = device_calibration.gyroscope_scale[1];
|
||||
calibration.gyro[2].scale = device_calibration.gyroscope_scale[2];
|
||||
calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0];
|
||||
calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1];
|
||||
calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2];
|
||||
}
|
||||
|
||||
ValidateCalibration(calibration);
|
||||
|
@ -127,10 +129,12 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
|
|||
|
||||
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
|
||||
s16 current_value) {
|
||||
constexpr s16 DefaultRingRange{800};
|
||||
|
||||
// TODO: Get default calibration form ring itself
|
||||
if (ring_data_max == 0 && ring_data_min == 0) {
|
||||
ring_data_max = current_value + 800;
|
||||
ring_data_min = current_value - 800;
|
||||
ring_data_max = current_value + DefaultRingRange;
|
||||
ring_data_min = current_value - DefaultRingRange;
|
||||
ring_data_default = current_value;
|
||||
}
|
||||
ring_data_max = std::max(ring_data_max, current_value);
|
||||
|
@ -143,42 +147,72 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
|
|||
return DriverResult::Success;
|
||||
}
|
||||
|
||||
DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
|
||||
bool& has_user_calibration) {
|
||||
MagicSpiCalibration spi_magic{};
|
||||
const DriverResult result{ReadSPI(address, spi_magic)};
|
||||
has_user_calibration = false;
|
||||
if (result == DriverResult::Success) {
|
||||
has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
|
||||
spi_magic.second == CalibrationMagic::USR_MAGIC_1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const {
|
||||
return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]);
|
||||
}
|
||||
|
||||
u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const {
|
||||
return static_cast<u16>((block[2] << 4) | (block[1] >> 4));
|
||||
}
|
||||
|
||||
void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) {
|
||||
constexpr u16 DefaultStickCenter{2048};
|
||||
constexpr u16 DefaultStickRange{1740};
|
||||
constexpr u16 DefaultStickCenter{0x800};
|
||||
constexpr u16 DefaultStickRange{0x6cc};
|
||||
|
||||
if (calibration.x.center == 0xFFF || calibration.x.center == 0) {
|
||||
calibration.x.center = DefaultStickCenter;
|
||||
}
|
||||
if (calibration.x.max == 0xFFF || calibration.x.max == 0) {
|
||||
calibration.x.max = DefaultStickRange;
|
||||
}
|
||||
if (calibration.x.min == 0xFFF || calibration.x.min == 0) {
|
||||
calibration.x.min = DefaultStickRange;
|
||||
}
|
||||
calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter);
|
||||
calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange);
|
||||
calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange);
|
||||
|
||||
if (calibration.y.center == 0xFFF || calibration.y.center == 0) {
|
||||
calibration.y.center = DefaultStickCenter;
|
||||
}
|
||||
if (calibration.y.max == 0xFFF || calibration.y.max == 0) {
|
||||
calibration.y.max = DefaultStickRange;
|
||||
}
|
||||
if (calibration.y.min == 0xFFF || calibration.y.min == 0) {
|
||||
calibration.y.min = DefaultStickRange;
|
||||
}
|
||||
calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter);
|
||||
calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange);
|
||||
calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange);
|
||||
}
|
||||
|
||||
void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
|
||||
constexpr s16 DefaultAccelerometerScale{0x4000};
|
||||
constexpr s16 DefaultGyroScale{0x3be7};
|
||||
constexpr s16 DefaultOffset{0};
|
||||
|
||||
for (auto& sensor : calibration.accelerometer) {
|
||||
if (sensor.scale == 0) {
|
||||
sensor.scale = 0x4000;
|
||||
}
|
||||
sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale);
|
||||
sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
|
||||
}
|
||||
for (auto& sensor : calibration.gyro) {
|
||||
if (sensor.scale == 0) {
|
||||
sensor.scale = 0x3be7;
|
||||
}
|
||||
sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale);
|
||||
sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
|
||||
}
|
||||
}
|
||||
|
||||
u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const {
|
||||
if (value == 0) {
|
||||
return default_value;
|
||||
}
|
||||
if (value == 0xFFF) {
|
||||
return default_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const {
|
||||
if (value == 0) {
|
||||
return default_value;
|
||||
}
|
||||
if (value == 0xFFF) {
|
||||
return default_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace InputCommon::Joycon
|
||||
|
|
|
@ -53,9 +53,27 @@ public:
|
|||
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
|
||||
|
||||
private:
|
||||
/// Returns true if the specified address corresponds to the magic value of user calibration
|
||||
DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
|
||||
|
||||
/// Converts a raw calibration block to an u16 value containing the x axis value
|
||||
u16 GetXAxisCalibrationValue(std::span<u8> block) const;
|
||||
|
||||
/// Converts a raw calibration block to an u16 value containing the y axis value
|
||||
u16 GetYAxisCalibrationValue(std::span<u8> block) const;
|
||||
|
||||
/// Ensures that all joystick calibration values are set
|
||||
void ValidateCalibration(JoyStickCalibration& calibration);
|
||||
|
||||
/// Ensures that all motion calibration values are set
|
||||
void ValidateCalibration(MotionCalibration& calibration);
|
||||
|
||||
/// Returns the default value if the value is either zero or 0xFFF
|
||||
u16 ValidateValue(u16 value, u16 default_value) const;
|
||||
|
||||
/// Returns the default value if the value is either zero or 0xFFF
|
||||
s16 ValidateValue(s16 value, s16 default_value) const;
|
||||
|
||||
s16 ring_data_max = 0;
|
||||
s16 ring_data_default = 0;
|
||||
s16 ring_data_min = 0;
|
||||
|
|
|
@ -22,8 +22,8 @@ void JoyconCommonProtocol::SetNonBlocking() {
|
|||
}
|
||||
|
||||
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
|
||||
std::vector<u8> buffer;
|
||||
const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer);
|
||||
std::array<u8, 1> buffer{};
|
||||
const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, buffer);
|
||||
controller_type = ControllerType::None;
|
||||
|
||||
if (result == DriverResult::Success) {
|
||||
|
@ -148,11 +148,13 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
|
|||
return SendData(local_buffer);
|
||||
}
|
||||
|
||||
DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) {
|
||||
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
|
||||
constexpr std::size_t HeaderSize = 20;
|
||||
constexpr std::size_t MaxTries = 10;
|
||||
const auto size = output.size();
|
||||
std::size_t tries = 0;
|
||||
std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size};
|
||||
std::vector<u8> local_buffer(size + 20);
|
||||
std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)};
|
||||
std::vector<u8> local_buffer{};
|
||||
|
||||
buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
|
||||
buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
|
||||
|
@ -167,8 +169,12 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8
|
|||
}
|
||||
} while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]);
|
||||
|
||||
if (local_buffer.size() < size + HeaderSize) {
|
||||
return DriverResult::WrongReply;
|
||||
}
|
||||
|
||||
// Remove header from output
|
||||
output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size);
|
||||
memcpy(output.data(), local_buffer.data() + HeaderSize, size);
|
||||
return DriverResult::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,10 +97,29 @@ public:
|
|||
/**
|
||||
* Reads the SPI memory stored on the joycon
|
||||
* @param Initial address location
|
||||
* @param size in bytes to be read
|
||||
* @returns output buffer containing the responce
|
||||
*/
|
||||
DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output);
|
||||
DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
|
||||
|
||||
/**
|
||||
* Reads the SPI memory stored on the joycon
|
||||
* @param Initial address location
|
||||
* @returns output object containing the responce
|
||||
*/
|
||||
template <typename Output>
|
||||
requires std::is_trivially_copyable_v<Output> DriverResult ReadSPI(SpiAddress addr,
|
||||
Output& output) {
|
||||
std::array<u8, sizeof(Output)> buffer;
|
||||
output = {};
|
||||
|
||||
const auto result = ReadRawSPI(addr, buffer);
|
||||
if (result != DriverResult::Success) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::memcpy(&output, buffer.data(), sizeof(Output));
|
||||
return DriverResult::Success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables MCU chip on the joycon
|
||||
|
|
|
@ -71,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) {
|
|||
|
||||
DriverResult GenericProtocol::GetColor(Color& color) {
|
||||
ScopedSetBlocking sb(this);
|
||||
std::vector<u8> buffer;
|
||||
const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer);
|
||||
std::array<u8, 12> buffer{};
|
||||
const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
|
||||
|
||||
color = {};
|
||||
if (result == DriverResult::Success) {
|
||||
|
@ -87,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) {
|
|||
|
||||
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
|
||||
ScopedSetBlocking sb(this);
|
||||
std::vector<u8> buffer;
|
||||
const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer);
|
||||
std::array<u8, 16> buffer{};
|
||||
const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
|
||||
|
||||
serial_number = {};
|
||||
if (result == DriverResult::Success) {
|
||||
|
|
|
@ -159,13 +159,12 @@ enum class UsbSubCommand : u8 {
|
|||
SEND_UART = 0x92,
|
||||
};
|
||||
|
||||
enum class CalMagic : u8 {
|
||||
enum class CalibrationMagic : u8 {
|
||||
USR_MAGIC_0 = 0xB2,
|
||||
USR_MAGIC_1 = 0xA1,
|
||||
USRR_MAGI_SIZE = 2,
|
||||
};
|
||||
|
||||
enum class CalAddr {
|
||||
enum class SpiAddress {
|
||||
SERIAL_NUMBER = 0X6000,
|
||||
DEVICE_TYPE = 0X6012,
|
||||
COLOR_EXIST = 0X601B,
|
||||
|
@ -396,10 +395,35 @@ struct MotionData {
|
|||
u64 delta_timestamp{};
|
||||
};
|
||||
|
||||
// Output from SPI read command containing user calibration magic
|
||||
struct MagicSpiCalibration {
|
||||
CalibrationMagic first;
|
||||
CalibrationMagic second;
|
||||
};
|
||||
static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size");
|
||||
|
||||
// Output from SPI read command containing left joystick calibration
|
||||
struct JoystickLeftSpiCalibration {
|
||||
std::array<u8, 3> max;
|
||||
std::array<u8, 3> center;
|
||||
std::array<u8, 3> min;
|
||||
};
|
||||
static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9,
|
||||
"JoystickLeftSpiCalibration is an invalid size");
|
||||
|
||||
// Output from SPI read command containing right joystick calibration
|
||||
struct JoystickRightSpiCalibration {
|
||||
std::array<u8, 3> center;
|
||||
std::array<u8, 3> min;
|
||||
std::array<u8, 3> max;
|
||||
};
|
||||
static_assert(sizeof(JoystickRightSpiCalibration) == 0x9,
|
||||
"JoystickRightSpiCalibration is an invalid size");
|
||||
|
||||
struct JoyStickAxisCalibration {
|
||||
u16 max{1};
|
||||
u16 min{1};
|
||||
u16 center{0};
|
||||
u16 max;
|
||||
u16 min;
|
||||
u16 center;
|
||||
};
|
||||
|
||||
struct JoyStickCalibration {
|
||||
|
@ -407,6 +431,14 @@ struct JoyStickCalibration {
|
|||
JoyStickAxisCalibration y;
|
||||
};
|
||||
|
||||
struct ImuSpiCalibration {
|
||||
std::array<s16, 3> accelerometer_offset;
|
||||
std::array<s16, 3> accelerometer_scale;
|
||||
std::array<s16, 3> gyroscope_offset;
|
||||
std::array<s16, 3> gyroscope_scale;
|
||||
};
|
||||
static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size");
|
||||
|
||||
struct RingCalibration {
|
||||
s16 default_value;
|
||||
s16 max_value;
|
||||
|
@ -488,14 +520,6 @@ struct InputReportNfcIr {
|
|||
static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
|
||||
#pragma pack(pop)
|
||||
|
||||
struct IMUCalibration {
|
||||
std::array<s16, 3> accelerometer_offset;
|
||||
std::array<s16, 3> accelerometer_scale;
|
||||
std::array<s16, 3> gyroscope_offset;
|
||||
std::array<s16, 3> gyroscope_scale;
|
||||
};
|
||||
static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
|
||||
|
||||
struct NFCReadBlock {
|
||||
u8 start;
|
||||
u8 end;
|
||||
|
|
|
@ -532,7 +532,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
|||
}
|
||||
|
||||
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
ScalarS32 lod) {
|
||||
ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) {
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
const std::string texture{Texture(ctx, info, index)};
|
||||
const std::string_view type{TextureType(info)};
|
||||
|
|
|
@ -581,7 +581,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
|
|||
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms);
|
||||
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
ScalarS32 lod);
|
||||
ScalarS32 lod, const IR::Value& skip_mips);
|
||||
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord);
|
||||
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
const IR::Value& coord, const IR::Value& derivatives,
|
||||
|
|
|
@ -414,7 +414,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
|
|||
|
||||
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
std::string_view coords, std::string_view offset, std::string_view lod,
|
||||
[[maybe_unused]] std::string_view ms) {
|
||||
std::string_view ms) {
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
if (info.has_bias) {
|
||||
throw NotImplementedException("EmitImageFetch Bias texture samples");
|
||||
|
@ -431,19 +431,24 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
|||
ctx.AddU1("{}=true;", *sparse_inst);
|
||||
}
|
||||
if (!sparse_inst || !supports_sparse) {
|
||||
if (!offset.empty()) {
|
||||
ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture,
|
||||
CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info));
|
||||
const auto int_coords{CoordsCastToInt(coords, info)};
|
||||
if (!ms.empty()) {
|
||||
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms);
|
||||
} else if (!offset.empty()) {
|
||||
ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod,
|
||||
CoordsCastToInt(offset, info));
|
||||
} else {
|
||||
if (info.type == TextureType::Buffer) {
|
||||
ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords);
|
||||
} else {
|
||||
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture,
|
||||
CoordsCastToInt(coords, info), lod);
|
||||
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!ms.empty()) {
|
||||
throw NotImplementedException("EmitImageFetch Sparse MSAA samples");
|
||||
}
|
||||
if (!offset.empty()) {
|
||||
ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));",
|
||||
*sparse_inst, texture, CastToIntVec(coords, info), lod,
|
||||
|
@ -455,27 +460,27 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
|||
}
|
||||
|
||||
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
std::string_view lod) {
|
||||
std::string_view lod, const IR::Value& skip_mips_val) {
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
const auto texture{Texture(ctx, info, index)};
|
||||
const bool skip_mips{skip_mips_val.U1()};
|
||||
const auto mips{
|
||||
[&] { return skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture); }};
|
||||
switch (info.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.AddU32x4(
|
||||
"{}=uvec4(uint(textureSize({},int({}))),0u,0u,uint(textureQueryLevels({})));", inst,
|
||||
texture, lod, texture);
|
||||
return ctx.AddU32x4("{}=uvec4(uint(textureSize({},int({}))),0u,0u,{});", inst, texture, lod,
|
||||
mips());
|
||||
case TextureType::ColorArray1D:
|
||||
case TextureType::Color2D:
|
||||
case TextureType::ColorCube:
|
||||
case TextureType::Color2DRect:
|
||||
return ctx.AddU32x4(
|
||||
"{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst,
|
||||
texture, lod, texture);
|
||||
return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({},int({}))),0u,{});", inst, texture, lod,
|
||||
mips());
|
||||
case TextureType::ColorArray2D:
|
||||
case TextureType::Color3D:
|
||||
case TextureType::ColorArrayCube:
|
||||
return ctx.AddU32x4(
|
||||
"{}=uvec4(uvec3(textureSize({},int({}))),uint(textureQueryLevels({})));", inst, texture,
|
||||
lod, texture);
|
||||
return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({},int({}))),{});", inst, texture, lod,
|
||||
mips());
|
||||
case TextureType::Buffer:
|
||||
throw NotImplementedException("EmitImageQueryDimensions Texture buffers");
|
||||
}
|
||||
|
|
|
@ -654,7 +654,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
|||
std::string_view coords, std::string_view offset, std::string_view lod,
|
||||
std::string_view ms);
|
||||
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
std::string_view lod);
|
||||
std::string_view lod, const IR::Value& skip_mips);
|
||||
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
std::string_view coords);
|
||||
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
|
|
|
@ -445,11 +445,13 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
|
|||
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
|
||||
}
|
||||
|
||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) {
|
||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
|
||||
const IR::Value& skip_mips_val) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const Id image{TextureImage(ctx, info, index)};
|
||||
const Id zero{ctx.u32_zero_value};
|
||||
const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }};
|
||||
const bool skip_mips{skip_mips_val.U1()};
|
||||
const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }};
|
||||
switch (info.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod),
|
||||
|
|
|
@ -539,7 +539,8 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
|||
const IR::Value& offset, const IR::Value& offset2, Id dref);
|
||||
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
|
||||
Id lod, Id ms);
|
||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
|
||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
|
||||
const IR::Value& skip_mips);
|
||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivates, Id offset, Id lod_clamp);
|
||||
|
|
|
@ -1846,15 +1846,16 @@ Value IREmitter::ImageFetch(const Value& handle, const Value& coords, const Valu
|
|||
return Inst(op, Flags{info}, handle, coords, offset, lod, multisampling);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) {
|
||||
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
|
||||
const IR::U1& skip_mips) {
|
||||
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryDimensions
|
||||
: Opcode::BindlessImageQueryDimensions};
|
||||
return Inst(op, handle, lod);
|
||||
return Inst(op, handle, lod, skip_mips);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
|
||||
TextureInstInfo info) {
|
||||
return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod);
|
||||
const IR::U1& skip_mips, TextureInstInfo info) {
|
||||
return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod, skip_mips);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) {
|
||||
|
|
|
@ -320,9 +320,10 @@ public:
|
|||
[[nodiscard]] F32 ImageSampleDrefExplicitLod(const Value& handle, const Value& coords,
|
||||
const F32& dref, const F32& lod,
|
||||
const Value& offset, TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod);
|
||||
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
|
||||
TextureInstInfo info);
|
||||
const IR::U1& skip_mips);
|
||||
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
|
||||
const IR::U1& skip_mips, TextureInstInfo info);
|
||||
|
||||
[[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords,
|
||||
TextureInstInfo info);
|
||||
|
|
|
@ -482,7 +482,7 @@ OPCODE(BindlessImageSampleDrefExplicitLod, F32, U32,
|
|||
OPCODE(BindlessImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
|
||||
OPCODE(BindlessImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
|
||||
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
|
||||
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
|
||||
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, U1, )
|
||||
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
|
||||
OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||
OPCODE(BindlessImageRead, U32x4, U32, Opaque, )
|
||||
|
@ -495,7 +495,7 @@ OPCODE(BoundImageSampleDrefExplicitLod, F32, U32,
|
|||
OPCODE(BoundImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
|
||||
OPCODE(BoundImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
|
||||
OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
|
||||
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
|
||||
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, U1, )
|
||||
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
|
||||
OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||
OPCODE(BoundImageRead, U32x4, U32, Opaque, )
|
||||
|
@ -508,7 +508,7 @@ OPCODE(ImageSampleDrefExplicitLod, F32, Opaq
|
|||
OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, Opaque, )
|
||||
OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, Opaque, F32, )
|
||||
OPCODE(ImageFetch, F32x4, Opaque, Opaque, Opaque, U32, Opaque, )
|
||||
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, )
|
||||
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, )
|
||||
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
|
||||
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, )
|
||||
OPCODE(ImageRead, U32x4, Opaque, Opaque, )
|
||||
|
|
|
@ -15,11 +15,13 @@ enum class Mode : u64 {
|
|||
SamplePos = 5,
|
||||
};
|
||||
|
||||
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg) {
|
||||
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg, u64 mask) {
|
||||
switch (mode) {
|
||||
case Mode::Dimension: {
|
||||
const bool needs_num_mips{((mask >> 3) & 1) != 0};
|
||||
const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
|
||||
const IR::U32 lod{v.X(src_reg)};
|
||||
return v.ir.ImageQueryDimension(handle, lod);
|
||||
return v.ir.ImageQueryDimension(handle, lod, skip_mips);
|
||||
}
|
||||
case Mode::TextureType:
|
||||
case Mode::SamplePos:
|
||||
|
@ -46,7 +48,7 @@ void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) {
|
|||
handle = v.X(src_reg);
|
||||
++src_reg;
|
||||
}
|
||||
const IR::Value query{Query(v, handle, txq.mode, src_reg)};
|
||||
const IR::Value query{Query(v, handle, txq.mode, src_reg, txq.mask)};
|
||||
IR::Reg dest_reg{txq.dest_reg};
|
||||
for (int element = 0; element < 4; ++element) {
|
||||
if (((txq.mask >> element) & 1) == 0) {
|
||||
|
|
|
@ -452,7 +452,8 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
|
|||
const IR::Value coord(inst.Arg(1));
|
||||
const IR::Value handle(ir.Imm32(0));
|
||||
const IR::U32 lod{ir.Imm32(0)};
|
||||
const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, info);
|
||||
const IR::U1 skip_mips{ir.Imm1(true)};
|
||||
const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, skip_mips, info);
|
||||
inst.SetArg(
|
||||
1, ir.CompositeConstruct(
|
||||
ir.FPMul(IR::F32(ir.CompositeExtract(coord, 0)),
|
||||
|
|
Loading…
Reference in a new issue