Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11d0a6e7b8 | |||
| 26547d3e3b | |||
| 7dcf4c0018 | |||
| ef29bf4515 | |||
| 2dbb144fc6 | |||
| 89199ca215 | |||
| 9cfc5fee2f | |||
| 1a6b1bf1d7 | |||
| c5134cbf3a | |||
| c6d001c94f | |||
| cf63eacc1a | |||
| 5333db91c1 | |||
| c20569ebdf | |||
| 156556ddd2 | |||
| 475d46bb64 | |||
| 94eca09cf6 | |||
| 7af2cb4318 | |||
| 663e221f99 | |||
| 020519def8 | |||
| 9a44c1ea27 | |||
| 65e697de59 | |||
| 047e77e2f0 | |||
| cce14b4cd7 | |||
| 6291975731 | |||
| 00decfbb07 | |||
| 111802bbbb | |||
| 3b5d5fa86f | |||
| dcc26c54a5 | |||
| c04203b786 | |||
| 8bd246032a | |||
| 1dd4132eb1 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
[submodule "inih"]
|
||||
path = externals/inih/inih
|
||||
url = https://github.com/svn2github/inih
|
||||
url = https://github.com/benhoyt/inih.git
|
||||
[submodule "cubeb"]
|
||||
path = externals/cubeb
|
||||
url = https://github.com/kinetiknz/cubeb.git
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ macro(yuzu_find_packages)
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Boost 1.73 boost/1.73.0"
|
||||
"Catch2 2.13 catch2/2.13.0"
|
||||
"fmt 7.0 fmt/7.0.3"
|
||||
"fmt 7.1 fmt/7.1.0"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
From https://github.com/yhirose/cpp-httplib/tree/fce8e6fefdab4ad48bc5b25c98e5ebfda4f3cf53
|
||||
From https://github.com/yhirose/cpp-httplib/tree/ff5677ad197947177c158fe857caff4f0e242045 with https://github.com/yhirose/cpp-httplib/pull/701
|
||||
|
||||
MIT License
|
||||
|
||||
|
||||
Vendored
+443
-214
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
Submodule externals/inih/inih updated: 603729dec8...1e80a47dff
+9
-1
@@ -32,7 +32,6 @@ if (MSVC)
|
||||
# /Zc:inline - Let codegen omit inline functions in object files
|
||||
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
|
||||
add_compile_options(
|
||||
/W3
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
@@ -43,6 +42,14 @@ if (MSVC)
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:throwingNew
|
||||
|
||||
# Warnings
|
||||
/W3
|
||||
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
|
||||
/we4548 # Expression before comma has no effect; expected expression with side-effect
|
||||
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
|
||||
/we4555 # Expression has no effect; expected expression with side-effect
|
||||
/we4834 # Discarding return value of function with 'nodiscard' attribute
|
||||
)
|
||||
|
||||
# /GS- - No stack buffer overflow checks
|
||||
@@ -56,6 +63,7 @@ else()
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=missing-declarations
|
||||
-Werror=reorder
|
||||
-Werror=unused-result
|
||||
-Wextra
|
||||
-Wmissing-declarations
|
||||
-Wno-attributes
|
||||
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
|
||||
void Swap(IOFile& other) noexcept;
|
||||
|
||||
[[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
|
||||
+11
-4
@@ -16,16 +16,23 @@
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
std::string GetLastErrorMsg() {
|
||||
static const std::size_t buff_size = 255;
|
||||
static constexpr std::size_t buff_size = 255;
|
||||
char err_str[buff_size];
|
||||
|
||||
#ifdef _WIN32
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
|
||||
return std::string(err_str, buff_size);
|
||||
#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
|
||||
// Thread safe (GNU-specific)
|
||||
const char* str = strerror_r(errno, err_str, buff_size);
|
||||
return std::string(str);
|
||||
#else
|
||||
// Thread safe (XSI-compliant)
|
||||
strerror_r(errno, err_str, buff_size);
|
||||
const int success = strerror_r(errno, err_str, buff_size);
|
||||
if (success != 0) {
|
||||
return {};
|
||||
}
|
||||
return std::string(err_str);
|
||||
#endif
|
||||
|
||||
return std::string(err_str, buff_size);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include "common/alignment.h"
|
||||
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||
: kernel.CreateNewUserProcessID();
|
||||
process->capabilities.InitializeForMetadatalessProcess();
|
||||
|
||||
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
|
||||
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
|
||||
std::uniform_int_distribution<u64> distribution;
|
||||
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
|
||||
[&] { return distribution(rng); });
|
||||
|
||||
@@ -1201,6 +1201,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, nullptr, "PrepareForJit"},
|
||||
|
||||
@@ -260,7 +260,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
|
||||
{404, nullptr, "HasLeftRightBattery"},
|
||||
{405, nullptr, "GetNpadInterfaceType"},
|
||||
{406, nullptr, "GetNpadLeftRightInterfaceType"},
|
||||
{407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"},
|
||||
{407, nullptr, "GetNpadOfHighestBatteryLevel"},
|
||||
{408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
|
||||
{500, nullptr, "GetPalmaConnectionHandle"},
|
||||
{501, nullptr, "InitializePalma"},
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
{23, nullptr, "Convert"},
|
||||
{24, nullptr, "ConvertCoreDataToCharInfo"},
|
||||
{25, nullptr, "ConvertCharInfoToCoreData"},
|
||||
{26, nullptr, "Append"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ SET::SET() : ServiceFramework("set") {
|
||||
{8, &SET::GetQuestFlag, "GetQuestFlag"},
|
||||
{9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"},
|
||||
{10, nullptr, "GetFirmwareVersionForDebug"},
|
||||
{11, nullptr, "GetDeviceNickName"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -300,6 +300,8 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
{198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
|
||||
{199, nullptr, "GetButtonConfigRegisteredSettings"},
|
||||
{200, nullptr, "SetButtonConfigRegisteredSettings"},
|
||||
{201, nullptr, "GetFieldTestingFlag"},
|
||||
{202, nullptr, "SetFieldTestingFlag"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -21,26 +21,6 @@
|
||||
|
||||
namespace GCAdapter {
|
||||
|
||||
// Used to loop through and assign button in poller
|
||||
constexpr std::array<PadButton, 12> PadButtonArray{
|
||||
PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN,
|
||||
PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R,
|
||||
PadButton::PAD_TRIGGER_L, PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B,
|
||||
PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START,
|
||||
};
|
||||
|
||||
static void PadToState(const GCPadStatus& pad, GCState& out_state) {
|
||||
for (const auto& button : PadButtonArray) {
|
||||
const auto button_key = static_cast<u16>(button);
|
||||
const auto button_value = (pad.button & button_key) != 0;
|
||||
out_state.buttons.insert_or_assign(static_cast<s32>(button_key), button_value);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < pad.axis_values.size(); ++i) {
|
||||
out_state.axes.insert_or_assign(static_cast<u32>(i), pad.axis_values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Adapter::Adapter() {
|
||||
if (usb_adapter_handle != nullptr) {
|
||||
return;
|
||||
@@ -49,168 +29,263 @@ Adapter::Adapter() {
|
||||
|
||||
const int init_res = libusb_init(&libusb_ctx);
|
||||
if (init_res == LIBUSB_SUCCESS) {
|
||||
Setup();
|
||||
adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this);
|
||||
} else {
|
||||
LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res);
|
||||
}
|
||||
}
|
||||
|
||||
GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
|
||||
GCPadStatus pad = {};
|
||||
const std::size_t offset = 1 + (9 * port);
|
||||
Adapter::~Adapter() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
adapter_controllers_status[port] = static_cast<ControllerTypes>(adapter_payload[offset] >> 4);
|
||||
void Adapter::AdapterInputThread() {
|
||||
LOG_DEBUG(Input, "GC Adapter input thread started");
|
||||
s32 payload_size{};
|
||||
AdapterPayload adapter_payload{};
|
||||
|
||||
if (adapter_scan_thread.joinable()) {
|
||||
adapter_scan_thread.join();
|
||||
}
|
||||
|
||||
while (adapter_input_thread_running) {
|
||||
libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(),
|
||||
static_cast<s32>(adapter_payload.size()), &payload_size, 16);
|
||||
if (IsPayloadCorrect(adapter_payload, payload_size)) {
|
||||
UpdateControllers(adapter_payload);
|
||||
UpdateVibrations();
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
if (restart_scan_thread) {
|
||||
adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this);
|
||||
restart_scan_thread = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) {
|
||||
if (payload_size != static_cast<s32>(adapter_payload.size()) ||
|
||||
adapter_payload[0] != LIBUSB_DT_HID) {
|
||||
LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size,
|
||||
adapter_payload[0]);
|
||||
if (input_error_counter++ > 20) {
|
||||
LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?");
|
||||
adapter_input_thread_running = false;
|
||||
restart_scan_thread = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
input_error_counter = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Adapter::UpdateControllers(const AdapterPayload& adapter_payload) {
|
||||
for (std::size_t port = 0; port < pads.size(); ++port) {
|
||||
const std::size_t offset = 1 + (9 * port);
|
||||
const auto type = static_cast<ControllerTypes>(adapter_payload[offset] >> 4);
|
||||
UpdatePadType(port, type);
|
||||
if (DeviceConnected(port)) {
|
||||
const u8 b1 = adapter_payload[offset + 1];
|
||||
const u8 b2 = adapter_payload[offset + 2];
|
||||
UpdateStateButtons(port, b1, b2);
|
||||
UpdateStateAxes(port, adapter_payload);
|
||||
if (configuring) {
|
||||
UpdateYuzuSettings(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) {
|
||||
if (pads[port].type == pad_type) {
|
||||
return;
|
||||
}
|
||||
// Device changed reset device and set new type
|
||||
ResetDevice(port);
|
||||
pads[port].type = pad_type;
|
||||
}
|
||||
|
||||
void Adapter::UpdateStateButtons(std::size_t port, u8 b1, u8 b2) {
|
||||
if (port >= pads.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr std::array<PadButton, 8> b1_buttons{
|
||||
PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X,
|
||||
PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT,
|
||||
PadButton::PAD_BUTTON_DOWN, PadButton::PAD_BUTTON_UP,
|
||||
PadButton::ButtonA, PadButton::ButtonB, PadButton::ButtonX, PadButton::ButtonY,
|
||||
PadButton::ButtonLeft, PadButton::ButtonRight, PadButton::ButtonDown, PadButton::ButtonUp,
|
||||
};
|
||||
|
||||
static constexpr std::array<PadButton, 4> b2_buttons{
|
||||
PadButton::PAD_BUTTON_START,
|
||||
PadButton::PAD_TRIGGER_Z,
|
||||
PadButton::PAD_TRIGGER_R,
|
||||
PadButton::PAD_TRIGGER_L,
|
||||
PadButton::ButtonStart,
|
||||
PadButton::TriggerZ,
|
||||
PadButton::TriggerR,
|
||||
PadButton::TriggerL,
|
||||
};
|
||||
pads[port].buttons = 0;
|
||||
for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
|
||||
if ((b1 & (1U << i)) != 0) {
|
||||
pads[port].buttons =
|
||||
static_cast<u16>(pads[port].buttons | static_cast<u16>(b1_buttons[i]));
|
||||
pads[port].last_button = b1_buttons[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
|
||||
if ((b2 & (1U << j)) != 0) {
|
||||
pads[port].buttons =
|
||||
static_cast<u16>(pads[port].buttons | static_cast<u16>(b2_buttons[j]));
|
||||
pads[port].last_button = b2_buttons[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) {
|
||||
if (port >= pads.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::size_t offset = 1 + (9 * port);
|
||||
static constexpr std::array<PadAxes, 6> axes{
|
||||
PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX,
|
||||
PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight,
|
||||
};
|
||||
|
||||
if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) {
|
||||
// Controller may have been disconnected, recalibrate if reconnected.
|
||||
get_origin[port] = true;
|
||||
for (const PadAxes axis : axes) {
|
||||
const auto index = static_cast<std::size_t>(axis);
|
||||
const u8 axis_value = adapter_payload[offset + 3 + index];
|
||||
if (pads[port].axis_origin[index] == 255) {
|
||||
pads[port].axis_origin[index] = axis_value;
|
||||
}
|
||||
pads[port].axis_values[index] =
|
||||
static_cast<s16>(axis_value - pads[port].axis_origin[index]);
|
||||
}
|
||||
|
||||
if (adapter_controllers_status[port] != ControllerTypes::None) {
|
||||
const u8 b1 = adapter_payload[offset + 1];
|
||||
const u8 b2 = adapter_payload[offset + 2];
|
||||
|
||||
for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
|
||||
if ((b1 & (1U << i)) != 0) {
|
||||
pad.button = static_cast<u16>(pad.button | static_cast<u16>(b1_buttons[i]));
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
|
||||
if ((b2 & (1U << j)) != 0) {
|
||||
pad.button = static_cast<u16>(pad.button | static_cast<u16>(b2_buttons[j]));
|
||||
}
|
||||
}
|
||||
for (PadAxes axis : axes) {
|
||||
const auto index = static_cast<std::size_t>(axis);
|
||||
pad.axis_values[index] = adapter_payload[offset + 3 + index];
|
||||
}
|
||||
|
||||
if (get_origin[port]) {
|
||||
origin_status[port].axis_values = pad.axis_values;
|
||||
get_origin[port] = false;
|
||||
}
|
||||
}
|
||||
return pad;
|
||||
}
|
||||
|
||||
void Adapter::Read() {
|
||||
LOG_DEBUG(Input, "GC Adapter Read() thread started");
|
||||
void Adapter::UpdateYuzuSettings(std::size_t port) {
|
||||
if (port >= pads.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int payload_size;
|
||||
std::array<u8, 37> adapter_payload;
|
||||
std::array<GCPadStatus, 4> pads;
|
||||
constexpr u8 axis_threshold = 50;
|
||||
GCPadStatus pad_status = {.port = port};
|
||||
|
||||
while (adapter_thread_running) {
|
||||
libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(),
|
||||
sizeof(adapter_payload), &payload_size, 16);
|
||||
if (pads[port].buttons != 0) {
|
||||
pad_status.button = pads[port].last_button;
|
||||
pad_queue.Push(pad_status);
|
||||
}
|
||||
|
||||
if (payload_size != sizeof(adapter_payload) || adapter_payload[0] != LIBUSB_DT_HID) {
|
||||
LOG_ERROR(Input,
|
||||
"Error reading payload (size: {}, type: {:02x}) Is the adapter connected?",
|
||||
payload_size, adapter_payload[0]);
|
||||
adapter_thread_running = false; // error reading from adapter, stop reading.
|
||||
break;
|
||||
// Accounting for a threshold here to ensure an intentional press
|
||||
for (std::size_t i = 0; i < pads[port].axis_values.size(); ++i) {
|
||||
const s16 value = pads[port].axis_values[i];
|
||||
|
||||
if (value > axis_threshold || value < -axis_threshold) {
|
||||
pad_status.axis = static_cast<PadAxes>(i);
|
||||
pad_status.axis_value = value;
|
||||
pad_status.axis_threshold = axis_threshold;
|
||||
pad_queue.Push(pad_status);
|
||||
}
|
||||
for (std::size_t port = 0; port < pads.size(); ++port) {
|
||||
pads[port] = GetPadStatus(port, adapter_payload);
|
||||
if (DeviceConnected(port) && configuring) {
|
||||
if (pads[port].button != 0) {
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accounting for a threshold here to ensure an intentional press
|
||||
for (size_t i = 0; i < pads[port].axis_values.size(); ++i) {
|
||||
const u8 value = pads[port].axis_values[i];
|
||||
const u8 origin = origin_status[port].axis_values[i];
|
||||
void Adapter::UpdateVibrations() {
|
||||
// Use 8 states to keep the switching between on/off fast enough for
|
||||
// a human to not notice the difference between switching from on/off
|
||||
// More states = more rumble strengths = slower update time
|
||||
constexpr u8 vibration_states = 8;
|
||||
|
||||
if (value > origin + pads[port].THRESHOLD ||
|
||||
value < origin - pads[port].THRESHOLD) {
|
||||
pads[port].axis = static_cast<PadAxes>(i);
|
||||
pads[port].axis_value = pads[port].axis_values[i];
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
}
|
||||
}
|
||||
PadToState(pads[port], state[port]);
|
||||
vibration_counter = (vibration_counter + 1) % vibration_states;
|
||||
|
||||
for (GCController& pad : pads) {
|
||||
const bool vibrate = pad.rumble_amplitude > vibration_counter;
|
||||
vibration_changed |= vibrate != pad.enable_vibration;
|
||||
pad.enable_vibration = vibrate;
|
||||
}
|
||||
SendVibrations();
|
||||
}
|
||||
|
||||
void Adapter::SendVibrations() {
|
||||
if (!rumble_enabled || !vibration_changed) {
|
||||
return;
|
||||
}
|
||||
s32 size{};
|
||||
constexpr u8 rumble_command = 0x11;
|
||||
const u8 p1 = pads[0].enable_vibration;
|
||||
const u8 p2 = pads[1].enable_vibration;
|
||||
const u8 p3 = pads[2].enable_vibration;
|
||||
const u8 p4 = pads[3].enable_vibration;
|
||||
std::array<u8, 5> payload = {rumble_command, p1, p2, p3, p4};
|
||||
const int err = libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, payload.data(),
|
||||
static_cast<s32>(payload.size()), &size, 16);
|
||||
if (err) {
|
||||
LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err));
|
||||
if (output_error_counter++ > 5) {
|
||||
LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled");
|
||||
rumble_enabled = false;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
return;
|
||||
}
|
||||
output_error_counter = 0;
|
||||
vibration_changed = false;
|
||||
}
|
||||
|
||||
bool Adapter::RumblePlay(std::size_t port, f32 amplitude) {
|
||||
amplitude = std::clamp(amplitude, 0.0f, 1.0f);
|
||||
const auto raw_amp = static_cast<u8>(amplitude * 0x8);
|
||||
pads[port].rumble_amplitude = raw_amp;
|
||||
|
||||
return rumble_enabled;
|
||||
}
|
||||
|
||||
void Adapter::AdapterScanThread() {
|
||||
adapter_scan_thread_running = true;
|
||||
adapter_input_thread_running = false;
|
||||
if (adapter_input_thread.joinable()) {
|
||||
adapter_input_thread.join();
|
||||
}
|
||||
ClearLibusbHandle();
|
||||
ResetDevices();
|
||||
while (adapter_scan_thread_running && !adapter_input_thread_running) {
|
||||
Setup();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
void Adapter::Setup() {
|
||||
// Initialize all controllers as unplugged
|
||||
adapter_controllers_status.fill(ControllerTypes::None);
|
||||
// Initialize all ports to store axis origin values
|
||||
get_origin.fill(true);
|
||||
usb_adapter_handle = libusb_open_device_with_vid_pid(libusb_ctx, 0x057e, 0x0337);
|
||||
|
||||
// pointer to list of connected usb devices
|
||||
libusb_device** devices{};
|
||||
|
||||
// populate the list of devices, get the count
|
||||
const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices);
|
||||
if (device_count < 0) {
|
||||
LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count);
|
||||
if (usb_adapter_handle == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!CheckDeviceAccess()) {
|
||||
ClearLibusbHandle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (devices != nullptr) {
|
||||
for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
|
||||
if (CheckDeviceAccess(devices[index])) {
|
||||
// GC Adapter found and accessible, registering it
|
||||
GetGCEndpoint(devices[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
libusb_free_device_list(devices, 1);
|
||||
libusb_device* device = libusb_get_device(usb_adapter_handle);
|
||||
|
||||
LOG_INFO(Input, "GC adapter is now connected");
|
||||
// GC Adapter found and accessible, registering it
|
||||
if (GetGCEndpoint(device)) {
|
||||
adapter_scan_thread_running = false;
|
||||
adapter_input_thread_running = true;
|
||||
rumble_enabled = true;
|
||||
input_error_counter = 0;
|
||||
output_error_counter = 0;
|
||||
adapter_input_thread = std::thread(&Adapter::AdapterInputThread, this);
|
||||
}
|
||||
}
|
||||
|
||||
bool Adapter::CheckDeviceAccess(libusb_device* device) {
|
||||
libusb_device_descriptor desc;
|
||||
const int get_descriptor_error = libusb_get_device_descriptor(device, &desc);
|
||||
if (get_descriptor_error) {
|
||||
// could not acquire the descriptor, no point in trying to use it.
|
||||
LOG_ERROR(Input, "libusb_get_device_descriptor failed with error: {}",
|
||||
get_descriptor_error);
|
||||
return false;
|
||||
bool Adapter::CheckDeviceAccess() {
|
||||
// This fixes payload problems from offbrand GCAdapters
|
||||
const s32 control_transfer_error =
|
||||
libusb_control_transfer(usb_adapter_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
|
||||
if (control_transfer_error < 0) {
|
||||
LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error);
|
||||
}
|
||||
|
||||
if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) {
|
||||
// This isn't the device we are looking for.
|
||||
return false;
|
||||
}
|
||||
const int open_error = libusb_open(device, &usb_adapter_handle);
|
||||
|
||||
if (open_error == LIBUSB_ERROR_ACCESS) {
|
||||
LOG_ERROR(Input, "Yuzu can not gain access to this device: ID {:04X}:{:04X}.",
|
||||
desc.idVendor, desc.idProduct);
|
||||
return false;
|
||||
}
|
||||
if (open_error) {
|
||||
LOG_ERROR(Input, "libusb_open failed to open device with error = {}", open_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
int kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0);
|
||||
s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0);
|
||||
if (kernel_driver_error == 1) {
|
||||
kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0);
|
||||
if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) {
|
||||
@@ -236,13 +311,13 @@ bool Adapter::CheckDeviceAccess(libusb_device* device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Adapter::GetGCEndpoint(libusb_device* device) {
|
||||
bool Adapter::GetGCEndpoint(libusb_device* device) {
|
||||
libusb_config_descriptor* config = nullptr;
|
||||
const int config_descriptor_return = libusb_get_config_descriptor(device, 0, &config);
|
||||
if (config_descriptor_return != LIBUSB_SUCCESS) {
|
||||
LOG_ERROR(Input, "libusb_get_config_descriptor failed with error = {}",
|
||||
config_descriptor_return);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u8 ic = 0; ic < config->bNumInterfaces; ic++) {
|
||||
@@ -264,31 +339,51 @@ void Adapter::GetGCEndpoint(libusb_device* device) {
|
||||
unsigned char clear_payload = 0x13;
|
||||
libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload,
|
||||
sizeof(clear_payload), nullptr, 16);
|
||||
|
||||
adapter_thread_running = true;
|
||||
adapter_input_thread = std::thread(&Adapter::Read, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Adapter::~Adapter() {
|
||||
Reset();
|
||||
}
|
||||
void Adapter::JoinThreads() {
|
||||
restart_scan_thread = false;
|
||||
adapter_input_thread_running = false;
|
||||
adapter_scan_thread_running = false;
|
||||
|
||||
void Adapter::Reset() {
|
||||
if (adapter_thread_running) {
|
||||
adapter_thread_running = false;
|
||||
if (adapter_scan_thread.joinable()) {
|
||||
adapter_scan_thread.join();
|
||||
}
|
||||
|
||||
if (adapter_input_thread.joinable()) {
|
||||
adapter_input_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
adapter_controllers_status.fill(ControllerTypes::None);
|
||||
get_origin.fill(true);
|
||||
|
||||
void Adapter::ClearLibusbHandle() {
|
||||
if (usb_adapter_handle) {
|
||||
libusb_release_interface(usb_adapter_handle, 1);
|
||||
libusb_close(usb_adapter_handle);
|
||||
usb_adapter_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Adapter::ResetDevices() {
|
||||
for (std::size_t i = 0; i < pads.size(); ++i) {
|
||||
ResetDevice(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Adapter::ResetDevice(std::size_t port) {
|
||||
pads[port].type = ControllerTypes::None;
|
||||
pads[port].enable_vibration = false;
|
||||
pads[port].rumble_amplitude = 0;
|
||||
pads[port].buttons = 0;
|
||||
pads[port].last_button = PadButton::Undefined;
|
||||
pads[port].axis_values.fill(0);
|
||||
pads[port].axis_origin.fill(255);
|
||||
}
|
||||
|
||||
void Adapter::Reset() {
|
||||
JoinThreads();
|
||||
ClearLibusbHandle();
|
||||
ResetDevices();
|
||||
|
||||
if (libusb_ctx) {
|
||||
libusb_exit(libusb_ctx);
|
||||
@@ -297,11 +392,11 @@ void Adapter::Reset() {
|
||||
|
||||
std::vector<Common::ParamPackage> Adapter::GetInputDevices() const {
|
||||
std::vector<Common::ParamPackage> devices;
|
||||
for (std::size_t port = 0; port < state.size(); ++port) {
|
||||
for (std::size_t port = 0; port < pads.size(); ++port) {
|
||||
if (!DeviceConnected(port)) {
|
||||
continue;
|
||||
}
|
||||
std::string name = fmt::format("Gamecube Controller {}", port);
|
||||
std::string name = fmt::format("Gamecube Controller {}", port + 1);
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "gcpad"},
|
||||
{"display", std::move(name)},
|
||||
@@ -318,18 +413,18 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
|
||||
// This list also excludes any button that can't be really mapped
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
|
||||
switch_to_gcadapter_button = {
|
||||
std::pair{Settings::NativeButton::A, PadButton::PAD_BUTTON_A},
|
||||
{Settings::NativeButton::B, PadButton::PAD_BUTTON_B},
|
||||
{Settings::NativeButton::X, PadButton::PAD_BUTTON_X},
|
||||
{Settings::NativeButton::Y, PadButton::PAD_BUTTON_Y},
|
||||
{Settings::NativeButton::Plus, PadButton::PAD_BUTTON_START},
|
||||
{Settings::NativeButton::DLeft, PadButton::PAD_BUTTON_LEFT},
|
||||
{Settings::NativeButton::DUp, PadButton::PAD_BUTTON_UP},
|
||||
{Settings::NativeButton::DRight, PadButton::PAD_BUTTON_RIGHT},
|
||||
{Settings::NativeButton::DDown, PadButton::PAD_BUTTON_DOWN},
|
||||
{Settings::NativeButton::SL, PadButton::PAD_TRIGGER_L},
|
||||
{Settings::NativeButton::SR, PadButton::PAD_TRIGGER_R},
|
||||
{Settings::NativeButton::R, PadButton::PAD_TRIGGER_Z},
|
||||
std::pair{Settings::NativeButton::A, PadButton::ButtonA},
|
||||
{Settings::NativeButton::B, PadButton::ButtonB},
|
||||
{Settings::NativeButton::X, PadButton::ButtonX},
|
||||
{Settings::NativeButton::Y, PadButton::ButtonY},
|
||||
{Settings::NativeButton::Plus, PadButton::ButtonStart},
|
||||
{Settings::NativeButton::DLeft, PadButton::ButtonLeft},
|
||||
{Settings::NativeButton::DUp, PadButton::ButtonUp},
|
||||
{Settings::NativeButton::DRight, PadButton::ButtonRight},
|
||||
{Settings::NativeButton::DDown, PadButton::ButtonDown},
|
||||
{Settings::NativeButton::SL, PadButton::TriggerL},
|
||||
{Settings::NativeButton::SR, PadButton::TriggerR},
|
||||
{Settings::NativeButton::R, PadButton::TriggerZ},
|
||||
};
|
||||
if (!params.Has("port")) {
|
||||
return {};
|
||||
@@ -352,8 +447,10 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
|
||||
for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) {
|
||||
Common::ParamPackage button_params({{"engine", "gcpad"}});
|
||||
button_params.Set("port", params.Get("port", 0));
|
||||
button_params.Set("button", static_cast<int>(PadButton::PAD_STICK));
|
||||
button_params.Set("axis", static_cast<int>(gcadapter_axis));
|
||||
button_params.Set("button", static_cast<s32>(PadButton::Stick));
|
||||
button_params.Set("axis", static_cast<s32>(gcadapter_axis));
|
||||
button_params.Set("threshold", 0.5f);
|
||||
button_params.Set("direction", "+");
|
||||
mapping.insert_or_assign(switch_button, std::move(button_params));
|
||||
}
|
||||
return mapping;
|
||||
@@ -382,46 +479,33 @@ InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice(
|
||||
}
|
||||
|
||||
bool Adapter::DeviceConnected(std::size_t port) const {
|
||||
return adapter_controllers_status[port] != ControllerTypes::None;
|
||||
}
|
||||
|
||||
void Adapter::ResetDeviceType(std::size_t port) {
|
||||
adapter_controllers_status[port] = ControllerTypes::None;
|
||||
return pads[port].type != ControllerTypes::None;
|
||||
}
|
||||
|
||||
void Adapter::BeginConfiguration() {
|
||||
get_origin.fill(true);
|
||||
for (auto& pq : pad_queue) {
|
||||
pq.Clear();
|
||||
}
|
||||
pad_queue.Clear();
|
||||
configuring = true;
|
||||
}
|
||||
|
||||
void Adapter::EndConfiguration() {
|
||||
for (auto& pq : pad_queue) {
|
||||
pq.Clear();
|
||||
}
|
||||
pad_queue.Clear();
|
||||
configuring = false;
|
||||
}
|
||||
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() {
|
||||
Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() {
|
||||
return pad_queue;
|
||||
}
|
||||
|
||||
const std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() const {
|
||||
const Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() const {
|
||||
return pad_queue;
|
||||
}
|
||||
|
||||
std::array<GCState, 4>& Adapter::GetPadState() {
|
||||
return state;
|
||||
GCController& Adapter::GetPadState(std::size_t port) {
|
||||
return pads.at(port);
|
||||
}
|
||||
|
||||
const std::array<GCState, 4>& Adapter::GetPadState() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
int Adapter::GetOriginValue(u32 port, u32 axis) const {
|
||||
return origin_status[port].axis_values[axis];
|
||||
const GCController& Adapter::GetPadState(std::size_t port) const {
|
||||
return pads.at(port);
|
||||
}
|
||||
|
||||
} // namespace GCAdapter
|
||||
|
||||
@@ -19,24 +19,23 @@ struct libusb_device_handle;
|
||||
namespace GCAdapter {
|
||||
|
||||
enum class PadButton {
|
||||
PAD_BUTTON_LEFT = 0x0001,
|
||||
PAD_BUTTON_RIGHT = 0x0002,
|
||||
PAD_BUTTON_DOWN = 0x0004,
|
||||
PAD_BUTTON_UP = 0x0008,
|
||||
PAD_TRIGGER_Z = 0x0010,
|
||||
PAD_TRIGGER_R = 0x0020,
|
||||
PAD_TRIGGER_L = 0x0040,
|
||||
PAD_BUTTON_A = 0x0100,
|
||||
PAD_BUTTON_B = 0x0200,
|
||||
PAD_BUTTON_X = 0x0400,
|
||||
PAD_BUTTON_Y = 0x0800,
|
||||
PAD_BUTTON_START = 0x1000,
|
||||
Undefined = 0x0000,
|
||||
ButtonLeft = 0x0001,
|
||||
ButtonRight = 0x0002,
|
||||
ButtonDown = 0x0004,
|
||||
ButtonUp = 0x0008,
|
||||
TriggerZ = 0x0010,
|
||||
TriggerR = 0x0020,
|
||||
TriggerL = 0x0040,
|
||||
ButtonA = 0x0100,
|
||||
ButtonB = 0x0200,
|
||||
ButtonX = 0x0400,
|
||||
ButtonY = 0x0800,
|
||||
ButtonStart = 0x1000,
|
||||
// Below is for compatibility with "AxisButton" type
|
||||
PAD_STICK = 0x2000,
|
||||
Stick = 0x2000,
|
||||
};
|
||||
|
||||
extern const std::array<PadButton, 12> PadButtonArray;
|
||||
|
||||
enum class PadAxes : u8 {
|
||||
StickX,
|
||||
StickY,
|
||||
@@ -47,87 +46,122 @@ enum class PadAxes : u8 {
|
||||
Undefined,
|
||||
};
|
||||
|
||||
enum class ControllerTypes {
|
||||
None,
|
||||
Wired,
|
||||
Wireless,
|
||||
};
|
||||
|
||||
struct GCPadStatus {
|
||||
u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
|
||||
std::size_t port{};
|
||||
|
||||
std::array<u8, 6> axis_values{}; // Triggers and sticks, following indices defined in PadAxes
|
||||
static constexpr u8 THRESHOLD = 50; // Threshold for axis press for polling
|
||||
PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
|
||||
|
||||
u8 port{};
|
||||
PadAxes axis{PadAxes::Undefined};
|
||||
u8 axis_value{255};
|
||||
s16 axis_value{};
|
||||
u8 axis_threshold{50};
|
||||
};
|
||||
|
||||
struct GCState {
|
||||
std::unordered_map<int, bool> buttons;
|
||||
std::unordered_map<u32, u16> axes;
|
||||
struct GCController {
|
||||
ControllerTypes type{};
|
||||
bool enable_vibration{};
|
||||
u8 rumble_amplitude{};
|
||||
u16 buttons{};
|
||||
PadButton last_button{};
|
||||
std::array<s16, 6> axis_values{};
|
||||
std::array<u8, 6> axis_origin{};
|
||||
};
|
||||
|
||||
enum class ControllerTypes { None, Wired, Wireless };
|
||||
|
||||
class Adapter {
|
||||
public:
|
||||
/// Initialize the GC Adapter capture and read sequence
|
||||
Adapter();
|
||||
|
||||
/// Close the adapter read thread and release the adapter
|
||||
~Adapter();
|
||||
|
||||
/// Request a vibration for a controlelr
|
||||
bool RumblePlay(std::size_t port, f32 amplitude);
|
||||
|
||||
/// Used for polling
|
||||
void BeginConfiguration();
|
||||
void EndConfiguration();
|
||||
|
||||
std::vector<Common::ParamPackage> GetInputDevices() const;
|
||||
InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
|
||||
InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
|
||||
Common::SPSCQueue<GCPadStatus>& GetPadQueue();
|
||||
const Common::SPSCQueue<GCPadStatus>& GetPadQueue() const;
|
||||
|
||||
GCController& GetPadState(std::size_t port);
|
||||
const GCController& GetPadState(std::size_t port) const;
|
||||
|
||||
/// Returns true if there is a device connected to port
|
||||
bool DeviceConnected(std::size_t port) const;
|
||||
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
|
||||
const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
|
||||
|
||||
std::array<GCState, 4>& GetPadState();
|
||||
const std::array<GCState, 4>& GetPadState() const;
|
||||
|
||||
int GetOriginValue(u32 port, u32 axis) const;
|
||||
/// Used for automapping features
|
||||
std::vector<Common::ParamPackage> GetInputDevices() const;
|
||||
InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
|
||||
InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
|
||||
|
||||
private:
|
||||
GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
|
||||
using AdapterPayload = std::array<u8, 37>;
|
||||
|
||||
void Read();
|
||||
void UpdatePadType(std::size_t port, ControllerTypes pad_type);
|
||||
void UpdateControllers(const AdapterPayload& adapter_payload);
|
||||
void UpdateYuzuSettings(std::size_t port);
|
||||
void UpdateStateButtons(std::size_t port, u8 b1, u8 b2);
|
||||
void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload);
|
||||
void UpdateVibrations();
|
||||
|
||||
/// Resets status of device connected to port
|
||||
void ResetDeviceType(std::size_t port);
|
||||
void AdapterInputThread();
|
||||
|
||||
/// Returns true if we successfully gain access to GC Adapter
|
||||
bool CheckDeviceAccess(libusb_device* device);
|
||||
void AdapterScanThread();
|
||||
|
||||
/// Captures GC Adapter endpoint address,
|
||||
void GetGCEndpoint(libusb_device* device);
|
||||
bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size);
|
||||
|
||||
/// For shutting down, clear all data, join all threads, release usb
|
||||
void Reset();
|
||||
// Updates vibration state of all controllers
|
||||
void SendVibrations();
|
||||
|
||||
/// For use in initialization, querying devices to find the adapter
|
||||
void Setup();
|
||||
|
||||
/// Resets status of all GC controller devices to a disconected state
|
||||
void ResetDevices();
|
||||
|
||||
/// Resets status of device connected to a disconected state
|
||||
void ResetDevice(std::size_t port);
|
||||
|
||||
/// Returns true if we successfully gain access to GC Adapter
|
||||
bool CheckDeviceAccess();
|
||||
|
||||
/// Captures GC Adapter endpoint address
|
||||
/// Returns true if the endpoind was set correctly
|
||||
bool GetGCEndpoint(libusb_device* device);
|
||||
|
||||
/// For shutting down, clear all data, join all threads, release usb
|
||||
void Reset();
|
||||
|
||||
// Join all threads
|
||||
void JoinThreads();
|
||||
|
||||
// Release usb handles
|
||||
void ClearLibusbHandle();
|
||||
|
||||
libusb_device_handle* usb_adapter_handle = nullptr;
|
||||
std::array<GCController, 4> pads;
|
||||
Common::SPSCQueue<GCPadStatus> pad_queue;
|
||||
|
||||
std::thread adapter_input_thread;
|
||||
bool adapter_thread_running;
|
||||
std::thread adapter_scan_thread;
|
||||
bool adapter_input_thread_running;
|
||||
bool adapter_scan_thread_running;
|
||||
bool restart_scan_thread;
|
||||
|
||||
libusb_context* libusb_ctx;
|
||||
|
||||
u8 input_endpoint = 0;
|
||||
u8 output_endpoint = 0;
|
||||
u8 input_endpoint{0};
|
||||
u8 output_endpoint{0};
|
||||
u8 input_error_counter{0};
|
||||
u8 output_error_counter{0};
|
||||
int vibration_counter{0};
|
||||
|
||||
bool configuring = false;
|
||||
|
||||
std::array<GCState, 4> state;
|
||||
std::array<bool, 4> get_origin;
|
||||
std::array<GCPadStatus, 4> origin_status;
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
|
||||
std::array<ControllerTypes, 4> adapter_controllers_status{};
|
||||
bool configuring{false};
|
||||
bool rumble_enabled{true};
|
||||
bool vibration_changed{true};
|
||||
};
|
||||
|
||||
} // namespace GCAdapter
|
||||
|
||||
@@ -15,22 +15,30 @@ namespace InputCommon {
|
||||
|
||||
class GCButton final : public Input::ButtonDevice {
|
||||
public:
|
||||
explicit GCButton(u32 port_, int button_, const GCAdapter::Adapter* adapter)
|
||||
explicit GCButton(u32 port_, s32 button_, GCAdapter::Adapter* adapter)
|
||||
: port(port_), button(button_), gcadapter(adapter) {}
|
||||
|
||||
~GCButton() override;
|
||||
|
||||
bool GetStatus() const override {
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
return gcadapter->GetPadState()[port].buttons.at(button);
|
||||
return (gcadapter->GetPadState(port).buttons & button) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
|
||||
const float amplitude = amp_high + amp_low > 2.0f ? 1.0f : (amp_high + amp_low) * 0.5f;
|
||||
const auto new_amp =
|
||||
static_cast<f32>(pow(amplitude, 0.5f) * (3.0f - 2.0f * pow(amplitude, 0.15f)));
|
||||
|
||||
return gcadapter->RumblePlay(port, new_amp);
|
||||
}
|
||||
|
||||
private:
|
||||
const u32 port;
|
||||
const int button;
|
||||
const GCAdapter::Adapter* gcadapter;
|
||||
const s32 button;
|
||||
GCAdapter::Adapter* gcadapter;
|
||||
};
|
||||
|
||||
class GCAxisButton final : public Input::ButtonDevice {
|
||||
@@ -38,13 +46,12 @@ public:
|
||||
explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_,
|
||||
const GCAdapter::Adapter* adapter)
|
||||
: port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
|
||||
gcadapter(adapter),
|
||||
origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {}
|
||||
gcadapter(adapter) {}
|
||||
|
||||
bool GetStatus() const override {
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
|
||||
const float axis_value = (current_axis_value - origin_value) / 128.0f;
|
||||
const float current_axis_value = gcadapter->GetPadState(port).axis_values.at(axis);
|
||||
const float axis_value = current_axis_value / 128.0f;
|
||||
if (trigger_if_greater) {
|
||||
// TODO: Might be worthwile to set a slider for the trigger threshold. It is
|
||||
// currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
|
||||
@@ -61,7 +68,6 @@ private:
|
||||
float threshold;
|
||||
bool trigger_if_greater;
|
||||
const GCAdapter::Adapter* gcadapter;
|
||||
const float origin_value;
|
||||
};
|
||||
|
||||
GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
|
||||
@@ -73,7 +79,7 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
|
||||
const auto button_id = params.Get("button", 0);
|
||||
const auto port = static_cast<u32>(params.Get("port", 0));
|
||||
|
||||
constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK);
|
||||
constexpr s32 PAD_STICK_ID = static_cast<s32>(GCAdapter::PadButton::Stick);
|
||||
|
||||
// button is not an axis/stick button
|
||||
if (button_id != PAD_STICK_ID) {
|
||||
@@ -106,32 +112,25 @@ Common::ParamPackage GCButtonFactory::GetNextInput() const {
|
||||
Common::ParamPackage params;
|
||||
GCAdapter::GCPadStatus pad;
|
||||
auto& queue = adapter->GetPadQueue();
|
||||
for (std::size_t port = 0; port < queue.size(); ++port) {
|
||||
while (queue[port].Pop(pad)) {
|
||||
// This while loop will break on the earliest detected button
|
||||
params.Set("engine", "gcpad");
|
||||
params.Set("port", static_cast<int>(port));
|
||||
for (const auto& button : GCAdapter::PadButtonArray) {
|
||||
const u16 button_value = static_cast<u16>(button);
|
||||
if (pad.button & button_value) {
|
||||
params.Set("button", button_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (queue.Pop(pad)) {
|
||||
// This while loop will break on the earliest detected button
|
||||
params.Set("engine", "gcpad");
|
||||
params.Set("port", static_cast<s32>(pad.port));
|
||||
if (pad.button != GCAdapter::PadButton::Undefined) {
|
||||
params.Set("button", static_cast<u16>(pad.button));
|
||||
}
|
||||
|
||||
// For Axis button implementation
|
||||
if (pad.axis != GCAdapter::PadAxes::Undefined) {
|
||||
params.Set("axis", static_cast<u8>(pad.axis));
|
||||
params.Set("button", static_cast<u16>(GCAdapter::PadButton::PAD_STICK));
|
||||
if (pad.axis_value > 128) {
|
||||
params.Set("direction", "+");
|
||||
params.Set("threshold", "0.25");
|
||||
} else {
|
||||
params.Set("direction", "-");
|
||||
params.Set("threshold", "-0.25");
|
||||
}
|
||||
break;
|
||||
// For Axis button implementation
|
||||
if (pad.axis != GCAdapter::PadAxes::Undefined) {
|
||||
params.Set("axis", static_cast<u8>(pad.axis));
|
||||
params.Set("button", static_cast<u16>(GCAdapter::PadButton::Stick));
|
||||
params.Set("threshold", "0.25");
|
||||
if (pad.axis_value > 0) {
|
||||
params.Set("direction", "+");
|
||||
} else {
|
||||
params.Set("direction", "-");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
@@ -152,17 +151,14 @@ public:
|
||||
explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_,
|
||||
const GCAdapter::Adapter* adapter, float range_)
|
||||
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
|
||||
origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))),
|
||||
origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))),
|
||||
range(range_) {}
|
||||
|
||||
float GetAxis(u32 axis) const {
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
std::lock_guard lock{mutex};
|
||||
const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
|
||||
const auto axis_value =
|
||||
static_cast<float>(gcadapter->GetPadState()[port].axes.at(axis));
|
||||
return (axis_value - origin_value) / (100.0f * range);
|
||||
static_cast<float>(gcadapter->GetPadState(port).axis_values.at(axis));
|
||||
return (axis_value) / (100.0f * range);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -215,8 +211,6 @@ private:
|
||||
const u32 axis_y;
|
||||
const float deadzone;
|
||||
const GCAdapter::Adapter* gcadapter;
|
||||
const float origin_value_x;
|
||||
const float origin_value_y;
|
||||
const float range;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
@@ -254,26 +248,44 @@ void GCAnalogFactory::EndConfiguration() {
|
||||
|
||||
Common::ParamPackage GCAnalogFactory::GetNextInput() {
|
||||
GCAdapter::GCPadStatus pad;
|
||||
Common::ParamPackage params;
|
||||
auto& queue = adapter->GetPadQueue();
|
||||
for (std::size_t port = 0; port < queue.size(); ++port) {
|
||||
while (queue[port].Pop(pad)) {
|
||||
if (pad.axis == GCAdapter::PadAxes::Undefined ||
|
||||
std::abs((static_cast<float>(pad.axis_value) - 128.0f) / 128.0f) < 0.1f) {
|
||||
continue;
|
||||
}
|
||||
// An analog device needs two axes, so we need to store the axis for later and wait for
|
||||
// a second input event. The axes also must be from the same joystick.
|
||||
const u8 axis = static_cast<u8>(pad.axis);
|
||||
if (analog_x_axis == -1) {
|
||||
analog_x_axis = axis;
|
||||
controller_number = static_cast<int>(port);
|
||||
} else if (analog_y_axis == -1 && analog_x_axis != axis &&
|
||||
controller_number == static_cast<int>(port)) {
|
||||
analog_y_axis = axis;
|
||||
}
|
||||
while (queue.Pop(pad)) {
|
||||
if (pad.button != GCAdapter::PadButton::Undefined) {
|
||||
params.Set("engine", "gcpad");
|
||||
params.Set("port", static_cast<s32>(pad.port));
|
||||
params.Set("button", static_cast<u16>(pad.button));
|
||||
return params;
|
||||
}
|
||||
if (pad.axis == GCAdapter::PadAxes::Undefined ||
|
||||
std::abs(static_cast<float>(pad.axis_value) / 128.0f) < 0.1f) {
|
||||
continue;
|
||||
}
|
||||
// An analog device needs two axes, so we need to store the axis for later and wait for
|
||||
// a second input event. The axes also must be from the same joystick.
|
||||
const u8 axis = static_cast<u8>(pad.axis);
|
||||
if (axis == 0 || axis == 1) {
|
||||
analog_x_axis = 0;
|
||||
analog_y_axis = 1;
|
||||
controller_number = static_cast<s32>(pad.port);
|
||||
break;
|
||||
}
|
||||
if (axis == 2 || axis == 3) {
|
||||
analog_x_axis = 2;
|
||||
analog_y_axis = 3;
|
||||
controller_number = static_cast<s32>(pad.port);
|
||||
break;
|
||||
}
|
||||
|
||||
if (analog_x_axis == -1) {
|
||||
analog_x_axis = axis;
|
||||
controller_number = static_cast<s32>(pad.port);
|
||||
} else if (analog_y_axis == -1 && analog_x_axis != axis &&
|
||||
controller_number == static_cast<s32>(pad.port)) {
|
||||
analog_y_axis = axis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Common::ParamPackage params;
|
||||
if (analog_x_axis != -1 && analog_y_axis != -1) {
|
||||
params.Set("engine", "gcpad");
|
||||
params.Set("port", controller_number);
|
||||
|
||||
@@ -144,7 +144,7 @@ void CDmaPusher::ExecuteCommand(u32 offset, u32 data) {
|
||||
}
|
||||
case ThiMethod::SetMethod1:
|
||||
LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})",
|
||||
static_cast<u32>(vic_thi_state.method_0));
|
||||
static_cast<u32>(vic_thi_state.method_0), data);
|
||||
vic_processor->ProcessMethod(static_cast<Tegra::Vic::Method>(vic_thi_state.method_0),
|
||||
{data});
|
||||
break;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "common/assert.h"
|
||||
#include "video_core/command_classes/codecs/codec.h"
|
||||
#include "video_core/command_classes/codecs/h264.h"
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/command_classes/nvdec_common.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,27 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_util.h"
|
||||
#include "video_core/command_classes/codecs/h264.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra::Decoder {
|
||||
namespace {
|
||||
// ZigZag LUTs from libavcodec.
|
||||
constexpr std::array<u8, 64> zig_zag_direct{
|
||||
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48,
|
||||
41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23,
|
||||
30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
|
||||
};
|
||||
|
||||
constexpr std::array<u8, 16> zig_zag_scan{
|
||||
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
|
||||
1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
H264::H264(GPU& gpu_) : gpu(gpu_) {}
|
||||
|
||||
H264::~H264() = default;
|
||||
@@ -48,7 +63,8 @@ std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, bo
|
||||
writer.WriteU(0, 8);
|
||||
writer.WriteU(31, 8);
|
||||
writer.WriteUe(0);
|
||||
const s32 chroma_format_idc = (context.h264_parameter_set.flags >> 12) & 0x3;
|
||||
const auto chroma_format_idc =
|
||||
static_cast<u32>((context.h264_parameter_set.flags >> 12) & 3);
|
||||
writer.WriteUe(chroma_format_idc);
|
||||
if (chroma_format_idc == 3) {
|
||||
writer.WriteBit(false);
|
||||
@@ -59,8 +75,8 @@ std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, bo
|
||||
writer.WriteBit(false); // QpprimeYZeroTransformBypassFlag
|
||||
writer.WriteBit(false); // Scaling matrix present flag
|
||||
|
||||
const s32 order_cnt_type = static_cast<s32>((context.h264_parameter_set.flags >> 14) & 3);
|
||||
writer.WriteUe(static_cast<s32>((context.h264_parameter_set.flags >> 8) & 0xf));
|
||||
const auto order_cnt_type = static_cast<u32>((context.h264_parameter_set.flags >> 14) & 3);
|
||||
writer.WriteUe(static_cast<u32>((context.h264_parameter_set.flags >> 8) & 0xf));
|
||||
writer.WriteUe(order_cnt_type);
|
||||
if (order_cnt_type == 0) {
|
||||
writer.WriteUe(context.h264_parameter_set.log2_max_pic_order_cnt);
|
||||
@@ -100,7 +116,7 @@ std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, bo
|
||||
writer.WriteUe(0);
|
||||
writer.WriteUe(0);
|
||||
|
||||
writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag);
|
||||
writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0);
|
||||
writer.WriteBit(false);
|
||||
writer.WriteUe(0);
|
||||
writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active);
|
||||
@@ -172,8 +188,8 @@ void H264BitWriter::WriteSe(s32 value) {
|
||||
WriteExpGolombCodedInt(value);
|
||||
}
|
||||
|
||||
void H264BitWriter::WriteUe(s32 value) {
|
||||
WriteExpGolombCodedUInt((u32)value);
|
||||
void H264BitWriter::WriteUe(u32 value) {
|
||||
WriteExpGolombCodedUInt(value);
|
||||
}
|
||||
|
||||
void H264BitWriter::End() {
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
/// WriteSe and WriteUe write in the Exp-Golomb-coded syntax
|
||||
void WriteU(s32 value, s32 value_sz);
|
||||
void WriteSe(s32 value);
|
||||
void WriteUe(s32 value);
|
||||
void WriteUe(u32 value);
|
||||
|
||||
/// Finalize the bitstream
|
||||
void End();
|
||||
@@ -55,18 +55,6 @@ public:
|
||||
const std::vector<u8>& GetByteArray() const;
|
||||
|
||||
private:
|
||||
// ZigZag LUTs from libavcodec.
|
||||
static constexpr std::array<u8, 64> zig_zag_direct{
|
||||
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48,
|
||||
41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23,
|
||||
30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
|
||||
};
|
||||
|
||||
static constexpr std::array<u8, 16> zig_zag_scan{
|
||||
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
|
||||
1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
|
||||
};
|
||||
|
||||
void WriteBits(s32 value, s32 bit_count);
|
||||
void WriteExpGolombCodedInt(s32 value);
|
||||
void WriteExpGolombCodedUInt(u32 value);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra::Decoder {
|
||||
|
||||
namespace {
|
||||
// Default compressed header probabilities once frame context resets
|
||||
constexpr Vp9EntropyProbs default_probs{
|
||||
.y_mode_prob{
|
||||
@@ -170,6 +170,35 @@ constexpr Vp9EntropyProbs default_probs{
|
||||
.high_precision{128, 128},
|
||||
};
|
||||
|
||||
constexpr std::array<s32, 256> norm_lut{
|
||||
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
constexpr std::array<s32, 254> map_lut{
|
||||
20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
|
||||
1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
|
||||
73, 4, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 5, 86, 87, 88, 89,
|
||||
90, 91, 92, 93, 94, 95, 96, 97, 6, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 109, 7, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 8, 122, 123, 124,
|
||||
125, 126, 127, 128, 129, 130, 131, 132, 133, 9, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
||||
143, 144, 145, 10, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 11, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 12, 170, 171, 172, 173, 174, 175, 176, 177,
|
||||
178, 179, 180, 181, 13, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 14, 194,
|
||||
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 15, 206, 207, 208, 209, 210, 211, 212,
|
||||
213, 214, 215, 216, 217, 16, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 17,
|
||||
230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 18, 242, 243, 244, 245, 246, 247,
|
||||
248, 249, 250, 251, 252, 253, 19,
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
VP9::VP9(GPU& gpu) : gpu(gpu) {}
|
||||
|
||||
VP9::~VP9() = default;
|
||||
@@ -379,14 +408,14 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
|
||||
Vp9FrameContainer frame{};
|
||||
{
|
||||
gpu.SyncGuestHost();
|
||||
frame.info = std::move(GetVp9PictureInfo(state));
|
||||
frame.info = GetVp9PictureInfo(state);
|
||||
|
||||
frame.bit_stream.resize(frame.info.bitstream_size);
|
||||
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.bit_stream.data(),
|
||||
frame.info.bitstream_size);
|
||||
}
|
||||
// Buffer two frames, saving the last show frame info
|
||||
if (next_next_frame.bit_stream.size() != 0) {
|
||||
if (!next_next_frame.bit_stream.empty()) {
|
||||
Vp9FrameContainer temp{
|
||||
.info = frame.info,
|
||||
.bit_stream = frame.bit_stream,
|
||||
@@ -396,15 +425,15 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
|
||||
frame.bit_stream = next_next_frame.bit_stream;
|
||||
next_next_frame = std::move(temp);
|
||||
|
||||
if (next_frame.bit_stream.size() != 0) {
|
||||
Vp9FrameContainer temp{
|
||||
if (!next_frame.bit_stream.empty()) {
|
||||
Vp9FrameContainer temp2{
|
||||
.info = frame.info,
|
||||
.bit_stream = frame.bit_stream,
|
||||
};
|
||||
next_frame.info.show_frame = frame.info.last_frame_shown;
|
||||
frame.info = next_frame.info;
|
||||
frame.bit_stream = next_frame.bit_stream;
|
||||
next_frame = std::move(temp);
|
||||
next_frame = std::move(temp2);
|
||||
} else {
|
||||
next_frame.info = frame.info;
|
||||
next_frame.bit_stream = frame.bit_stream;
|
||||
@@ -605,12 +634,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
|
||||
|
||||
writer.End();
|
||||
return writer.GetBuffer();
|
||||
|
||||
const auto writer_bytearray = writer.GetBuffer();
|
||||
|
||||
std::vector<u8> compressed_header(writer_bytearray.size());
|
||||
std::memcpy(compressed_header.data(), writer_bytearray.data(), writer_bytearray.size());
|
||||
return compressed_header;
|
||||
}
|
||||
|
||||
VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
@@ -648,7 +671,6 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
current_frame_info.intra_only = true;
|
||||
|
||||
} else {
|
||||
std::array<s32, 3> ref_frame_index;
|
||||
|
||||
if (!current_frame_info.show_frame) {
|
||||
uncomp_writer.WriteBit(current_frame_info.intra_only);
|
||||
@@ -663,9 +685,9 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
}
|
||||
|
||||
// Last, Golden, Altref frames
|
||||
ref_frame_index = std::array<s32, 3>{0, 1, 2};
|
||||
std::array<s32, 3> ref_frame_index{0, 1, 2};
|
||||
|
||||
// set when next frame is hidden
|
||||
// Set when next frame is hidden
|
||||
// altref and golden references are swapped
|
||||
if (swap_next_golden) {
|
||||
ref_frame_index = std::array<s32, 3>{0, 2, 1};
|
||||
@@ -754,17 +776,19 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
for (std::size_t index = 0; index < current_frame_info.ref_deltas.size(); index++) {
|
||||
const s8 old_deltas = loop_filter_ref_deltas[index];
|
||||
const s8 new_deltas = current_frame_info.ref_deltas[index];
|
||||
const bool differing_delta = old_deltas != new_deltas;
|
||||
|
||||
loop_filter_delta_update |=
|
||||
(update_loop_filter_ref_deltas[index] = old_deltas != new_deltas);
|
||||
update_loop_filter_ref_deltas[index] = differing_delta;
|
||||
loop_filter_delta_update |= differing_delta;
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < current_frame_info.mode_deltas.size(); index++) {
|
||||
const s8 old_deltas = loop_filter_mode_deltas[index];
|
||||
const s8 new_deltas = current_frame_info.mode_deltas[index];
|
||||
const bool differing_delta = old_deltas != new_deltas;
|
||||
|
||||
loop_filter_delta_update |=
|
||||
(update_loop_filter_mode_deltas[index] = old_deltas != new_deltas);
|
||||
update_loop_filter_mode_deltas[index] = differing_delta;
|
||||
loop_filter_delta_update |= differing_delta;
|
||||
}
|
||||
|
||||
uncomp_writer.WriteBit(loop_filter_delta_update);
|
||||
@@ -829,7 +853,7 @@ std::vector<u8>& VP9::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state) {
|
||||
{
|
||||
Vp9FrameContainer curr_frame = GetCurrentFrame(state);
|
||||
current_frame_info = curr_frame.info;
|
||||
bitstream = curr_frame.bit_stream;
|
||||
bitstream = std::move(curr_frame.bit_stream);
|
||||
}
|
||||
|
||||
// The uncompressed header routine sets PrevProb parameters needed for the compressed header
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/stream.h"
|
||||
#include "video_core/command_classes/codecs/vp9_types.h"
|
||||
@@ -52,17 +52,6 @@ private:
|
||||
u32 range{0xff};
|
||||
s32 count{-24};
|
||||
s32 half_probability{128};
|
||||
static constexpr std::array<s32, 256> norm_lut{
|
||||
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
};
|
||||
|
||||
class VpxBitStreamWriter {
|
||||
@@ -193,23 +182,6 @@ private:
|
||||
|
||||
s32 diff_update_probability = 252;
|
||||
s32 frame_sync_code = 0x498342;
|
||||
static constexpr std::array<s32, 254> map_lut = {
|
||||
20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50,
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66,
|
||||
67, 68, 69, 70, 71, 72, 73, 4, 74, 75, 76, 77, 78, 79, 80, 81, 82,
|
||||
83, 84, 85, 5, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 6,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 7, 110, 111, 112, 113,
|
||||
114, 115, 116, 117, 118, 119, 120, 121, 8, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131, 132, 133, 9, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
|
||||
10, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 11, 158, 159, 160,
|
||||
161, 162, 163, 164, 165, 166, 167, 168, 169, 12, 170, 171, 172, 173, 174, 175, 176,
|
||||
177, 178, 179, 180, 181, 13, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
|
||||
193, 14, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 15, 206, 207,
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 16, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 17, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 18, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 19,
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace Decoder
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "common/cityhash.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/command_classes/nvdec_common.h"
|
||||
|
||||
namespace Tegra {
|
||||
class GPU;
|
||||
|
||||
@@ -15,7 +15,7 @@ void Tegra::Host1x::StateWrite(u32 offset, u32 arguments) {
|
||||
std::memcpy(state_offset, &arguments, sizeof(u32));
|
||||
}
|
||||
|
||||
void Tegra::Host1x::ProcessMethod(Host1x::Method method, const std::vector<u32>& arguments) {
|
||||
void Tegra::Host1x::ProcessMethod(Method method, const std::vector<u32>& arguments) {
|
||||
StateWrite(static_cast<u32>(method), arguments[0]);
|
||||
switch (method) {
|
||||
case Method::WaitSyncpt:
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
~Host1x();
|
||||
|
||||
/// Writes the method into the state, Invoke Execute() if encountered
|
||||
void ProcessMethod(Host1x::Method method, const std::vector<u32>& arguments);
|
||||
void ProcessMethod(Method method, const std::vector<u32>& arguments);
|
||||
|
||||
private:
|
||||
/// For Host1x, execute is waiting on a syncpoint previously written into the state
|
||||
|
||||
@@ -2,13 +2,9 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <bitset>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/command_classes/nvdec.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
@@ -16,7 +12,7 @@ Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique<Codec>(gpu)) {}
|
||||
|
||||
Nvdec::~Nvdec() = default;
|
||||
|
||||
void Nvdec::ProcessMethod(Nvdec::Method method, const std::vector<u32>& arguments) {
|
||||
void Nvdec::ProcessMethod(Method method, const std::vector<u32>& arguments) {
|
||||
if (method == Method::SetVideoCodec) {
|
||||
codec->StateWrite(static_cast<u32>(method), arguments[0]);
|
||||
} else {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/command_classes/codecs/codec.h"
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
~Nvdec();
|
||||
|
||||
/// Writes the method into the state, Invoke Execute() if encountered
|
||||
void ProcessMethod(Nvdec::Method method, const std::vector<u32>& arguments);
|
||||
void ProcessMethod(Method method, const std::vector<u32>& arguments);
|
||||
|
||||
/// Return most recently decoded frame
|
||||
AVFrame* GetFrame();
|
||||
@@ -34,6 +34,6 @@ private:
|
||||
void Execute();
|
||||
|
||||
GPU& gpu;
|
||||
std::unique_ptr<Tegra::Codec> codec;
|
||||
std::unique_ptr<Codec> codec;
|
||||
};
|
||||
} // namespace Tegra
|
||||
|
||||
@@ -27,22 +27,22 @@ SyncptIncrManager::SyncptIncrManager(GPU& gpu_) : gpu(gpu_) {}
|
||||
SyncptIncrManager::~SyncptIncrManager() = default;
|
||||
|
||||
void SyncptIncrManager::Increment(u32 id) {
|
||||
increments.push_back(SyncptIncr{0, id, true});
|
||||
increments.emplace_back(0, 0, id, true);
|
||||
IncrementAllDone();
|
||||
}
|
||||
|
||||
u32 SyncptIncrManager::IncrementWhenDone(u32 class_id, u32 id) {
|
||||
const u32 handle = current_id++;
|
||||
increments.push_back(SyncptIncr{handle, class_id, id});
|
||||
increments.emplace_back(handle, class_id, id);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SyncptIncrManager::SignalDone(u32 handle) {
|
||||
auto done_incr = std::find_if(increments.begin(), increments.end(),
|
||||
[handle](SyncptIncr incr) { return incr.id == handle; });
|
||||
if (done_incr != increments.end()) {
|
||||
const SyncptIncr incr = *done_incr;
|
||||
*done_incr = SyncptIncr{incr.id, incr.class_id, incr.syncpt_id, true};
|
||||
const auto done_incr =
|
||||
std::find_if(increments.begin(), increments.end(),
|
||||
[handle](const SyncptIncr& incr) { return incr.id == handle; });
|
||||
if (done_incr != increments.cend()) {
|
||||
done_incr->complete = true;
|
||||
}
|
||||
IncrementAllDone();
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ struct SyncptIncr {
|
||||
u32 syncpt_id;
|
||||
bool complete;
|
||||
|
||||
SyncptIncr(u32 id, u32 syncpt_id_, u32 class_id_, bool done = false)
|
||||
: id(id), class_id(class_id_), syncpt_id(syncpt_id_), complete(done) {}
|
||||
SyncptIncr(u32 id_, u32 class_id_, u32 syncpt_id_, bool done = false)
|
||||
: id(id_), class_id(class_id_), syncpt_id(syncpt_id_), complete(done) {}
|
||||
};
|
||||
|
||||
class SyncptIncrManager {
|
||||
|
||||
@@ -26,7 +26,7 @@ void Vic::VicStateWrite(u32 offset, u32 arguments) {
|
||||
std::memcpy(state_offset, &arguments, sizeof(u32));
|
||||
}
|
||||
|
||||
void Vic::ProcessMethod(Vic::Method method, const std::vector<u32>& arguments) {
|
||||
void Vic::ProcessMethod(Method method, const std::vector<u32>& arguments) {
|
||||
LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", static_cast<u32>(method));
|
||||
VicStateWrite(static_cast<u32>(method), arguments[0]);
|
||||
const u64 arg = static_cast<u64>(arguments[0]) << 8;
|
||||
|
||||
@@ -63,11 +63,11 @@ public:
|
||||
SetOutputSurfaceChromaVOffset = 0x1ca
|
||||
};
|
||||
|
||||
explicit Vic(GPU& gpu, std::shared_ptr<Tegra::Nvdec> nvdec_processor);
|
||||
explicit Vic(GPU& gpu, std::shared_ptr<Nvdec> nvdec_processor);
|
||||
~Vic();
|
||||
|
||||
/// Write to the device state.
|
||||
void ProcessMethod(Vic::Method method, const std::vector<u32>& arguments);
|
||||
void ProcessMethod(Method method, const std::vector<u32>& arguments);
|
||||
|
||||
private:
|
||||
void Execute();
|
||||
|
||||
@@ -65,6 +65,12 @@ struct Client::Impl {
|
||||
if (cli == nullptr) {
|
||||
cli = std::make_unique<httplib::Client>(host.c_str());
|
||||
}
|
||||
|
||||
if (!cli->is_valid()) {
|
||||
LOG_ERROR(WebService, "Client is invalid, skipping request!");
|
||||
return {};
|
||||
}
|
||||
|
||||
cli->set_connection_timeout(TIMEOUT_SECONDS);
|
||||
cli->set_read_timeout(TIMEOUT_SECONDS);
|
||||
cli->set_write_timeout(TIMEOUT_SECONDS);
|
||||
|
||||
Reference in New Issue
Block a user