mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-09-28 23:11:20 +00:00
Merge branch 'master' into nn/auto-indicator
This commit is contained in:
commit
7f4ba5afe4
@ -15,8 +15,8 @@ arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetyp
|
||||
arch -x86_64 /usr/local/bin/brew install llvm@16 glew cmake sdl2 vulkan-headers coreutils
|
||||
arch -x86_64 /usr/local/bin/brew link -f llvm@16 ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.2.7 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/05a8770c483cfddf5b077667a392d846bc2ad719/Formula/m/molten-vk.rb
|
||||
# moltenvk based on commit for 1.2.9 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/c117dde3198d62817371984d04d50e653ca88f7d/Formula/m/molten-vk.rb
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
|
||||
#export MACOSX_DEPLOYMENT_TARGET=12.0
|
||||
export CXX=clang++
|
||||
|
2
3rdparty/7zip/7zip
vendored
2
3rdparty/7zip/7zip
vendored
@ -1 +1 @@
|
||||
Subproject commit 89a73b901229c8550c172c9556ff8442ae7ac4b8
|
||||
Subproject commit a7a1d4a241492e81f659a920f7379c193593ebc6
|
2
3rdparty/MoltenVK/CMakeLists.txt
vendored
2
3rdparty/MoltenVK/CMakeLists.txt
vendored
@ -4,7 +4,7 @@ include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(moltenvk
|
||||
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
||||
GIT_TAG 66f6ff1
|
||||
GIT_TAG bf097ed
|
||||
BUILD_IN_SOURCE 1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
|
||||
|
2
3rdparty/libsdl-org/SDL
vendored
2
3rdparty/libsdl-org/SDL
vendored
@ -1 +1 @@
|
||||
Subproject commit fb1497566c5a05e2babdcf45ef0ab5c7cca2c4ae
|
||||
Subproject commit 92fe3b19c868ad062c323dde2cfc9d8b4bfdd785
|
@ -1679,9 +1679,9 @@ void camera_context::operator()()
|
||||
data3 = 0; // unused
|
||||
}
|
||||
|
||||
if (queue->send(evt_data.source, CELL_CAMERA_FRAME_UPDATE, data2, data3) != 0) [[unlikely]]
|
||||
if (CellError err = queue->send(evt_data.source, CELL_CAMERA_FRAME_UPDATE, data2, data3)) [[unlikely]]
|
||||
{
|
||||
cellCamera.warning("Failed to send frame update event");
|
||||
cellCamera.warning("Failed to send frame update event (error=0x%x)", err);
|
||||
}
|
||||
|
||||
frame_update_event_sent = true;
|
||||
@ -1819,9 +1819,9 @@ void camera_context::send_attach_state(bool attached)
|
||||
{
|
||||
if (auto queue = lv2_event_queue::find(key))
|
||||
{
|
||||
if (queue->send(evt_data.source, attached ? CELL_CAMERA_ATTACH : CELL_CAMERA_DETACH, 0, 0) != 0) [[unlikely]]
|
||||
if (CellError err = queue->send(evt_data.source, attached ? CELL_CAMERA_ATTACH : CELL_CAMERA_DETACH, 0, 0)) [[unlikely]]
|
||||
{
|
||||
cellCamera.warning("Failed to send attach event (attached=%d)", attached);
|
||||
cellCamera.warning("Failed to send attach event (attached=%d, error=0x%x)", attached, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1759,7 +1759,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
|
||||
|
||||
error_code cellGemGetStatusFlags(u32 gem_num, vm::ptr<u64> flags)
|
||||
{
|
||||
cellGem.todo("cellGemGetStatusFlags(gem_num=%d, flags=*0x%x)", gem_num, flags);
|
||||
cellGem.trace("cellGemGetStatusFlags(gem_num=%d, flags=*0x%x)", gem_num, flags);
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
||||
@ -2094,7 +2094,7 @@ error_code cellGemReset(u32 gem_num)
|
||||
|
||||
error_code cellGemSetRumble(u32 gem_num, u8 rumble)
|
||||
{
|
||||
cellGem.warning("cellGemSetRumble(gem_num=%d, rumble=0x%x)", gem_num, rumble);
|
||||
cellGem.trace("cellGemSetRumble(gem_num=%d, rumble=0x%x)", gem_num, rumble);
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
||||
|
@ -11,7 +11,7 @@ error_code sys_config_stop(ppu_thread& ppu);
|
||||
|
||||
extern bool is_input_allowed();
|
||||
|
||||
LOG_CHANNEL(sys_io);
|
||||
LOG_CHANNEL(cellKb);
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellKbError>::format(std::string& out, u64 arg)
|
||||
@ -77,7 +77,7 @@ void KeyboardHandlerBase::save(utils::serial& ar)
|
||||
|
||||
error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
|
||||
{
|
||||
sys_io.warning("cellKbInit(max_connect=%d)", max_connect);
|
||||
cellKb.warning("cellKbInit(max_connect=%d)", max_connect);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -102,7 +102,7 @@ error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
|
||||
|
||||
error_code cellKbEnd(ppu_thread& ppu)
|
||||
{
|
||||
sys_io.notice("cellKbEnd()");
|
||||
cellKb.notice("cellKbEnd()");
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -123,7 +123,7 @@ error_code cellKbEnd(ppu_thread& ppu)
|
||||
|
||||
error_code cellKbClearBuf(u32 port_no)
|
||||
{
|
||||
sys_io.trace("cellKbClearBuf(port_no=%d)", port_no);
|
||||
cellKb.trace("cellKbClearBuf(port_no=%d)", port_no);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -158,7 +158,7 @@ error_code cellKbClearBuf(u32 port_no)
|
||||
|
||||
u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
{
|
||||
sys_io.trace("cellKbCnvRawCode(arrange=%d, mkey=%d, led=%d, rawcode=0x%x)", arrange, mkey, led, rawcode);
|
||||
cellKb.trace("cellKbCnvRawCode(arrange=%d, mkey=%d, led=%d, rawcode=0x%x)", arrange, mkey, led, rawcode);
|
||||
|
||||
// CELL_KB_RAWDAT
|
||||
if (rawcode <= CELL_KEYC_E_UNDEF ||
|
||||
@ -308,7 +308,7 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
|
||||
error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
|
||||
{
|
||||
sys_io.trace("cellKbGetInfo(info=*0x%x)", info);
|
||||
cellKb.trace("cellKbGetInfo(info=*0x%x)", info);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -340,7 +340,7 @@ error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
|
||||
|
||||
error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
|
||||
{
|
||||
sys_io.trace("cellKbRead(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellKb.trace("cellKbRead(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -397,7 +397,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
|
||||
|
||||
error_code cellKbSetCodeType(u32 port_no, u32 type)
|
||||
{
|
||||
sys_io.trace("cellKbSetCodeType(port_no=%d, type=%d)", port_no, type);
|
||||
cellKb.trace("cellKbSetCodeType(port_no=%d, type=%d)", port_no, type);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -425,7 +425,7 @@ error_code cellKbSetCodeType(u32 port_no, u32 type)
|
||||
|
||||
error_code cellKbSetLEDStatus(u32 port_no, u8 led)
|
||||
{
|
||||
sys_io.trace("cellKbSetLEDStatus(port_no=%d, led=%d)", port_no, led);
|
||||
cellKb.trace("cellKbSetLEDStatus(port_no=%d, led=%d)", port_no, led);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -454,7 +454,7 @@ error_code cellKbSetLEDStatus(u32 port_no, u8 led)
|
||||
|
||||
error_code cellKbSetReadMode(u32 port_no, u32 rmode)
|
||||
{
|
||||
sys_io.trace("cellKbSetReadMode(port_no=%d, rmode=%d)", port_no, rmode);
|
||||
cellKb.trace("cellKbSetReadMode(port_no=%d, rmode=%d)", port_no, rmode);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
@ -486,7 +486,7 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode)
|
||||
|
||||
error_code cellKbGetConfiguration(u32 port_no, vm::ptr<CellKbConfig> config)
|
||||
{
|
||||
sys_io.trace("cellKbGetConfiguration(port_no=%d, config=*0x%x)", port_no, config);
|
||||
cellKb.trace("cellKbGetConfiguration(port_no=%d, config=*0x%x)", port_no, config);
|
||||
|
||||
auto& handler = g_fxo->get<KeyboardHandlerBase>();
|
||||
|
||||
|
@ -12,7 +12,7 @@ error_code sys_config_stop(ppu_thread& ppu);
|
||||
|
||||
extern bool is_input_allowed();
|
||||
|
||||
LOG_CHANNEL(sys_io);
|
||||
LOG_CHANNEL(cellMouse);
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellMouseError>::format(std::string& out, u64 arg)
|
||||
@ -37,7 +37,7 @@ void fmt_class_string<CellMouseError>::format(std::string& out, u64 arg)
|
||||
|
||||
error_code cellMouseInit(ppu_thread& ppu, u32 max_connect)
|
||||
{
|
||||
sys_io.notice("cellMouseInit(max_connect=%d)", max_connect);
|
||||
cellMouse.notice("cellMouseInit(max_connect=%d)", max_connect);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -60,7 +60,7 @@ error_code cellMouseInit(ppu_thread& ppu, u32 max_connect)
|
||||
|
||||
error_code cellMouseClearBuf(u32 port_no)
|
||||
{
|
||||
sys_io.trace("cellMouseClearBuf(port_no=%d)", port_no);
|
||||
cellMouse.trace("cellMouseClearBuf(port_no=%d)", port_no);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -97,7 +97,7 @@ error_code cellMouseClearBuf(u32 port_no)
|
||||
|
||||
error_code cellMouseEnd(ppu_thread& ppu)
|
||||
{
|
||||
sys_io.notice("cellMouseEnd()");
|
||||
cellMouse.notice("cellMouseEnd()");
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -113,7 +113,7 @@ error_code cellMouseEnd(ppu_thread& ppu)
|
||||
|
||||
error_code cellMouseGetInfo(vm::ptr<CellMouseInfo> info)
|
||||
{
|
||||
sys_io.trace("cellMouseGetInfo(info=*0x%x)", info);
|
||||
cellMouse.trace("cellMouseGetInfo(info=*0x%x)", info);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -146,7 +146,7 @@ error_code cellMouseGetInfo(vm::ptr<CellMouseInfo> info)
|
||||
|
||||
error_code cellMouseInfoTabletMode(u32 port_no, vm::ptr<CellMouseInfoTablet> info)
|
||||
{
|
||||
sys_io.trace("cellMouseInfoTabletMode(port_no=%d, info=*0x%x)", port_no, info);
|
||||
cellMouse.trace("cellMouseInfoTabletMode(port_no=%d, info=*0x%x)", port_no, info);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -183,7 +183,7 @@ error_code cellMouseInfoTabletMode(u32 port_no, vm::ptr<CellMouseInfoTablet> inf
|
||||
|
||||
error_code cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
|
||||
{
|
||||
sys_io.trace("cellMouseGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellMouse.trace("cellMouseGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -233,7 +233,7 @@ error_code cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
|
||||
|
||||
error_code cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
|
||||
{
|
||||
sys_io.trace("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
cellMouse.trace("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -288,7 +288,7 @@ error_code cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
|
||||
|
||||
error_code cellMouseSetTabletMode(u32 port_no, u32 mode)
|
||||
{
|
||||
sys_io.warning("cellMouseSetTabletMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
cellMouse.warning("cellMouseSetTabletMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -324,7 +324,7 @@ error_code cellMouseSetTabletMode(u32 port_no, u32 mode)
|
||||
|
||||
error_code cellMouseGetTabletDataList(u32 port_no, vm::ptr<CellMouseTabletDataList> data)
|
||||
{
|
||||
sys_io.warning("cellMouseGetTabletDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
cellMouse.warning("cellMouseGetTabletDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@ -380,7 +380,7 @@ error_code cellMouseGetTabletDataList(u32 port_no, vm::ptr<CellMouseTabletDataLi
|
||||
|
||||
error_code cellMouseGetRawData(u32 port_no, vm::ptr<CellMouseRawData> data)
|
||||
{
|
||||
sys_io.trace("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellMouse.trace("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
|
@ -14,7 +14,7 @@ error_code sys_config_stop(ppu_thread& ppu);
|
||||
|
||||
extern bool is_input_allowed();
|
||||
|
||||
LOG_CHANNEL(sys_io);
|
||||
LOG_CHANNEL(cellPad);
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellPadError>::format(std::string& out, u64 arg)
|
||||
@ -148,7 +148,7 @@ extern void pad_state_notify_state_change(usz index, u32 state)
|
||||
|
||||
error_code cellPadInit(ppu_thread& ppu, u32 max_connect)
|
||||
{
|
||||
sys_io.warning("cellPadInit(max_connect=%d)", max_connect);
|
||||
cellPad.warning("cellPadInit(max_connect=%d)", max_connect);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -182,7 +182,7 @@ error_code cellPadInit(ppu_thread& ppu, u32 max_connect)
|
||||
|
||||
error_code cellPadEnd(ppu_thread& ppu)
|
||||
{
|
||||
sys_io.notice("cellPadEnd()");
|
||||
cellPad.notice("cellPadEnd()");
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -218,7 +218,7 @@ void clear_pad_buffer(const std::shared_ptr<Pad>& pad)
|
||||
|
||||
error_code cellPadClearBuf(u32 port_no)
|
||||
{
|
||||
sys_io.trace("cellPadClearBuf(port_no=%d)", port_no);
|
||||
cellPad.trace("cellPadClearBuf(port_no=%d)", port_no);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -579,7 +579,7 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
|
||||
|
||||
error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
{
|
||||
sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellPad.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -607,7 +607,7 @@ error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
|
||||
error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
|
||||
{
|
||||
sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info);
|
||||
cellPad.trace("cellPadPeriphGetInfo(info=*0x%x)", info);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -658,7 +658,7 @@ error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
|
||||
|
||||
error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
|
||||
{
|
||||
sys_io.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellPad.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -691,7 +691,7 @@ error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
|
||||
|
||||
error_code cellPadGetRawData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
{
|
||||
sys_io.todo("cellPadGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
cellPad.todo("cellPadGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -720,7 +720,7 @@ error_code cellPadGetRawData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
|
||||
error_code cellPadGetDataExtra(u32 port_no, vm::ptr<u32> device_type, vm::ptr<CellPadData> data)
|
||||
{
|
||||
sys_io.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data);
|
||||
cellPad.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data);
|
||||
|
||||
// TODO: This is used just to get data from a BD/CEC remote,
|
||||
// but if the port isnt a remote, device type is set to CELL_PAD_DEV_TYPE_STANDARD and just regular cellPadGetData is returned
|
||||
@ -744,7 +744,7 @@ error_code cellPadGetDataExtra(u32 port_no, vm::ptr<u32> device_type, vm::ptr<Ce
|
||||
|
||||
error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
|
||||
{
|
||||
sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param);
|
||||
cellPad.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -788,7 +788,7 @@ error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
|
||||
|
||||
error_code cellPadGetInfo(vm::ptr<CellPadInfo> info)
|
||||
{
|
||||
sys_io.trace("cellPadGetInfo(info=*0x%x)", info);
|
||||
cellPad.trace("cellPadGetInfo(info=*0x%x)", info);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -833,7 +833,7 @@ error_code cellPadGetInfo(vm::ptr<CellPadInfo> info)
|
||||
|
||||
error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
|
||||
{
|
||||
sys_io.trace("cellPadGetInfo2(info=*0x%x)", info);
|
||||
cellPad.trace("cellPadGetInfo2(info=*0x%x)", info);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -882,7 +882,7 @@ error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
|
||||
|
||||
error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellPadCapabilityInfo> info)
|
||||
{
|
||||
sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr());
|
||||
cellPad.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr());
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -913,7 +913,7 @@ error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellPadCapabilityInfo>
|
||||
|
||||
error_code cellPadSetPortSetting(u32 port_no, u32 port_setting)
|
||||
{
|
||||
sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);
|
||||
cellPad.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -938,7 +938,7 @@ error_code cellPadSetPortSetting(u32 port_no, u32 port_setting)
|
||||
|
||||
error_code cellPadInfoPressMode(u32 port_no)
|
||||
{
|
||||
sys_io.trace("cellPadInfoPressMode(port_no=%d)", port_no);
|
||||
cellPad.trace("cellPadInfoPressMode(port_no=%d)", port_no);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -965,7 +965,7 @@ error_code cellPadInfoPressMode(u32 port_no)
|
||||
|
||||
error_code cellPadInfoSensorMode(u32 port_no)
|
||||
{
|
||||
sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no);
|
||||
cellPad.trace("cellPadInfoSensorMode(port_no=%d)", port_no);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -992,7 +992,7 @@ error_code cellPadInfoSensorMode(u32 port_no)
|
||||
|
||||
error_code cellPadSetPressMode(u32 port_no, u32 mode)
|
||||
{
|
||||
sys_io.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
cellPad.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1026,7 +1026,7 @@ error_code cellPadSetPressMode(u32 port_no, u32 mode)
|
||||
|
||||
error_code cellPadSetSensorMode(u32 port_no, u32 mode)
|
||||
{
|
||||
sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
cellPad.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1060,7 +1060,7 @@ error_code cellPadSetSensorMode(u32 port_no, u32 mode)
|
||||
|
||||
error_code cellPadLddRegisterController()
|
||||
{
|
||||
sys_io.warning("cellPadLddRegisterController()");
|
||||
cellPad.warning("cellPadLddRegisterController()");
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1085,7 +1085,7 @@ error_code cellPadLddRegisterController()
|
||||
|
||||
error_code cellPadLddDataInsert(s32 handle, vm::ptr<CellPadData> data)
|
||||
{
|
||||
sys_io.trace("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data);
|
||||
cellPad.trace("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1110,7 +1110,7 @@ error_code cellPadLddDataInsert(s32 handle, vm::ptr<CellPadData> data)
|
||||
|
||||
error_code cellPadLddGetPortNo(s32 handle)
|
||||
{
|
||||
sys_io.trace("cellPadLddGetPortNo(handle=%d)", handle);
|
||||
cellPad.trace("cellPadLddGetPortNo(handle=%d)", handle);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1134,7 +1134,7 @@ error_code cellPadLddGetPortNo(s32 handle)
|
||||
|
||||
error_code cellPadLddUnregisterController(s32 handle)
|
||||
{
|
||||
sys_io.warning("cellPadLddUnregisterController(handle=%d)", handle);
|
||||
cellPad.warning("cellPadLddUnregisterController(handle=%d)", handle);
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
@ -1160,7 +1160,7 @@ error_code cellPadLddUnregisterController(s32 handle)
|
||||
|
||||
error_code cellPadFilterIIRInit(vm::ptr<CellPadFilterIIRSos> pSos, s32 cutoff)
|
||||
{
|
||||
sys_io.todo("cellPadFilterIIRInit(pSos=*0x%x, cutoff=%d)", pSos, cutoff);
|
||||
cellPad.todo("cellPadFilterIIRInit(pSos=*0x%x, cutoff=%d)", pSos, cutoff);
|
||||
|
||||
if (!pSos) // TODO: does this check for cutoff > 2 ?
|
||||
{
|
||||
@ -1172,7 +1172,7 @@ error_code cellPadFilterIIRInit(vm::ptr<CellPadFilterIIRSos> pSos, s32 cutoff)
|
||||
|
||||
u32 cellPadFilterIIRFilter(vm::ptr<CellPadFilterIIRSos> pSos, u32 filterIn)
|
||||
{
|
||||
sys_io.todo("cellPadFilterIIRFilter(pSos=*0x%x, filterIn=%d)", pSos, filterIn);
|
||||
cellPad.todo("cellPadFilterIIRFilter(pSos=*0x%x, filterIn=%d)", pSos, filterIn);
|
||||
|
||||
// TODO: apply filter
|
||||
|
||||
@ -1183,7 +1183,7 @@ s32 sys_io_3733EA3C(u32 port_no, vm::ptr<u32> device_type, vm::ptr<CellPadData>
|
||||
{
|
||||
// Used by the ps1 emulator built into the firmware
|
||||
// Seems to call the same function that getdataextra does
|
||||
sys_io.trace("sys_io_3733EA3C(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data);
|
||||
cellPad.trace("sys_io_3733EA3C(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data);
|
||||
return cellPadGetDataExtra(port_no, device_type, data);
|
||||
}
|
||||
|
||||
|
@ -744,7 +744,7 @@ error_code sceNpDrmIsAvailable(ppu_thread& ppu, vm::cptr<u8> k_licensee_addr, vm
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto ret = npDrmIsAvailable(k_licensee_addr, drm_path);
|
||||
lv2_sleep(50'000, &ppu);
|
||||
lv2_sleep(25'000, &ppu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -305,6 +305,16 @@ public:
|
||||
return addr + index * 8 + (is_code_addr ? 4 : 0);
|
||||
}
|
||||
|
||||
bool is_func(u32 cia) const
|
||||
{
|
||||
if (cia % 4 || !addr || cia < addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (cia - addr) / 8 < access().size();
|
||||
}
|
||||
|
||||
// Allocation address
|
||||
u32 addr = 0;
|
||||
|
||||
|
@ -2760,7 +2760,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc, bool is_thread_entry)
|
||||
|
||||
const auto cia = _this->cia;
|
||||
|
||||
if (_this->current_function && vm::read32(cia) != ppu_instructions::SC(0))
|
||||
if (_this->current_function && g_fxo->get<ppu_function_manager>().is_func(cia))
|
||||
{
|
||||
return fmt::format("PPU[0x%x] Thread (%s) [HLE:0x%08x, LR:0x%08x]", _this->id, *name_cache.get(), cia, _this->lr);
|
||||
}
|
||||
|
@ -2627,18 +2627,18 @@ reg_state_t reg_state_t::downgrade() const
|
||||
{
|
||||
if (flag & vf::is_const)
|
||||
{
|
||||
return reg_state_t{vf::is_mask, 0, umax, this->value, ~this->value};
|
||||
return reg_state_t{vf::is_mask, 0, umax, this->value, ~this->value, this->origin};
|
||||
}
|
||||
|
||||
if (!(flag - vf::is_null))
|
||||
{
|
||||
return reg_state_t{vf::is_mask, 0, this->tag, 0, 0};
|
||||
return reg_state_t{vf::is_mask, 0, this->tag, 0, 0, this->origin};
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
reg_state_t reg_state_t::merge(const reg_state_t& rhs) const
|
||||
reg_state_t reg_state_t::merge(const reg_state_t& rhs, u32 current_pc) const
|
||||
{
|
||||
if (rhs == *this)
|
||||
{
|
||||
@ -2661,12 +2661,13 @@ reg_state_t reg_state_t::merge(const reg_state_t& rhs) const
|
||||
{
|
||||
// Success (create new value tag)
|
||||
res.tag = reg_state_t::alloc_tag();
|
||||
res.origin = current_pc;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return make_unknown();
|
||||
return make_unknown(current_pc);
|
||||
}
|
||||
|
||||
reg_state_t reg_state_t::build_on_top_of(const reg_state_t& rhs) const
|
||||
@ -2728,9 +2729,17 @@ u32 reg_state_t::alloc_tag(bool reset) noexcept
|
||||
return ++g_tls_tag;
|
||||
}
|
||||
|
||||
void reg_state_t::invalidate_if_created(u32 current_pc)
|
||||
{
|
||||
if (!is_const() && origin == current_pc)
|
||||
{
|
||||
tag = reg_state_t::alloc_tag();
|
||||
}
|
||||
}
|
||||
|
||||
// Converge 2 register states to the same flow in execution
|
||||
template <usz N>
|
||||
static void merge(std::array<reg_state_t, N>& result, const std::array<reg_state_t, N>& lhs, const std::array<reg_state_t, N>& rhs)
|
||||
static void merge(std::array<reg_state_t, N>& result, const std::array<reg_state_t, N>& lhs, const std::array<reg_state_t, N>& rhs, u32 current_pc)
|
||||
{
|
||||
usz index = umax;
|
||||
|
||||
@ -2738,7 +2747,7 @@ static void merge(std::array<reg_state_t, N>& result, const std::array<reg_state
|
||||
{
|
||||
index++;
|
||||
|
||||
state = lhs[index].merge(rhs[index]);
|
||||
state = lhs[index].merge(rhs[index], current_pc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2777,7 +2786,7 @@ struct block_reg_info
|
||||
|
||||
static std::unique_ptr<block_reg_info> create(u32 pc) noexcept
|
||||
{
|
||||
auto ptr = new block_reg_info{ pc, reg_state_t::make_unknown<s_reg_max>() };
|
||||
auto ptr = new block_reg_info{ pc, reg_state_t::make_unknown<s_reg_max>(pc) };
|
||||
|
||||
for (reg_state_t& f : ptr->local_state)
|
||||
{
|
||||
@ -4882,7 +4891,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
const bool should_search_patterns = target_count < 300u;
|
||||
|
||||
// Treat start of function as an unknown value with tag (because it is)
|
||||
const reg_state_t start_program_count = reg_state_t::make_unknown();
|
||||
const reg_state_t start_program_count = reg_state_t::make_unknown(entry_point - 1);
|
||||
|
||||
// Initialize
|
||||
reg_state_it.emplace_back(entry_point);
|
||||
@ -5375,10 +5384,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
vregs[reg] = reg_state_t::from_value(value);
|
||||
};
|
||||
|
||||
const auto inherit_const_value = [&](u32 reg, bs_t<vf> flag, u32 value)
|
||||
const auto inherit_const_value = [&](u32 reg, const reg_state_t& ra, const reg_state_t& rb, u32 value, u32 pos)
|
||||
{
|
||||
flag -= vf::is_null;
|
||||
vregs[reg] = reg_state_t{flag, value, flag & vf::is_const ? u32{umax} : reg_state_t::alloc_tag()};
|
||||
if (ra.origin != rb.origin)
|
||||
{
|
||||
pos = reg_state_it[wi].pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = ra.origin;
|
||||
}
|
||||
|
||||
const bs_t<vf> flag = (ra.flag & rb.flag) - vf::is_null;
|
||||
|
||||
vregs[reg] = reg_state_t{flag, value, flag & vf::is_const ? u32{umax} : reg_state_t::alloc_tag(), 0, 0, pos};
|
||||
};
|
||||
|
||||
const auto inherit_const_mask_value = [&](u32 reg, reg_state_t state, u32 mask_ones, u32 mask_zeroes)
|
||||
@ -5407,12 +5426,12 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
ensure(state.tag != umax);
|
||||
vregs[reg] = reg_state_t{vf::is_mask, 0, state.tag, ones, zeroes};
|
||||
vregs[reg] = reg_state_t{vf::is_mask, 0, state.tag, ones, zeroes, state.origin};
|
||||
};
|
||||
|
||||
const auto unconst = [&](u32 reg)
|
||||
const auto unconst = [&](u32 reg, u32 pc)
|
||||
{
|
||||
vregs[reg] = {{}, {}, reg_state_t::alloc_tag()};
|
||||
vregs[reg] = reg_state_t::make_unknown(pc);
|
||||
};
|
||||
|
||||
const auto add_block = [&](u32 target)
|
||||
@ -5467,6 +5486,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic16.active)
|
||||
{
|
||||
for (auto state : {&atomic16.lsa, &atomic16.ls, &atomic16.ls_offs})
|
||||
{
|
||||
state->invalidate_if_created(pos);
|
||||
}
|
||||
}
|
||||
|
||||
const u32 data = std::bit_cast<be_t<u32>>(::at32(result.data, (pos - lsa) / 4));
|
||||
const auto op = spu_opcode_t{data};
|
||||
const auto type = g_spu_itype.decode(data);
|
||||
@ -5650,7 +5677,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
case MFC_Cmd:
|
||||
{
|
||||
const auto [af, av, atagg, _3, _5] = get_reg(op.rt);
|
||||
const auto [af, av, atagg, _3, _5, apc] = get_reg(op.rt);
|
||||
|
||||
if (!is_pattern_match)
|
||||
{
|
||||
@ -5662,9 +5689,15 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
case MFC_GETLLAR_CMD:
|
||||
{
|
||||
// Get LSA and apply mask for GETLLAR
|
||||
// TODO: Simplify this to be a value returning function
|
||||
auto old_lsa = get_reg(s_reg_mfc_lsa);
|
||||
inherit_const_mask_value(s_reg_mfc_lsa, old_lsa, 0, ~SPU_LS_MASK_128);
|
||||
|
||||
// Restore LSA
|
||||
auto lsa = get_reg(s_reg_mfc_lsa);
|
||||
inherit_const_mask_value(s_reg_mfc_lsa, lsa, 0, ~SPU_LS_MASK_128);
|
||||
lsa = get_reg(s_reg_mfc_lsa);
|
||||
vregs[s_reg_mfc_lsa] = old_lsa;
|
||||
|
||||
const u32 lsa_pc = atomic16.lsa_last_pc == SPU_LS_SIZE ? bpc : atomic16.lsa_last_pc;
|
||||
|
||||
if (atomic16.active)
|
||||
@ -5716,7 +5749,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vregs[s_reg_mfc_lsa].compare_with_mask_indifference(*val, SPU_LS_MASK_1))
|
||||
if (vregs[s_reg_mfc_lsa].compare_with_mask_indifference(*val, SPU_LS_MASK_16))
|
||||
{
|
||||
regs[reg_it] = s_reg_mfc_lsa;
|
||||
continue;
|
||||
@ -5726,7 +5759,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const auto& _reg = vregs[i];
|
||||
|
||||
if (_reg == *val)
|
||||
if (_reg.compare_with_mask_indifference(*val, SPU_LS_MASK_16))
|
||||
{
|
||||
regs[reg_it] = i;
|
||||
break;
|
||||
@ -5908,14 +5941,25 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
// Merge pattern attributes between different code paths, may cause detection of failures
|
||||
atomic16_t& existing = it->second;
|
||||
|
||||
if (existing.lsa_pc != atomic16.lsa_pc || existing.put_pc != atomic16.put_pc || existing.lsa != atomic16.lsa)
|
||||
auto compare_tag_and_reg = [](std::pair<const reg_state_t*, u32> a, std::pair<const reg_state_t*, u32> b)
|
||||
{
|
||||
if (b.first->is_const() && a.first->is_const())
|
||||
{
|
||||
return a.first->compare_with_mask_indifference(*b.first, SPU_LS_MASK_1);
|
||||
}
|
||||
|
||||
// Compare register source
|
||||
return a.second == b.second;
|
||||
};
|
||||
|
||||
if (existing.lsa_pc != atomic16.lsa_pc || existing.put_pc != atomic16.put_pc || !existing.lsa.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128))
|
||||
{
|
||||
// Register twice
|
||||
break_putllc16(22, atomic16.discard());
|
||||
break_putllc16(22, existing.discard());
|
||||
}
|
||||
|
||||
if (existing.active && existing.ls_access && atomic16.ls_access && (!existing.ls.compare_with_mask_indifference(atomic16.ls, SPU_LS_MASK_1) || existing.ls_offs != atomic16.ls_offs))
|
||||
if (existing.active && existing.ls_access && atomic16.ls_access && (!compare_tag_and_reg({&existing.ls, existing.reg}, {&atomic16.ls, atomic16.reg}) || existing.ls_offs != atomic16.ls_offs || existing.reg2 != atomic16.reg2))
|
||||
{
|
||||
// Conflicting loads with stores in more than one code path
|
||||
break_putllc16(27, atomic16.set_invalid_ls(existing.ls_write || atomic16.ls_write));
|
||||
@ -5938,6 +5982,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
// Propagate LS access
|
||||
existing.ls = atomic16.ls;
|
||||
existing.reg = atomic16.reg;
|
||||
existing.reg2 = atomic16.reg2;
|
||||
existing.ls_offs = atomic16.ls_offs;
|
||||
}
|
||||
|
||||
@ -5989,7 +6035,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (invalidate)
|
||||
{
|
||||
unconst(op.rt);
|
||||
unconst(op.rt, pos);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -6068,7 +6114,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
// Unconst
|
||||
unconst(op.rt);
|
||||
unconst(op.rt, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6237,7 +6283,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
// Unconst
|
||||
unconst(op.rt);
|
||||
unconst(op.rt, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::STQA:
|
||||
@ -6291,7 +6337,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
// Unconst
|
||||
unconst(op.rt);
|
||||
unconst(op.rt, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6371,14 +6417,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
// Unconst
|
||||
unconst(op.rt);
|
||||
unconst(op.rt, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case spu_itype::HBR:
|
||||
{
|
||||
hbr_loc = spu_branch_target(pos, op.roh << 7 | op.rt);
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
const auto [af, av, at, ao, az, apc] = get_reg(op.ra);
|
||||
hbr_tg = af & vf::is_const && !op.c ? av & 0x3fffc : -1;
|
||||
break;
|
||||
}
|
||||
@ -6443,9 +6489,13 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
const auto [bf, bv, _2, _4, _6] = get_reg(op.rb);
|
||||
inherit_const_value(op.rt, af & bf, bv | av);
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, ra, rb, av | bv, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::XORI:
|
||||
@ -6456,8 +6506,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
inherit_const_value(op.rt, af, av ^ op.si10);
|
||||
const auto ra = get_reg(op.ra);
|
||||
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
|
||||
inherit_const_value(op.rt, ra, ra, av ^ op.si10, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::XOR:
|
||||
@ -6468,16 +6521,24 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
const auto [bf, bv, _2, _4, _6] = get_reg(op.rb);
|
||||
inherit_const_value(op.rt, af & bf, bv ^ av);
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, ra, rb, bv ^ av, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::NOR:
|
||||
{
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
const auto [bf, bv, _2, _4, _6] = get_reg(op.rb);
|
||||
inherit_const_value(op.rt, af & bf, ~(bv | av));
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, ra, rb, ~(bv | av), pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::ANDI:
|
||||
@ -6494,9 +6555,13 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
const auto [bf, bv, _2, _4, _6] = get_reg(op.rb);
|
||||
inherit_const_value(op.rt, af & bf, bv & av);
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, ra, rb, bv & av, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::AI:
|
||||
@ -6508,9 +6573,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto [af, av, at, ao, az] = ra;
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
|
||||
inherit_const_value(op.rt, af, av + op.si10);
|
||||
inherit_const_value(op.rt, ra, ra, av + op.si10, pos);
|
||||
|
||||
if (u32 mask = ra.get_known_zeroes() & ~op.si10; mask & 1)
|
||||
{
|
||||
@ -6525,10 +6590,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az] = ra;
|
||||
const auto [bf, bv, bt, bo, bz] = rb;
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, af & bf, bv + av);
|
||||
inherit_const_value(op.rt, ra, rb, bv + av, pos);
|
||||
|
||||
if (u32 mask = ra.get_known_zeroes() & rb.get_known_zeroes(); mask & 1)
|
||||
{
|
||||
@ -6540,8 +6605,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
case spu_itype::SFI:
|
||||
{
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
inherit_const_value(op.rt, af, op.si10 - av);
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto [af, av, at, ao, az, apc] = get_reg(op.ra);
|
||||
|
||||
inherit_const_value(op.rt, ra, ra, op.si10 - av, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::SF:
|
||||
@ -6549,10 +6616,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
const auto [af, av, at, ao, az] = ra;
|
||||
const auto [bf, bv, bt, bo, bz] = rb;
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
const auto [bf, bv, bt, bo, bz, bpc] = rb;
|
||||
|
||||
inherit_const_value(op.rt, af & bf, bv - av);
|
||||
inherit_const_value(op.rt, ra, rb, bv - av, pos);
|
||||
|
||||
if (u32 mask = ra.get_known_zeroes() & rb.get_known_zeroes(); mask & 1)
|
||||
{
|
||||
@ -6588,8 +6655,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
inherit_const_value(op.rt, af, av >> ((0 - op.i7) & 0x1f));
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto [af, av, at, ao, az, apc] = get_reg(op.ra);
|
||||
|
||||
inherit_const_value(op.rt, ra, ra, av >> ((0 - op.i7) & 0x1f), pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::SHLI:
|
||||
@ -6606,8 +6675,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
const auto [af, av, at, ao, az] = get_reg(op.ra);
|
||||
inherit_const_value(op.rt, af, av << (op.i7 & 0x1f));
|
||||
const auto ra = get_reg(op.ra);
|
||||
const auto [af, av, at, ao, az, apc] = ra;
|
||||
|
||||
inherit_const_value(op.rt, ra, ra, av << (op.i7 & 0x1f), pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::SELB:
|
||||
@ -6616,7 +6687,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
const auto rb = get_reg(op.rb);
|
||||
|
||||
// Ignore RC, perform a value merge which also respect bitwise information
|
||||
vregs[op.rt4] = ra.merge(rb);
|
||||
vregs[op.rt4] = ra.merge(rb, pos);
|
||||
break;
|
||||
}
|
||||
case spu_itype::SHLQBYI:
|
||||
@ -6641,7 +6712,49 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (!(type & spu_itype::zregmod))
|
||||
{
|
||||
const u32 op_rt = type & spu_itype::_quadrop ? +op.rt4 : +op.rt;
|
||||
unconst(op_rt);
|
||||
|
||||
u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max;
|
||||
|
||||
if (m_use_ra.test(pos / 4))
|
||||
{
|
||||
ra = op.ra;
|
||||
}
|
||||
|
||||
if (m_use_rb.test(pos / 4))
|
||||
{
|
||||
rb = op.rb;
|
||||
}
|
||||
|
||||
if (type & spu_itype::_quadrop && m_use_rc.test(pos / 4))
|
||||
{
|
||||
rc = op.rc;
|
||||
}
|
||||
|
||||
u32 reg_pos = SPU_LS_SIZE;
|
||||
|
||||
for (u32 reg : {ra, rb, rc})
|
||||
{
|
||||
if (reg != s_reg_max)
|
||||
{
|
||||
if (reg_pos == SPU_LS_SIZE)
|
||||
{
|
||||
reg = vregs[reg].origin;
|
||||
}
|
||||
else if (reg_pos != vregs[reg].origin)
|
||||
{
|
||||
const u32 block_start = reg_state_it[wi].pc;
|
||||
|
||||
// if (vregs[reg].origin >= block_start && vregs[reg].origin <= pos)
|
||||
// {
|
||||
// reg_pos = std::max<u32>(vregs[reg].origin, reg_pos);
|
||||
// }
|
||||
reg_pos = block_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unconst(op_rt, reg_pos == SPU_LS_SIZE ? pos : reg_pos);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -7714,7 +7827,7 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
|
||||
}
|
||||
else
|
||||
{
|
||||
merge(res_state, res_state, *arg_state);
|
||||
merge(res_state, res_state, *arg_state, it->block_pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1292,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
const auto diff = m_ir->CreateZExt(m_ir->CreateSub(dest, _lsa), get_type<u64>());
|
||||
|
||||
const auto _new = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr<u128>(m_lsptr, dest), llvm::MaybeAlign{16});
|
||||
const auto _rdata = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr<u128>(spu_ptr<u8>(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x7f)), llvm::MaybeAlign{16});
|
||||
const auto _rdata = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr<u128>(spu_ptr<u8>(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16});
|
||||
|
||||
const bool is_accurate_op = !!g_cfg.core.spu_accurate_reservations;
|
||||
|
||||
@ -1360,7 +1360,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
|
||||
llvm::Value* old_val{};
|
||||
|
||||
if (is_accurate_op)
|
||||
if (true || is_accurate_op)
|
||||
{
|
||||
old_val = m_ir->CreateLoad(get_type<u64>(), spu_ptr<u64>(&spu_thread::rtime));
|
||||
}
|
||||
@ -1373,7 +1373,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
|
||||
const auto cmp_res2 = m_ir->CreateAtomicCmpXchg(rptr2, old_val, m_ir->CreateAdd(old_val, m_ir->getInt64(128)), llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering::SequentiallyConsistent);
|
||||
|
||||
if (is_accurate_op)
|
||||
if (true || is_accurate_op)
|
||||
{
|
||||
m_ir->CreateCondBr(m_ir->CreateExtractValue(cmp_res2, 1), _success, _fail);
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ public:
|
||||
u32 tag = umax;
|
||||
u32 known_ones{};
|
||||
u32 known_zeroes{};
|
||||
u32 origin = SPU_LS_SIZE;
|
||||
|
||||
bool is_const() const;
|
||||
|
||||
@ -222,21 +223,33 @@ public:
|
||||
bool compare_with_mask_indifference(u32 imm, u32 mask_bits) const;
|
||||
bool unequal_with_mask_indifference(const reg_state_t& r, u32 mask_bits) const;
|
||||
|
||||
// Convert constant-based value to mask-based value
|
||||
reg_state_t downgrade() const;
|
||||
reg_state_t merge(const reg_state_t& rhs) const;
|
||||
|
||||
// Connect two register states between different blocks
|
||||
reg_state_t merge(const reg_state_t& rhs, u32 current_pc) const;
|
||||
|
||||
// Override value with newer value if needed
|
||||
reg_state_t build_on_top_of(const reg_state_t& rhs) const;
|
||||
|
||||
// Get known zeroes mask
|
||||
u32 get_known_zeroes() const;
|
||||
|
||||
// Get known ones mask
|
||||
u32 get_known_ones() const;
|
||||
|
||||
// Invalidate value if non-constant and reached the point in history of its creation
|
||||
void invalidate_if_created(u32 current_pc);
|
||||
|
||||
template <usz Count = 1>
|
||||
static std::conditional_t<Count == 1, reg_state_t, std::array<reg_state_t, Count>> make_unknown() noexcept
|
||||
static std::conditional_t<Count == 1, reg_state_t, std::array<reg_state_t, Count>> make_unknown(u32 pc) noexcept
|
||||
{
|
||||
if constexpr (Count == 1)
|
||||
{
|
||||
reg_state_t v{};
|
||||
v.tag = alloc_tag();
|
||||
v.flag = {};
|
||||
v.origin = pc;
|
||||
return v;
|
||||
}
|
||||
else
|
||||
@ -245,7 +258,7 @@ public:
|
||||
|
||||
for (reg_state_t& state : result)
|
||||
{
|
||||
state = make_unknown<1>();
|
||||
state = make_unknown<1>(pc);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "sys_memory.h"
|
||||
#include <span>
|
||||
|
||||
extern void dump_executable(std::span<const u8> data, ppu_module* _main, std::string_view title_id);
|
||||
extern void dump_executable(std::span<const u8> data, const ppu_module* _module, std::string_view title_id);
|
||||
|
||||
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64, utils::serial* = nullptr);
|
||||
extern void ppu_unload_prx(const lv2_prx& prx);
|
||||
@ -195,8 +195,8 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
|
||||
}
|
||||
|
||||
std::string vpath0;
|
||||
const std::string path = vfs::get(vpath, nullptr, &vpath0);
|
||||
const std::string name = vpath0.substr(vpath0.find_last_of('/') + 1);
|
||||
std::string path = vfs::get(vpath, nullptr, &vpath0);
|
||||
std::string name = vpath0.substr(vpath0.find_last_of('/') + 1);
|
||||
|
||||
bool ignore = false;
|
||||
|
||||
|
@ -94,7 +94,7 @@ void KeyboardHandlerBase::RemoveConsumer(keyboard_consumer::identifier id)
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyboardHandlerBase::HandleKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key)
|
||||
bool KeyboardHandlerBase::HandleKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key)
|
||||
{
|
||||
bool consumed = false;
|
||||
|
||||
@ -102,13 +102,13 @@ bool KeyboardHandlerBase::HandleKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
|
||||
for (auto& [id, consumer] : m_consumers)
|
||||
{
|
||||
consumed |= consumer.ConsumeKey(code, pressed, is_auto_repeat, key);
|
||||
consumed |= consumer.ConsumeKey(qt_code, native_code, pressed, is_auto_repeat, key);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key)
|
||||
bool keyboard_consumer::ConsumeKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key)
|
||||
{
|
||||
bool consumed = false;
|
||||
|
||||
@ -124,22 +124,24 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
KbData& data = keyboard.m_data;
|
||||
const KbConfig& config = keyboard.m_config;
|
||||
|
||||
if (auto it = keyboard.m_keys.find(code); it != keyboard.m_keys.end())
|
||||
if (auto it = keyboard.m_keys.find(qt_code); it != keyboard.m_keys.end())
|
||||
{
|
||||
KbButton& button = it->second;
|
||||
|
||||
const u32 out_key_code = get_out_key_code(qt_code, native_code, button.m_outKeyCode);
|
||||
|
||||
u16 kcode = CELL_KEYC_NO_EVENT;
|
||||
bool is_meta_key = IsMetaKey(code);
|
||||
bool is_meta_key = IsMetaKey(qt_code);
|
||||
|
||||
if (!is_meta_key)
|
||||
{
|
||||
if (config.code_type == CELL_KB_CODETYPE_RAW)
|
||||
{
|
||||
kcode = button.m_outKeyCode;
|
||||
kcode = out_key_code;
|
||||
}
|
||||
else // config.code_type == CELL_KB_CODETYPE_ASCII
|
||||
{
|
||||
kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, button.m_outKeyCode);
|
||||
kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, out_key_code);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,33 +155,33 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
// Meta Keys
|
||||
if (is_meta_key)
|
||||
{
|
||||
data.mkey |= button.m_outKeyCode;
|
||||
data.mkey |= out_key_code;
|
||||
|
||||
if (config.read_mode == CELL_KB_RMODE_INPUTCHAR)
|
||||
{
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, true);
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, true);
|
||||
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Led Keys
|
||||
if (code == Key_CapsLock) data.led ^= CELL_KB_LED_CAPS_LOCK;
|
||||
if (code == Key_NumLock) data.led ^= CELL_KB_LED_NUM_LOCK;
|
||||
if (code == Key_ScrollLock) data.led ^= CELL_KB_LED_SCROLL_LOCK;
|
||||
// if (code == Key_Kana_Lock) data.led ^= CELL_KB_LED_KANA;
|
||||
// if (code == ???) data.led ^= CELL_KB_LED_COMPOSE;
|
||||
if (qt_code == Key_CapsLock) data.led ^= CELL_KB_LED_CAPS_LOCK;
|
||||
if (qt_code == Key_NumLock) data.led ^= CELL_KB_LED_NUM_LOCK;
|
||||
if (qt_code == Key_ScrollLock) data.led ^= CELL_KB_LED_SCROLL_LOCK;
|
||||
// if (qt_code == Key_Kana_Lock) data.led ^= CELL_KB_LED_KANA;
|
||||
// if (qt_code == ???) data.led ^= CELL_KB_LED_COMPOSE;
|
||||
|
||||
if (config.read_mode == CELL_KB_RMODE_INPUTCHAR)
|
||||
{
|
||||
data.buttons[0] = KbButton(kcode, button.m_outKeyCode, true);
|
||||
data.buttons[0] = KbButton(kcode, out_key_code, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(kcode, button.m_outKeyCode, true);
|
||||
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(kcode, out_key_code, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,13 +192,13 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
// Meta Keys
|
||||
if (is_meta_key)
|
||||
{
|
||||
data.mkey &= ~button.m_outKeyCode;
|
||||
data.mkey &= ~out_key_code;
|
||||
}
|
||||
|
||||
// Needed to indicate key releases. Without this you have to tap another key before using the same key again
|
||||
if (config.read_mode == CELL_KB_RMODE_INPUTCHAR)
|
||||
{
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, false);
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, false);
|
||||
data.len = 1;
|
||||
}
|
||||
else
|
||||
@ -205,7 +207,7 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
|
||||
for (s32 i = 0; i < data.len; i++)
|
||||
{
|
||||
if (data.buttons[i].m_keyCode == kcode && (!is_meta_key || data.buttons[i].m_outKeyCode == button.m_outKeyCode))
|
||||
if (data.buttons[i].m_keyCode == kcode && (!is_meta_key || data.buttons[i].m_outKeyCode == out_key_code))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
@ -219,7 +221,7 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
|
||||
|
||||
if (data.len <= 1)
|
||||
{
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, false);
|
||||
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, false);
|
||||
}
|
||||
|
||||
data.len = std::max(1, data.len - 1);
|
||||
@ -247,10 +249,32 @@ bool keyboard_consumer::IsMetaKey(u32 code)
|
||||
return code == Key_Control
|
||||
|| code == Key_Shift
|
||||
|| code == Key_Alt
|
||||
|| code == Key_Meta
|
||||
|| code == Key_Super_L
|
||||
|| code == Key_Super_R;
|
||||
}
|
||||
|
||||
u32 keyboard_consumer::get_out_key_code(u32 qt_code, u32 native_code, u32 out_key_code)
|
||||
{
|
||||
// Parse native key codes to differentiate between left and right keys. (Qt sometimes really sucks)
|
||||
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
|
||||
switch (qt_code)
|
||||
{
|
||||
case Key_Control:
|
||||
return native_code == native_key::ctrl_l ? CELL_KB_MKEY_L_CTRL : CELL_KB_MKEY_R_CTRL;
|
||||
case Key_Shift:
|
||||
return native_code == native_key::shift_l ? CELL_KB_MKEY_L_SHIFT : CELL_KB_MKEY_R_SHIFT;
|
||||
case Key_Alt:
|
||||
return native_code == native_key::alt_l ? CELL_KB_MKEY_L_ALT : CELL_KB_MKEY_R_ALT;
|
||||
case Key_Meta:
|
||||
return native_code == native_key::meta_l ? CELL_KB_MKEY_L_WIN : CELL_KB_MKEY_R_WIN;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return out_key_code;
|
||||
}
|
||||
|
||||
void KeyboardHandlerBase::SetIntercepted(bool intercepted)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
@ -282,6 +306,8 @@ void keyboard_consumer::SetIntercepted(bool intercepted)
|
||||
|
||||
void KeyboardHandlerBase::ReleaseAllKeys()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto& [id, consumer] : m_consumers)
|
||||
{
|
||||
consumer.ReleaseAllKeys();
|
||||
@ -294,12 +320,33 @@ void keyboard_consumer::ReleaseAllKeys()
|
||||
{
|
||||
for (const auto& [key_code, button] : keyboard.m_keys)
|
||||
{
|
||||
ConsumeKey(button.m_keyCode, false, false, {});
|
||||
switch (button.m_keyCode)
|
||||
{
|
||||
case Key_Control:
|
||||
ConsumeKey(button.m_keyCode, native_key::ctrl_l, false, false, {});
|
||||
ConsumeKey(button.m_keyCode, native_key::ctrl_r, false, false, {});
|
||||
break;
|
||||
case Key_Shift:
|
||||
ConsumeKey(button.m_keyCode, native_key::shift_l, false, false, {});
|
||||
ConsumeKey(button.m_keyCode, native_key::shift_r, false, false, {});
|
||||
break;
|
||||
case Key_Alt:
|
||||
ConsumeKey(button.m_keyCode, native_key::alt_l, false, false, {});
|
||||
ConsumeKey(button.m_keyCode, native_key::alt_r, false, false, {});
|
||||
break;
|
||||
case Key_Meta:
|
||||
ConsumeKey(button.m_keyCode, native_key::meta_l, false, false, {});
|
||||
ConsumeKey(button.m_keyCode, native_key::meta_r, false, false, {});
|
||||
break;
|
||||
default:
|
||||
ConsumeKey(button.m_keyCode, 0, false, false, {});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::u32string& key : keyboard.m_extra_data.pressed_keys)
|
||||
{
|
||||
ConsumeKey(CELL_KEYC_NO_EVENT, false, false, key);
|
||||
ConsumeKey(CELL_KEYC_NO_EVENT, 0, false, false, key);
|
||||
}
|
||||
|
||||
keyboard.m_extra_data.pressed_keys.clear();
|
||||
|
@ -22,6 +22,39 @@ enum QtKeys
|
||||
Key_Super_R = 0x01000054
|
||||
};
|
||||
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values
|
||||
enum native_key : u32
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ctrl_l = 0x001D,
|
||||
ctrl_r = 0xE01D,
|
||||
shift_l = 0x002A,
|
||||
shift_r = 0x0036,
|
||||
alt_l = 0x0038,
|
||||
alt_r = 0xE038,
|
||||
meta_l = 0xE05B,
|
||||
meta_r = 0xE05C,
|
||||
#elif defined (__APPLE__)
|
||||
ctrl_l = 0x3B, // kVK_Control
|
||||
ctrl_r = 0x3E, // kVK_RightControl
|
||||
shift_l = 0x38, // kVK_Shift
|
||||
shift_r = 0x3C, // kVK_RightShift
|
||||
alt_l = 0x3A, // kVK_Option
|
||||
alt_r = 0x3D, // kVK_RightOption
|
||||
meta_l = 0x37, // kVK_Command
|
||||
meta_r = 0x36, // kVK_RightCommand
|
||||
#else
|
||||
ctrl_l = 0x0025,
|
||||
ctrl_r = 0x0069,
|
||||
shift_l = 0x0032,
|
||||
shift_r = 0x003E,
|
||||
alt_l = 0x0040,
|
||||
alt_r = 0x006C,
|
||||
meta_l = 0x0085,
|
||||
meta_r = 0x0086,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct KbInfo
|
||||
{
|
||||
u32 max_connect = 0;
|
||||
@ -88,7 +121,7 @@ public:
|
||||
keyboard_consumer() {}
|
||||
keyboard_consumer(identifier id) : m_id(id) {}
|
||||
|
||||
bool ConsumeKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key);
|
||||
bool ConsumeKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key);
|
||||
void SetIntercepted(bool intercepted);
|
||||
|
||||
static bool IsMetaKey(u32 code);
|
||||
@ -103,6 +136,8 @@ public:
|
||||
void ReleaseAllKeys();
|
||||
|
||||
protected:
|
||||
u32 get_out_key_code(u32 qt_code, u32 native_code, u32 out_key_code);
|
||||
|
||||
identifier m_id = identifier::unknown;
|
||||
KbInfo m_info{};
|
||||
std::vector<Keyboard> m_keyboards;
|
||||
@ -126,7 +161,7 @@ public:
|
||||
keyboard_consumer& GetConsumer(keyboard_consumer::identifier id);
|
||||
void RemoveConsumer(keyboard_consumer::identifier id);
|
||||
|
||||
bool HandleKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key);
|
||||
bool HandleKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key);
|
||||
void SetIntercepted(bool intercepted);
|
||||
|
||||
stx::init_mutex init;
|
||||
|
@ -9,9 +9,6 @@ using namespace std::chrono_literals;
|
||||
|
||||
LOG_CHANNEL(rb3_midi_drums_log);
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
namespace controller
|
||||
{
|
||||
|
||||
@ -158,67 +155,6 @@ u8 min_velocity()
|
||||
return g_cfg_rb3drums.minimum_velocity;
|
||||
}
|
||||
|
||||
enum class Id : u8
|
||||
{
|
||||
// Each 'Note' can be triggered by multiple different numbers.
|
||||
// Keeping them flattened in an enum for simplicity / switch statement usage.
|
||||
|
||||
// These follow the rockband 3 midi pro adapter support.
|
||||
Snare0 = 38,
|
||||
Snare1 = 31,
|
||||
Snare2 = 34,
|
||||
Snare3 = 37,
|
||||
Snare4 = 39,
|
||||
HiTom0 = 48,
|
||||
HiTom1 = 50,
|
||||
LowTom0 = 45,
|
||||
LowTom1 = 47,
|
||||
FloorTom0 = 41,
|
||||
FloorTom1 = 43,
|
||||
Hihat0 = 22,
|
||||
Hihat1 = 26,
|
||||
Hihat2 = 42,
|
||||
Hihat3 = 54,
|
||||
Ride0 = 51,
|
||||
Ride1 = 53,
|
||||
Ride2 = 56,
|
||||
Ride3 = 59,
|
||||
Crash0 = 49,
|
||||
Crash1 = 52,
|
||||
Crash2 = 55,
|
||||
Crash3 = 57,
|
||||
Kick0 = 33,
|
||||
Kick1 = 35,
|
||||
Kick2 = 36,
|
||||
HihatPedal = 44,
|
||||
|
||||
// These are from alesis nitro mesh max. ymmv.
|
||||
SnareRim = 40, // midi pro adapter counts this as snare.
|
||||
HihatWithPedalUp = 46, // The midi pro adapter considers this a normal hihat hit.
|
||||
HihatPedalPartial = 23, // If pedal is not 100% down, this will be sent instead of a normal hihat hit.
|
||||
|
||||
// Internal value used for converting midi CC.
|
||||
// Values past 127 are not used in midi notes.
|
||||
MidiCC = 255,
|
||||
};
|
||||
|
||||
// Intermediate mapping regardless of which midi ids triggered it.
|
||||
enum class Note : u8
|
||||
{
|
||||
Invalid,
|
||||
Kick,
|
||||
HihatPedal,
|
||||
Snare,
|
||||
SnareRim,
|
||||
HiTom,
|
||||
LowTom,
|
||||
FloorTom,
|
||||
HihatWithPedalUp,
|
||||
Hihat,
|
||||
Ride,
|
||||
Crash,
|
||||
};
|
||||
|
||||
Note str_to_note(const std::string_view name)
|
||||
{
|
||||
static const std::unordered_map<std::string_view, Note> mapping{
|
||||
@ -298,27 +234,21 @@ std::unordered_map<Id, Note> create_id_to_note_mapping()
|
||||
{Id::Crash2, Note::Crash},
|
||||
{Id::Crash3, Note::Crash},
|
||||
};
|
||||
|
||||
// Apply configured overrides.
|
||||
auto split = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","});
|
||||
for (const auto& segment : split)
|
||||
const std::vector<std::string> segments = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","});
|
||||
for (const std::string& segment : segments)
|
||||
{
|
||||
if (auto midi_override = parse_midi_override(segment))
|
||||
if (const auto midi_override = parse_midi_override(segment))
|
||||
{
|
||||
auto id = midi_override->first;
|
||||
auto note = midi_override->second;
|
||||
const auto id = midi_override->first;
|
||||
const auto note = midi_override->second;
|
||||
mapping[id] = note;
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
Note id_to_note(Id id)
|
||||
{
|
||||
static auto mapping = create_id_to_note_mapping();
|
||||
auto it = mapping.find(id);
|
||||
return it != std::end(mapping) ? it->second : Note::Invalid;
|
||||
}
|
||||
|
||||
namespace combo
|
||||
{
|
||||
|
||||
@ -345,39 +275,18 @@ std::vector<u8> parse_combo(const std::string_view name, const std::string_view
|
||||
return notes;
|
||||
}
|
||||
|
||||
struct Definition
|
||||
{
|
||||
std::string name;
|
||||
std::vector<u8> notes;
|
||||
std::function<rb3drums::KitState()> create_state;
|
||||
|
||||
Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state)
|
||||
: name{std::move(name)}
|
||||
, notes{parse_combo(this->name, csv)}
|
||||
, create_state{create_state}
|
||||
{}
|
||||
};
|
||||
|
||||
std::chrono::milliseconds window()
|
||||
{
|
||||
return std::chrono::milliseconds{g_cfg_rb3drums.combo_window_ms};
|
||||
}
|
||||
|
||||
const std::vector<Definition>& definitions()
|
||||
{
|
||||
// Only parse once and cache.
|
||||
static const std::vector<Definition> defs{
|
||||
{"start", g_cfg_rb3drums.combo_start.to_string(), []{ return drum::start_state(); }},
|
||||
{"select", g_cfg_rb3drums.combo_select.to_string(), []{ return drum::select_state(); }},
|
||||
{"hold kick", g_cfg_rb3drums.combo_toggle_hold_kick.to_string(), []{ return drum::toggle_hold_kick_state(); }}
|
||||
};
|
||||
return defs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace midi
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void set_flag(u8* buf, [[maybe_unused]] std::string_view name, const controller::FlagByIndex& fbi)
|
||||
{
|
||||
auto i = fbi[drum::INDEX];
|
||||
@ -397,9 +306,18 @@ void set_flag_if_any(u8* buf, std::string_view name, const controller::FlagByInd
|
||||
|
||||
}
|
||||
|
||||
usb_device_rb3_midi_drums::Definition::Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state)
|
||||
: name{std::move(name)}
|
||||
, notes{midi::combo::parse_combo(this->name, csv)}
|
||||
, create_state{create_state}
|
||||
{}
|
||||
|
||||
usb_device_rb3_midi_drums::usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name)
|
||||
: usb_device_emulated(location)
|
||||
{
|
||||
m_id_to_note_mapping = midi::create_id_to_note_mapping();
|
||||
combo.reload_definitions();
|
||||
|
||||
UsbDeviceDescriptor descriptor{};
|
||||
descriptor.bcdDevice = 0x0200;
|
||||
descriptor.bDeviceClass = 0x00;
|
||||
@ -603,6 +521,12 @@ void usb_device_rb3_midi_drums::interrupt_transfer(u32 buf_size, u8* buf, u32 /*
|
||||
}
|
||||
memcpy(buf, bytes.data(), bytes.size());
|
||||
|
||||
if (g_cfg_rb3drums.reload_requested)
|
||||
{
|
||||
m_id_to_note_mapping = midi::create_id_to_note_mapping();
|
||||
combo.reload_definitions();
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
u8 midi_msg[32];
|
||||
@ -712,6 +636,12 @@ rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_message(u8* msg, usz si
|
||||
return rb3drums::KitState{};
|
||||
}
|
||||
|
||||
midi::Note usb_device_rb3_midi_drums::id_to_note(midi::Id id)
|
||||
{
|
||||
const auto it = m_id_to_note_mapping.find(id);
|
||||
return it != m_id_to_note_mapping.cend() ? it->second : midi::Note::Invalid;
|
||||
}
|
||||
|
||||
rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const u8 velocity)
|
||||
{
|
||||
if (velocity < midi::min_velocity())
|
||||
@ -722,7 +652,7 @@ rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const
|
||||
|
||||
rb3drums::KitState kit_state{};
|
||||
kit_state.expiry = std::chrono::steady_clock::now() + drum::hit_duration();
|
||||
auto note = midi::id_to_note(static_cast<midi::Id>(id));
|
||||
const midi::Note note = id_to_note(static_cast<midi::Id>(id));
|
||||
switch (note)
|
||||
{
|
||||
case midi::Note::Kick: kit_state.kick_pedal = velocity; break;
|
||||
@ -751,7 +681,8 @@ bool usb_device_rb3_midi_drums::is_midi_cc(const u8 id, const u8 value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto is_past_threshold = [](u8 value)
|
||||
|
||||
const auto is_past_threshold = [](u8 value)
|
||||
{
|
||||
const u8 threshold = g_cfg_rb3drums.midi_cc_threshold;
|
||||
return g_cfg_rb3drums.midi_cc_invert_threshold
|
||||
@ -834,6 +765,15 @@ bool rb3drums::KitState::is_drum() const
|
||||
return std::max({snare, hi_tom, low_tom, floor_tom}) >= midi::min_velocity();
|
||||
}
|
||||
|
||||
void usb_device_rb3_midi_drums::ComboTracker::reload_definitions()
|
||||
{
|
||||
m_definitions = {
|
||||
{"start", g_cfg_rb3drums.combo_start.to_string(), []{ return drum::start_state(); }},
|
||||
{"select", g_cfg_rb3drums.combo_select.to_string(), []{ return drum::select_state(); }},
|
||||
{"hold kick", g_cfg_rb3drums.combo_toggle_hold_kick.to_string(), []{ return drum::toggle_hold_kick_state(); }}
|
||||
};
|
||||
}
|
||||
|
||||
void usb_device_rb3_midi_drums::ComboTracker::add(u8 note)
|
||||
{
|
||||
if (!midi_notes.empty() && std::chrono::steady_clock::now() >= expiry)
|
||||
@ -843,9 +783,8 @@ void usb_device_rb3_midi_drums::ComboTracker::add(u8 note)
|
||||
}
|
||||
|
||||
const usz i = midi_notes.size();
|
||||
const auto& defs = midi::combo::definitions();
|
||||
bool is_in_combo = false;
|
||||
for (const auto& def : defs)
|
||||
for (const auto& def : m_definitions)
|
||||
{
|
||||
if (i < def.notes.size() && note == def.notes[i])
|
||||
{
|
||||
@ -879,7 +818,7 @@ std::optional<rb3drums::KitState> usb_device_rb3_midi_drums::ComboTracker::take_
|
||||
{
|
||||
return {};
|
||||
}
|
||||
for (const auto& combo : midi::combo::definitions())
|
||||
for (const auto& combo : m_definitions)
|
||||
{
|
||||
if (midi_notes == combo.notes)
|
||||
{
|
||||
|
@ -38,10 +38,83 @@ struct KitState
|
||||
bool is_drum() const;
|
||||
};
|
||||
|
||||
}; // namespace rb3drums
|
||||
} // namespace rb3drums
|
||||
|
||||
namespace midi
|
||||
{
|
||||
|
||||
enum class Id : u8
|
||||
{
|
||||
// Each 'Note' can be triggered by multiple different numbers.
|
||||
// Keeping them flattened in an enum for simplicity / switch statement usage.
|
||||
|
||||
// These follow the rockband 3 midi pro adapter support.
|
||||
Snare0 = 38,
|
||||
Snare1 = 31,
|
||||
Snare2 = 34,
|
||||
Snare3 = 37,
|
||||
Snare4 = 39,
|
||||
HiTom0 = 48,
|
||||
HiTom1 = 50,
|
||||
LowTom0 = 45,
|
||||
LowTom1 = 47,
|
||||
FloorTom0 = 41,
|
||||
FloorTom1 = 43,
|
||||
Hihat0 = 22,
|
||||
Hihat1 = 26,
|
||||
Hihat2 = 42,
|
||||
Hihat3 = 54,
|
||||
Ride0 = 51,
|
||||
Ride1 = 53,
|
||||
Ride2 = 56,
|
||||
Ride3 = 59,
|
||||
Crash0 = 49,
|
||||
Crash1 = 52,
|
||||
Crash2 = 55,
|
||||
Crash3 = 57,
|
||||
Kick0 = 33,
|
||||
Kick1 = 35,
|
||||
Kick2 = 36,
|
||||
HihatPedal = 44,
|
||||
|
||||
// These are from alesis nitro mesh max. ymmv.
|
||||
SnareRim = 40, // midi pro adapter counts this as snare.
|
||||
HihatWithPedalUp = 46, // The midi pro adapter considers this a normal hihat hit.
|
||||
HihatPedalPartial = 23, // If pedal is not 100% down, this will be sent instead of a normal hihat hit.
|
||||
|
||||
// Internal value used for converting midi CC.
|
||||
// Values past 127 are not used in midi notes.
|
||||
MidiCC = 255,
|
||||
};
|
||||
|
||||
// Intermediate mapping regardless of which midi ids triggered it.
|
||||
enum class Note : u8
|
||||
{
|
||||
Invalid,
|
||||
Kick,
|
||||
HihatPedal,
|
||||
Snare,
|
||||
SnareRim,
|
||||
HiTom,
|
||||
LowTom,
|
||||
FloorTom,
|
||||
HihatWithPedalUp,
|
||||
Hihat,
|
||||
Ride,
|
||||
Crash,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class usb_device_rb3_midi_drums : public usb_device_emulated
|
||||
{
|
||||
public:
|
||||
usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name);
|
||||
~usb_device_rb3_midi_drums();
|
||||
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||
|
||||
private:
|
||||
usz response_pos{};
|
||||
bool buttons_enabled{};
|
||||
@ -50,9 +123,19 @@ private:
|
||||
bool hold_kick{};
|
||||
bool midi_cc_triggered{};
|
||||
|
||||
struct Definition
|
||||
{
|
||||
std::string name;
|
||||
std::vector<u8> notes;
|
||||
std::function<rb3drums::KitState()> create_state;
|
||||
|
||||
Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state);
|
||||
};
|
||||
|
||||
class ComboTracker
|
||||
{
|
||||
public:
|
||||
void reload_definitions();
|
||||
void add(u8 note);
|
||||
void reset();
|
||||
std::optional<rb3drums::KitState> take_state();
|
||||
@ -60,18 +143,15 @@ private:
|
||||
private:
|
||||
std::chrono::steady_clock::time_point expiry;
|
||||
std::vector<u8> midi_notes;
|
||||
std::vector<Definition> m_definitions;
|
||||
};
|
||||
ComboTracker combo;
|
||||
|
||||
std::unordered_map<midi::Id, midi::Note> m_id_to_note_mapping;
|
||||
|
||||
midi::Note id_to_note(midi::Id id);
|
||||
rb3drums::KitState parse_midi_message(u8* msg, usz size);
|
||||
rb3drums::KitState parse_midi_note(u8 id, u8 velocity);
|
||||
bool is_midi_cc(u8 id, u8 value);
|
||||
void write_state(u8* buf, const rb3drums::KitState&);
|
||||
|
||||
public:
|
||||
usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name);
|
||||
~usb_device_rb3_midi_drums();
|
||||
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||
};
|
||||
|
@ -264,7 +264,8 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo
|
||||
buf[1] |= 0x01; // Select
|
||||
break;
|
||||
case turntable_btn::right_turntable:
|
||||
buf[6] = 255 - value; // Right Turntable
|
||||
// DJ Hero does not register input if the turntable is 0, so force it to 1.
|
||||
buf[6] = std::max(1, 255 - value); // Right Turntable
|
||||
// DJ Hero requires turntables to be centered at 128.
|
||||
// If this axis ends up centered at 127, force it to 128.
|
||||
if (buf[6] == 127)
|
||||
|
@ -27,7 +27,7 @@ bool mouse_config::load()
|
||||
return false;
|
||||
}
|
||||
|
||||
void mouse_config::save() const
|
||||
void mouse_config::save()
|
||||
{
|
||||
fs::pending_file file(cfg_name);
|
||||
|
||||
@ -36,6 +36,8 @@ void mouse_config::save() const
|
||||
file.file.write(to_string());
|
||||
file.commit();
|
||||
}
|
||||
|
||||
reload_requested = true;
|
||||
}
|
||||
|
||||
cfg::string& mouse_config::get_button(int code)
|
||||
|
@ -9,18 +9,20 @@ struct mouse_config final : cfg::node
|
||||
|
||||
const std::string cfg_name;
|
||||
|
||||
cfg::string mouse_button_1{this, "Button 1", "Mouse Left"};
|
||||
cfg::string mouse_button_2{this, "Button 2", "Mouse Right"};
|
||||
cfg::string mouse_button_3{this, "Button 3", "Mouse Middle"};
|
||||
cfg::string mouse_button_4{this, "Button 4", ""};
|
||||
cfg::string mouse_button_5{this, "Button 5", ""};
|
||||
cfg::string mouse_button_6{this, "Button 6", ""};
|
||||
cfg::string mouse_button_7{this, "Button 7", ""};
|
||||
cfg::string mouse_button_8{this, "Button 8", ""};
|
||||
cfg::string mouse_button_1{ this, "Button 1", "Mouse Left", true };
|
||||
cfg::string mouse_button_2{ this, "Button 2", "Mouse Right", true };
|
||||
cfg::string mouse_button_3{ this, "Button 3", "Mouse Middle", true };
|
||||
cfg::string mouse_button_4{ this, "Button 4", "", true };
|
||||
cfg::string mouse_button_5{ this, "Button 5", "", true };
|
||||
cfg::string mouse_button_6{ this, "Button 6", "", true };
|
||||
cfg::string mouse_button_7{ this, "Button 7", "", true };
|
||||
cfg::string mouse_button_8{ this, "Button 8", "", true };
|
||||
|
||||
atomic_t<bool> reload_requested = true;
|
||||
|
||||
bool exist() const;
|
||||
bool load();
|
||||
void save() const;
|
||||
void save();
|
||||
|
||||
cfg::string& get_button(int code);
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ bool cfg_rb3drums::load()
|
||||
return false;
|
||||
}
|
||||
|
||||
void cfg_rb3drums::save() const
|
||||
void cfg_rb3drums::save()
|
||||
{
|
||||
cfg_log.notice("Saving rb3drums config to '%s'", path);
|
||||
|
||||
@ -41,4 +41,6 @@ void cfg_rb3drums::save() const
|
||||
{
|
||||
cfg_log.error("Failed to save rb3drums config to '%s' (error=%s)", path, fs::g_tls_error);
|
||||
}
|
||||
|
||||
reload_requested = true;
|
||||
}
|
||||
|
@ -6,22 +6,24 @@ struct cfg_rb3drums final : cfg::node
|
||||
{
|
||||
cfg_rb3drums();
|
||||
bool load();
|
||||
void save() const;
|
||||
void save();
|
||||
|
||||
cfg::uint<1, 100> pulse_ms{this, "Pulse width ms", 30, true};
|
||||
cfg::uint<1, 127> minimum_velocity{this, "Minimum velocity", 10, true};
|
||||
cfg::uint<1, 5000> combo_window_ms{this, "Combo window in milliseconds", 2000, true};
|
||||
cfg::_bool stagger_cymbals{this, "Stagger cymbal hits", true, true};
|
||||
cfg::string midi_overrides{this, "Midi id to note override", ""};
|
||||
cfg::string combo_start{this, "Combo Start", "HihatPedal,HihatPedal,HihatPedal,Snare"};
|
||||
cfg::string combo_select{this, "Combo Select", "HihatPedal,HihatPedal,HihatPedal,SnareRim"};
|
||||
cfg::string combo_toggle_hold_kick{this, "Combo Toggle Hold Kick", "HihatPedal,HihatPedal,HihatPedal,Kick"};
|
||||
cfg::string midi_overrides{this, "Midi id to note override", "", true};
|
||||
cfg::string combo_start{this, "Combo Start", "HihatPedal,HihatPedal,HihatPedal,Snare", true};
|
||||
cfg::string combo_select{this, "Combo Select", "HihatPedal,HihatPedal,HihatPedal,SnareRim", true};
|
||||
cfg::string combo_toggle_hold_kick{this, "Combo Toggle Hold Kick", "HihatPedal,HihatPedal,HihatPedal,Kick", true};
|
||||
cfg::uint<0, 255> midi_cc_status{this, "Midi CC status", 0xB0, true};
|
||||
cfg::uint<0, 127> midi_cc_number{this, "Midi CC control number", 4, true};
|
||||
cfg::uint<0, 127> midi_cc_threshold{this, "Midi CC threshold", 64, true};
|
||||
cfg::_bool midi_cc_invert_threshold{this, "Midi CC invert threshold", false, true};
|
||||
|
||||
const std::string path;
|
||||
|
||||
atomic_t<bool> reload_requested = false;
|
||||
};
|
||||
|
||||
extern cfg_rb3drums g_cfg_rb3drums;
|
||||
|
@ -1549,4 +1549,26 @@ namespace rsx
|
||||
{
|
||||
return get_format_block_size_in_bytes(format) == 2 ? 0xFFFF : 0xFFFFFF;
|
||||
}
|
||||
|
||||
bool is_texcoord_wrapping_mode(rsx::texture_wrap_mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
// Clamping modes
|
||||
default:
|
||||
rsx_log.error("Unknown texture wrap mode: %d", static_cast<int>(mode));
|
||||
[[ fallthrough ]];
|
||||
case rsx::texture_wrap_mode::border:
|
||||
case rsx::texture_wrap_mode::clamp:
|
||||
case rsx::texture_wrap_mode::clamp_to_edge:
|
||||
case rsx::texture_wrap_mode::mirror_once_clamp_to_edge:
|
||||
case rsx::texture_wrap_mode::mirror_once_border:
|
||||
case rsx::texture_wrap_mode::mirror_once_clamp:
|
||||
return false;
|
||||
// Wrapping modes
|
||||
case rsx::texture_wrap_mode::wrap:
|
||||
case rsx::texture_wrap_mode::mirror:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,4 +286,6 @@ namespace rsx
|
||||
|
||||
format_class classify_format(rsx::surface_depth_format2 format);
|
||||
format_class classify_format(u32 gcm_format);
|
||||
|
||||
bool is_texcoord_wrapping_mode(rsx::texture_wrap_mode mode);
|
||||
}
|
||||
|
@ -332,6 +332,9 @@ namespace glsl
|
||||
{ "SEXT_G_BIT" , rsx::texture_control_bits::SEXT_G },
|
||||
{ "SEXT_B_BIT" , rsx::texture_control_bits::SEXT_B },
|
||||
{ "SEXT_A_BIT" , rsx::texture_control_bits::SEXT_A },
|
||||
{ "WRAP_S_BIT", rsx::texture_control_bits::WRAP_S },
|
||||
{ "WRAP_T_BIT", rsx::texture_control_bits::WRAP_T },
|
||||
{ "WRAP_R_BIT", rsx::texture_control_bits::WRAP_R },
|
||||
|
||||
{ "ALPHAKILL ", rsx::texture_control_bits::ALPHAKILL },
|
||||
{ "RENORMALIZE ", rsx::texture_control_bits::RENORMALIZE },
|
||||
|
@ -34,6 +34,9 @@ namespace rsx
|
||||
FILTERED_MIN,
|
||||
UNNORMALIZED_COORDS,
|
||||
CLAMP_TEXCOORDS_BIT,
|
||||
WRAP_S,
|
||||
WRAP_T,
|
||||
WRAP_R,
|
||||
|
||||
GAMMA_CTRL_MASK = (1 << GAMMA_R) | (1 << GAMMA_G) | (1 << GAMMA_B) | (1 << GAMMA_A),
|
||||
EXPAND_MASK = (1 << EXPAND_R) | (1 << EXPAND_G) | (1 << EXPAND_B) | (1 << EXPAND_A),
|
||||
|
@ -27,4 +27,16 @@ vec3 compute2x2DownsampleWeights(const in float coord, const in float uv_step, c
|
||||
return vec3(1.0 - (computed_weights.x + computed_weights.y), computed_weights.xy);
|
||||
}
|
||||
|
||||
vec2 texture2DMSCoord(const in vec2 coords, const in uint flags)
|
||||
{
|
||||
if (0u == (flags & (WRAP_S_MASK | WRAP_T_MASK)))
|
||||
{
|
||||
return coords;
|
||||
}
|
||||
|
||||
const vec2 wrapped_coords = mod(coords, vec2(1.0));
|
||||
const bvec2 wrap_control_mask = bvec2(uvec2(flags) & uvec2(WRAP_S_MASK, WRAP_T_MASK));
|
||||
return _select(coords, wrapped_coords, wrap_control_mask);
|
||||
}
|
||||
|
||||
)"
|
||||
|
@ -12,7 +12,7 @@ vec4 sampleTexture2DMS(in _MSAA_SAMPLER_TYPE_ tex, const in vec2 coords, const i
|
||||
{
|
||||
const uint flags = TEX_FLAGS(index);
|
||||
const vec2 scaled_coords = COORD_SCALE2(index, coords);
|
||||
const vec2 normalized_coords = mod(scaled_coords, vec2(1.0));
|
||||
const vec2 normalized_coords = texture2DMSCoord(scaled_coords, flags);
|
||||
const vec2 sample_count = vec2(2., textureSamples(tex) * 0.5);
|
||||
const vec2 image_size = textureSize(tex) * sample_count;
|
||||
const ivec2 icoords = ivec2(normalized_coords * image_size);
|
||||
|
@ -11,6 +11,9 @@ R"(
|
||||
#define SEXT_G_MASK (1 << SEXT_G_BIT)
|
||||
#define SEXT_B_MASK (1 << SEXT_B_BIT)
|
||||
#define SEXT_A_MASK (1 << SEXT_A_BIT)
|
||||
#define WRAP_S_MASK (1 << WRAP_S_BIT)
|
||||
#define WRAP_T_MASK (1 << WRAP_T_BIT)
|
||||
#define WRAP_R_MASK (1 << WRAP_R_BIT)
|
||||
|
||||
#define GAMMA_CTRL_MASK (GAMMA_R_MASK | GAMMA_G_MASK | GAMMA_B_MASK | GAMMA_A_MASK)
|
||||
#define SIGN_EXPAND_MASK (EXPAND_R_MASK | EXPAND_G_MASK | EXPAND_B_MASK | EXPAND_A_MASK)
|
||||
|
@ -2525,14 +2525,28 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
if (backend_config.supports_hw_msaa &&
|
||||
sampler_descriptors[i]->samples > 1)
|
||||
if (backend_config.supports_hw_msaa && sampler_descriptors[i]->samples > 1)
|
||||
{
|
||||
current_fp_texture_state.multisampled_textures |= (1 << i);
|
||||
texture_control |= (static_cast<u32>(tex.zfunc()) << texture_control_bits::DEPTH_COMPARE_OP);
|
||||
texture_control |= (static_cast<u32>(tex.mag_filter() != rsx::texture_magnify_filter::nearest) << texture_control_bits::FILTERED_MAG);
|
||||
texture_control |= (static_cast<u32>(tex.min_filter() != rsx::texture_minify_filter::nearest) << texture_control_bits::FILTERED_MIN);
|
||||
texture_control |= (((tex.format() & CELL_GCM_TEXTURE_UN) >> 6) << texture_control_bits::UNNORMALIZED_COORDS);
|
||||
|
||||
if (rsx::is_texcoord_wrapping_mode(tex.wrap_s()))
|
||||
{
|
||||
texture_control |= (1 << texture_control_bits::WRAP_S);
|
||||
}
|
||||
|
||||
if (rsx::is_texcoord_wrapping_mode(tex.wrap_t()))
|
||||
{
|
||||
texture_control |= (1 << texture_control_bits::WRAP_T);
|
||||
}
|
||||
|
||||
if (rsx::is_texcoord_wrapping_mode(tex.wrap_r()))
|
||||
{
|
||||
texture_control |= (1 << texture_control_bits::WRAP_R);
|
||||
}
|
||||
}
|
||||
|
||||
if (sampler_descriptors[i]->format_class != RSX_FORMAT_CLASS_COLOR)
|
||||
|
@ -301,14 +301,17 @@ static void fixup_settings(const psf::registry* _psf)
|
||||
}
|
||||
}
|
||||
|
||||
extern void dump_executable(std::span<const u8> data, ppu_module* _module, std::string_view title_id)
|
||||
extern void dump_executable(std::span<const u8> data, const ppu_module* _module, std::string_view title_id)
|
||||
{
|
||||
const std::string_view filename = _module->path.substr(_module->path.find_last_of('/') + 1);
|
||||
std::string_view filename = _module->path;
|
||||
filename = filename.substr(filename.find_last_of('/') + 1);
|
||||
|
||||
const std::string lower = fmt::to_lower(filename);
|
||||
|
||||
// Format filename and directory name
|
||||
// Make each directory for each file so tools like IDA can work on it cleanly
|
||||
const std::string dir_path = fs::get_cache_dir() + "ppu_progs/" + std::string{!title_id.empty() ? title_id : "untitled"} + fmt::format("-%s-%s", fmt::base57(_module->sha1), filename) + '/';
|
||||
const std::string file_path = dir_path + (fmt::to_lower(filename).ends_with(".prx") || fmt::to_lower(filename).ends_with(".sprx") ? "prog.prx" : "exec.elf");
|
||||
const std::string file_path = dir_path + (lower.ends_with(".prx") || lower.ends_with(".sprx") ? "prog.prx" : "exec.elf");
|
||||
|
||||
if (fs::create_dir(dir_path) || fs::g_tls_error == fs::error::exist)
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
|
||||
|
||||
const int key = getUnmodifiedKey(keyEvent);
|
||||
|
||||
if (key < 0 || !HandleKey(static_cast<u32>(key), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||
{
|
||||
keyEvent->ignore();
|
||||
}
|
||||
@ -131,7 +131,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
|
||||
|
||||
const int key = getUnmodifiedKey(keyEvent);
|
||||
|
||||
if (key < 0 || !HandleKey(static_cast<u32>(key), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||
{
|
||||
keyEvent->ignore();
|
||||
}
|
||||
@ -179,17 +179,20 @@ void basic_keyboard_handler::LoadSettings(Keyboard& keyboard)
|
||||
std::vector<KbButton> buttons;
|
||||
|
||||
// Meta Keys
|
||||
//buttons.emplace_back(Qt::Key_Control, CELL_KB_MKEY_L_CTRL);
|
||||
buttons.emplace_back(Qt::Key_Control, CELL_KB_MKEY_L_CTRL);
|
||||
buttons.emplace_back(Qt::Key_Shift, CELL_KB_MKEY_L_SHIFT);
|
||||
buttons.emplace_back(Qt::Key_Alt, CELL_KB_MKEY_L_ALT);
|
||||
buttons.emplace_back(Qt::Key_Super_L, CELL_KB_MKEY_L_WIN);
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_CTRL);
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT);
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_ALT);
|
||||
buttons.emplace_back(Qt::Key_Super_R, CELL_KB_MKEY_R_WIN);
|
||||
buttons.emplace_back(Qt::Key_Meta, CELL_KB_MKEY_L_WIN);
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_CTRL); // There is no way to know if it's left or right in Qt at the moment
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT); // There is no way to know if it's left or right in Qt at the moment
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_ALT); // There is no way to know if it's left or right in Qt at the moment
|
||||
//buttons.emplace_back(, CELL_KB_MKEY_R_WIN); // There is no way to know if it's left or right in Qt at the moment
|
||||
|
||||
buttons.emplace_back(Qt::Key_Super_L, CELL_KB_MKEY_L_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
|
||||
buttons.emplace_back(Qt::Key_Super_R, CELL_KB_MKEY_R_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
|
||||
|
||||
// CELL_KB_RAWDAT
|
||||
//buttons.emplace_back(, CELL_KEYC_NO_EVENT);
|
||||
//buttons.emplace_back(, CELL_KEYC_NO_EVENT); // Redundant, listed for completeness
|
||||
//buttons.emplace_back(, CELL_KEYC_E_ROLLOVER);
|
||||
//buttons.emplace_back(, CELL_KEYC_E_POSTFAIL);
|
||||
//buttons.emplace_back(, CELL_KEYC_E_UNDEF);
|
||||
@ -221,8 +224,8 @@ void basic_keyboard_handler::LoadSettings(Keyboard& keyboard)
|
||||
buttons.emplace_back(Qt::Key_Left, CELL_KEYC_LEFT_ARROW);
|
||||
buttons.emplace_back(Qt::Key_Down, CELL_KEYC_DOWN_ARROW);
|
||||
buttons.emplace_back(Qt::Key_Up, CELL_KEYC_UP_ARROW);
|
||||
//buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_NUM_LOCK);
|
||||
buttons.emplace_back(Qt::Key_Meta, CELL_KEYC_APPLICATION);
|
||||
//buttons.emplace_back(, CELL_KEYC_NUM_LOCK);
|
||||
//buttons.emplace_back(, CELL_KEYC_APPLICATION); // This is probably the PS key on the PS3 keyboard
|
||||
buttons.emplace_back(Qt::Key_Kana_Shift, CELL_KEYC_KANA); // maybe Key_Kana_Lock
|
||||
buttons.emplace_back(Qt::Key_Henkan, CELL_KEYC_HENKAN);
|
||||
buttons.emplace_back(Qt::Key_Muhenkan, CELL_KEYC_MUHENKAN);
|
||||
|
@ -23,14 +23,7 @@ void basic_mouse_handler::Init(const u32 max_connect)
|
||||
g_cfg_mouse.from_default();
|
||||
g_cfg_mouse.load();
|
||||
|
||||
m_buttons[CELL_MOUSE_BUTTON_1] = get_mouse_button(g_cfg_mouse.mouse_button_1);
|
||||
m_buttons[CELL_MOUSE_BUTTON_2] = get_mouse_button(g_cfg_mouse.mouse_button_2);
|
||||
m_buttons[CELL_MOUSE_BUTTON_3] = get_mouse_button(g_cfg_mouse.mouse_button_3);
|
||||
m_buttons[CELL_MOUSE_BUTTON_4] = get_mouse_button(g_cfg_mouse.mouse_button_4);
|
||||
m_buttons[CELL_MOUSE_BUTTON_5] = get_mouse_button(g_cfg_mouse.mouse_button_5);
|
||||
m_buttons[CELL_MOUSE_BUTTON_6] = get_mouse_button(g_cfg_mouse.mouse_button_6);
|
||||
m_buttons[CELL_MOUSE_BUTTON_7] = get_mouse_button(g_cfg_mouse.mouse_button_7);
|
||||
m_buttons[CELL_MOUSE_BUTTON_8] = get_mouse_button(g_cfg_mouse.mouse_button_8);
|
||||
reload_config();
|
||||
|
||||
m_mice.clear();
|
||||
m_mice.emplace_back(Mouse());
|
||||
@ -52,6 +45,18 @@ void basic_mouse_handler::Init(const u32 max_connect)
|
||||
type = mouse_handler::basic;
|
||||
}
|
||||
|
||||
void basic_mouse_handler::reload_config()
|
||||
{
|
||||
m_buttons[CELL_MOUSE_BUTTON_1] = get_mouse_button(g_cfg_mouse.mouse_button_1);
|
||||
m_buttons[CELL_MOUSE_BUTTON_2] = get_mouse_button(g_cfg_mouse.mouse_button_2);
|
||||
m_buttons[CELL_MOUSE_BUTTON_3] = get_mouse_button(g_cfg_mouse.mouse_button_3);
|
||||
m_buttons[CELL_MOUSE_BUTTON_4] = get_mouse_button(g_cfg_mouse.mouse_button_4);
|
||||
m_buttons[CELL_MOUSE_BUTTON_5] = get_mouse_button(g_cfg_mouse.mouse_button_5);
|
||||
m_buttons[CELL_MOUSE_BUTTON_6] = get_mouse_button(g_cfg_mouse.mouse_button_6);
|
||||
m_buttons[CELL_MOUSE_BUTTON_7] = get_mouse_button(g_cfg_mouse.mouse_button_7);
|
||||
m_buttons[CELL_MOUSE_BUTTON_8] = get_mouse_button(g_cfg_mouse.mouse_button_8);
|
||||
}
|
||||
|
||||
/* Sets the target window for the event handler, and also installs an event filter on the target. */
|
||||
void basic_mouse_handler::SetTargetWindow(QWindow* target)
|
||||
{
|
||||
@ -80,6 +85,11 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
|
||||
// !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target)
|
||||
if (!m_target || !m_target->isVisible() || target == m_target)
|
||||
{
|
||||
if (g_cfg_mouse.reload_requested.exchange(false))
|
||||
{
|
||||
reload_config();
|
||||
}
|
||||
|
||||
switch (ev->type())
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
|
@ -27,9 +27,10 @@ public:
|
||||
|
||||
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||||
private:
|
||||
QWindow* m_target = nullptr;
|
||||
void reload_config();
|
||||
bool get_mouse_lock_state() const;
|
||||
static int get_mouse_button(const cfg::string& button);
|
||||
|
||||
QWindow* m_target = nullptr;
|
||||
std::map<u8, int> m_buttons;
|
||||
};
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
LOG_CHANNEL(ds3_log, "DS3");
|
||||
|
||||
using namespace reports;
|
||||
|
||||
constexpr std::array<u8, 6> battery_capacity = {0, 1, 25, 50, 75, 100};
|
||||
|
||||
constexpr id_pair SONY_DS3_ID_0 = {0x054C, 0x0268};
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
namespace reports
|
||||
{
|
||||
struct ds3_rumble
|
||||
{
|
||||
@ -53,10 +53,10 @@ namespace
|
||||
u8 unknown_3[4];
|
||||
u8 battery_status;
|
||||
u8 unknown_4[10];
|
||||
le_t<u16, 1> gyro;
|
||||
le_t<u16, 1> accel_x;
|
||||
le_t<u16, 1> accel_z;
|
||||
le_t<u16, 1> accel_y;
|
||||
le_t<u16, 1> gyro;
|
||||
};
|
||||
static_assert(sizeof(ds3_input_report) == 49);
|
||||
}
|
||||
@ -67,7 +67,7 @@ public:
|
||||
#ifdef _WIN32
|
||||
u8 report_id = 0;
|
||||
#endif
|
||||
ds3_input_report report{};
|
||||
reports::ds3_input_report report{};
|
||||
};
|
||||
|
||||
class ds3_pad_handler final : public hid_pad_handler<ds3_device>
|
||||
|
@ -2,8 +2,12 @@
|
||||
#include "ds4_pad_handler.h"
|
||||
#include "Emu/Io/pad_config.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
LOG_CHANNEL(ds4_log, "DS4");
|
||||
|
||||
using namespace reports;
|
||||
|
||||
constexpr id_pair SONY_DS4_ID_0 = {0x054C, 0x0BA0}; // Dongle
|
||||
constexpr id_pair SONY_DS4_ID_1 = {0x054C, 0x05C4}; // CUH-ZCT1x
|
||||
constexpr id_pair SONY_DS4_ID_2 = {0x054C, 0x09CC}; // CUH-ZCT2x
|
||||
@ -427,7 +431,6 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) const
|
||||
pitchNeg >= 0 || yawNeg >= 0 || rollNeg >= 0)
|
||||
{
|
||||
ds4_log.error("GetCalibrationData: calibration data check failed! pitchPlus=%d, pitchNeg=%d, rollPlus=%d, rollNeg=%d, yawPlus=%d, yawNeg=%d", pitchPlus, pitchNeg, rollPlus, rollNeg, yawPlus, yawNeg);
|
||||
return false;
|
||||
}
|
||||
|
||||
const s32 gyroSpeedScale = read_s16(&buf[19]) + read_s16(&buf[21]);
|
||||
@ -465,12 +468,16 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) const
|
||||
|
||||
// Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected
|
||||
|
||||
for (const auto& data : ds4Dev->calib_data)
|
||||
for (size_t i = 0; i < ds4Dev->calib_data.size(); i++)
|
||||
{
|
||||
CalibData& data = ds4Dev->calib_data[i];
|
||||
|
||||
if (data.sens_denom == 0)
|
||||
{
|
||||
ds4_log.error("GetCalibrationData: Failure: sens_denom == 0");
|
||||
return false;
|
||||
ds4_log.error("GetCalibrationData: Invalid accelerometer calibration data for axis %d, disabling calibration.", i);
|
||||
data.bias = 0;
|
||||
data.sens_numer = 4 * DS4_ACC_RES_PER_G;
|
||||
data.sens_denom = std::numeric_limits<s16>::max();
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,13 +700,13 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device)
|
||||
|
||||
if (device->has_calib_data)
|
||||
{
|
||||
int calibOffset = offset + offsetof(ds4_input_report_common, gyro);
|
||||
int calib_offset = offset + offsetof(ds4_input_report_common, gyro);
|
||||
for (int i = 0; i < CalibIndex::COUNT; ++i)
|
||||
{
|
||||
const s16 rawValue = read_s16(&buf[calibOffset]);
|
||||
const s16 calValue = apply_calibration(rawValue, device->calib_data[i]);
|
||||
buf[calibOffset++] = (static_cast<u16>(calValue) >> 0) & 0xFF;
|
||||
buf[calibOffset++] = (static_cast<u16>(calValue) >> 8) & 0xFF;
|
||||
const s16 raw_value = read_s16(&buf[calib_offset]);
|
||||
const s16 cal_value = apply_calibration(raw_value, device->calib_data[i]);
|
||||
buf[calib_offset++] = (static_cast<u16>(cal_value) >> 0) & 0xFF;
|
||||
buf[calib_offset++] = (static_cast<u16>(cal_value) >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
namespace reports
|
||||
{
|
||||
constexpr u32 DS4_ACC_RES_PER_G = 8192;
|
||||
constexpr u32 DS4_GYRO_RES_PER_DEG_S = 86; // technically this could be 1024, but keeping it at 86 keeps us within 16 bits of precision
|
||||
@ -119,8 +119,8 @@ public:
|
||||
bool bt_controller{false};
|
||||
bool has_calib_data{false};
|
||||
std::array<CalibData, CalibIndex::COUNT> calib_data{};
|
||||
ds4_input_report_usb report_usb{};
|
||||
ds4_input_report_bt report_bt{};
|
||||
reports::ds4_input_report_usb report_usb{};
|
||||
reports::ds4_input_report_bt report_bt{};
|
||||
};
|
||||
|
||||
class ds4_pad_handler final : public hid_pad_handler<DS4Device>
|
||||
|
@ -2,8 +2,12 @@
|
||||
#include "dualsense_pad_handler.h"
|
||||
#include "Emu/Io/pad_config.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
LOG_CHANNEL(dualsense_log, "DualSense");
|
||||
|
||||
using namespace reports;
|
||||
|
||||
template <>
|
||||
void fmt_class_string<DualSenseDevice::DualSenseDataMode>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@ -430,31 +434,12 @@ bool dualsense_pad_handler::get_calibration_data(DualSenseDevice* dualsense_devi
|
||||
dualsense_device->calib_data[CalibIndex::YAW].bias = read_s16(&buf[3]);
|
||||
dualsense_device->calib_data[CalibIndex::ROLL].bias = read_s16(&buf[5]);
|
||||
|
||||
s16 pitch_plus, pitch_minus, roll_plus, roll_minus, yaw_plus, yaw_minus;
|
||||
|
||||
// TODO: This was copied from DS4. Find out if it applies here.
|
||||
// Check for calibration data format
|
||||
// It's going to be either alternating +/- or +++---
|
||||
if (read_s16(&buf[9]) < 0 && read_s16(&buf[7]) > 0)
|
||||
{
|
||||
// Wired mode for OEM controllers
|
||||
pitch_plus = read_s16(&buf[7]);
|
||||
pitch_minus = read_s16(&buf[9]);
|
||||
yaw_plus = read_s16(&buf[11]);
|
||||
yaw_minus = read_s16(&buf[13]);
|
||||
roll_plus = read_s16(&buf[15]);
|
||||
roll_minus = read_s16(&buf[17]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bluetooth mode and wired mode for some 3rd party controllers
|
||||
pitch_plus = read_s16(&buf[7]);
|
||||
yaw_plus = read_s16(&buf[9]);
|
||||
roll_plus = read_s16(&buf[11]);
|
||||
pitch_minus = read_s16(&buf[13]);
|
||||
yaw_minus = read_s16(&buf[15]);
|
||||
roll_minus = read_s16(&buf[17]);
|
||||
}
|
||||
const s16 pitch_plus = read_s16(&buf[7]);
|
||||
const s16 pitch_minus = read_s16(&buf[9]);
|
||||
const s16 yaw_plus = read_s16(&buf[11]);
|
||||
const s16 yaw_minus = read_s16(&buf[13]);
|
||||
const s16 roll_plus = read_s16(&buf[15]);
|
||||
const s16 roll_minus = read_s16(&buf[17]);
|
||||
|
||||
// Confirm correctness. Need confirmation with dongle with no active controller
|
||||
if (pitch_plus <= 0 || yaw_plus <= 0 || roll_plus <= 0 ||
|
||||
@ -462,7 +447,6 @@ bool dualsense_pad_handler::get_calibration_data(DualSenseDevice* dualsense_devi
|
||||
{
|
||||
dualsense_log.error("get_calibration_data: calibration data check failed! pitch_plus=%d, pitch_minus=%d, roll_plus=%d, roll_minus=%d, yaw_plus=%d, yaw_minus=%d",
|
||||
pitch_plus, pitch_minus, roll_plus, roll_minus, yaw_plus, yaw_minus);
|
||||
return false;
|
||||
}
|
||||
|
||||
const s32 gyro_speed_scale = read_s16(&buf[19]) + read_s16(&buf[21]);
|
||||
@ -501,12 +485,16 @@ bool dualsense_pad_handler::get_calibration_data(DualSenseDevice* dualsense_devi
|
||||
|
||||
// Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected
|
||||
|
||||
for (const CalibData& data : dualsense_device->calib_data)
|
||||
for (size_t i = 0; i < dualsense_device->calib_data.size(); i++)
|
||||
{
|
||||
CalibData& data = dualsense_device->calib_data[i];
|
||||
|
||||
if (data.sens_denom == 0)
|
||||
{
|
||||
dualsense_log.error("get_calibration_data: Failure: sens_denom == 0");
|
||||
return false;
|
||||
dualsense_log.error("GetCalibrationData: Invalid accelerometer calibration data for axis %d, disabling calibration.", i);
|
||||
data.bias = 0;
|
||||
data.sens_numer = 4 * DUALSENSE_ACC_RES_PER_G;
|
||||
data.sens_denom = std::numeric_limits<s16>::max();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
namespace reports
|
||||
{
|
||||
constexpr u32 DUALSENSE_ACC_RES_PER_G = 8192;
|
||||
constexpr u32 DUALSENSE_GYRO_RES_PER_DEG_S = 86; // technically this could be 1024, but keeping it at 86 keeps us within 16 bits of precision
|
||||
@ -172,7 +172,7 @@ public:
|
||||
u8 bt_sequence{0};
|
||||
bool has_calib_data{false};
|
||||
std::array<CalibData, CalibIndex::COUNT> calib_data{};
|
||||
dualsense_input_report_common report{}; // No need to have separate reports for usb and bluetooth
|
||||
reports::dualsense_input_report_common report{}; // No need to have separate reports for usb and bluetooth
|
||||
DualSenseDataMode data_mode{DualSenseDataMode::Simple};
|
||||
DualSenseFeatureSet feature_set{DualSenseFeatureSet::Normal};
|
||||
bool init_lightbar{true};
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
struct CalibData
|
||||
{
|
||||
s16 bias;
|
||||
s32 sens_numer;
|
||||
s32 sens_denom;
|
||||
s16 bias = 0;
|
||||
s32 sens_numer = 0;
|
||||
s32 sens_denom = 0;
|
||||
};
|
||||
|
||||
enum CalibIndex
|
||||
@ -87,12 +87,12 @@ protected:
|
||||
virtual int send_output_report(Device* device) = 0;
|
||||
virtual DataStatus get_data(Device* device) = 0;
|
||||
|
||||
static s16 apply_calibration(s32 rawValue, const CalibData& calibData)
|
||||
static s16 apply_calibration(s32 raw_value, const CalibData& calib_data)
|
||||
{
|
||||
const s32 biased = rawValue - calibData.bias;
|
||||
const s32 quot = calibData.sens_numer / calibData.sens_denom;
|
||||
const s32 rem = calibData.sens_numer % calibData.sens_denom;
|
||||
const s32 output = (quot * biased) + ((rem * biased) / calibData.sens_denom);
|
||||
const s32 biased = raw_value - calib_data.bias;
|
||||
const s32 quot = calib_data.sens_numer / calib_data.sens_denom;
|
||||
const s32 rem = calib_data.sens_numer % calib_data.sens_denom;
|
||||
const s32 output = (quot * biased) + ((rem * biased) / calib_data.sens_denom);
|
||||
|
||||
return static_cast<s16>(std::clamp<s32>(output, s16{smin}, s16{smax}));
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "keyboard_pad_handler.h"
|
||||
#include "pad_thread.h"
|
||||
#include "Emu/Io/pad_config.h"
|
||||
#include "Emu/Io/KeyboardHandler.h"
|
||||
#include "Input/product_info.h"
|
||||
#include "rpcs3qt/gs_frame.h"
|
||||
|
||||
@ -821,12 +822,16 @@ u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
|
||||
|
||||
int keyboard_pad_handler::native_scan_code_from_string([[maybe_unused]] const std::string& key)
|
||||
{
|
||||
// NOTE: Qt throws a Ctrl key at us when using Alt Gr, so there is no point in distinguishing left and right Alt at the moment
|
||||
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
|
||||
if (key == "Shift Left") return native_key::shift_l;
|
||||
if (key == "Shift Right") return native_key::shift_r;
|
||||
if (key == "Ctrl Left") return native_key::ctrl_l;
|
||||
if (key == "Ctrl Right") return native_key::ctrl_r;
|
||||
if (key == "Alt Left") return native_key::alt_l;
|
||||
if (key == "Alt Right") return native_key::alt_r;
|
||||
if (key == "Meta Left") return native_key::meta_l;
|
||||
if (key == "Meta Right") return native_key::meta_r;
|
||||
#ifdef _WIN32
|
||||
if (key == "Shift Left") return 42;
|
||||
if (key == "Shift Right") return 54;
|
||||
if (key == "Ctrl Left") return 29;
|
||||
if (key == "Ctrl Right") return 285;
|
||||
if (key == "Num+0" || key == "Num+Ins") return 82;
|
||||
if (key == "Num+1" || key == "Num+End") return 79;
|
||||
if (key == "Num+2" || key == "Num+Down") return 80;
|
||||
@ -851,15 +856,20 @@ int keyboard_pad_handler::native_scan_code_from_string([[maybe_unused]] const st
|
||||
|
||||
std::string keyboard_pad_handler::native_scan_code_to_string(int native_scan_code)
|
||||
{
|
||||
// NOTE: the other Qt function "nativeVirtualKey" does not distinguish between VK_SHIFT and VK_RSHIFT key in Qt at the moment
|
||||
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
|
||||
// NOTE: for MacOs: nativeScanCode may not work
|
||||
switch (native_scan_code)
|
||||
{
|
||||
case native_key::shift_l: return "Shift Left";
|
||||
case native_key::shift_r: return "Shift Right";
|
||||
case native_key::ctrl_l: return "Ctrl Left";
|
||||
case native_key::ctrl_r: return "Ctrl Right";
|
||||
case native_key::alt_l: return "Alt Left";
|
||||
case native_key::alt_r: return "Alt Right";
|
||||
case native_key::meta_l: return "Meta Left";
|
||||
case native_key::meta_r: return "Meta Right";
|
||||
#ifdef _WIN32
|
||||
// NOTE: the other Qt function "nativeVirtualKey" does not distinguish between VK_SHIFT and VK_RSHIFT key in Qt at the moment
|
||||
// NOTE: Qt throws a Ctrl key at us when using Alt Gr, so there is no point in distinguishing left and right Alt at the moment
|
||||
case 42: return "Shift Left";
|
||||
case 54: return "Shift Right";
|
||||
case 29: return "Ctrl Left";
|
||||
case 285: return "Ctrl Right";
|
||||
case 82: return "Num+0"; // Also "Num+Ins" depending on numlock
|
||||
case 79: return "Num+1"; // Also "Num+End" depending on numlock
|
||||
case 80: return "Num+2"; // Also "Num+Down" depending on numlock
|
||||
@ -878,7 +888,6 @@ std::string keyboard_pad_handler::native_scan_code_to_string(int native_scan_cod
|
||||
case 284: return "Num+Enter";
|
||||
#else
|
||||
// TODO
|
||||
// NOTE for MacOs: nativeScanCode may not work
|
||||
#endif
|
||||
default: return "";
|
||||
}
|
||||
|
@ -102,4 +102,6 @@ void raw_mice_config::save()
|
||||
{
|
||||
cfg_log.error("Failed to save %s config to '%s' (error=%s)", cfg_id, cfg_name, fs::g_tls_error);
|
||||
}
|
||||
|
||||
reload_requested = true;
|
||||
}
|
||||
|
@ -18,14 +18,14 @@ public:
|
||||
|
||||
cfg::_float<10, 1000> mouse_acceleration{ this, "Mouse Acceleration", 100.0f, true };
|
||||
|
||||
cfg::string mouse_button_1{this, "Button 1", "Button 1"};
|
||||
cfg::string mouse_button_2{this, "Button 2", "Button 2"};
|
||||
cfg::string mouse_button_3{this, "Button 3", "Button 3"};
|
||||
cfg::string mouse_button_4{this, "Button 4", "Button 4"};
|
||||
cfg::string mouse_button_5{this, "Button 5", "Button 5"};
|
||||
cfg::string mouse_button_6{this, "Button 6", ""};
|
||||
cfg::string mouse_button_7{this, "Button 7", ""};
|
||||
cfg::string mouse_button_8{this, "Button 8", ""};
|
||||
cfg::string mouse_button_1{ this, "Button 1", "Button 1", true };
|
||||
cfg::string mouse_button_2{ this, "Button 2", "Button 2", true };
|
||||
cfg::string mouse_button_3{ this, "Button 3", "Button 3", true };
|
||||
cfg::string mouse_button_4{ this, "Button 4", "Button 4", true };
|
||||
cfg::string mouse_button_5{ this, "Button 5", "Button 5", true };
|
||||
cfg::string mouse_button_6{ this, "Button 6", "", true };
|
||||
cfg::string mouse_button_7{ this, "Button 7", "", true };
|
||||
cfg::string mouse_button_8{ this, "Button 8", "", true };
|
||||
|
||||
cfg::string& get_button_by_index(int index);
|
||||
cfg::string& get_button(int code);
|
||||
@ -38,6 +38,7 @@ struct raw_mice_config : cfg::node
|
||||
shared_mutex m_mutex;
|
||||
static constexpr std::string_view cfg_id = "raw_mouse";
|
||||
std::array<std::shared_ptr<raw_mouse_config>, 4> players;
|
||||
atomic_t<bool> reload_requested = false;
|
||||
|
||||
bool load();
|
||||
void save();
|
||||
|
@ -35,6 +35,15 @@ u32 g_registered_handlers = 0;
|
||||
|
||||
raw_mouse::raw_mouse(u32 index, const std::string& device_name, void* handle, raw_mouse_handler* handler)
|
||||
: m_index(index), m_device_name(device_name), m_handle(handle), m_handler(handler)
|
||||
{
|
||||
reload_config();
|
||||
}
|
||||
|
||||
raw_mouse::~raw_mouse()
|
||||
{
|
||||
}
|
||||
|
||||
void raw_mouse::reload_config()
|
||||
{
|
||||
if (m_index < ::size32(g_cfg_raw_mouse.players))
|
||||
{
|
||||
@ -54,10 +63,6 @@ raw_mouse::raw_mouse(u32 index, const std::string& device_name, void* handle, ra
|
||||
}
|
||||
}
|
||||
|
||||
raw_mouse::~raw_mouse()
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<int, int> raw_mouse::get_mouse_button(const cfg::string& button)
|
||||
{
|
||||
const std::string value = button.to_string();
|
||||
@ -119,6 +124,11 @@ void raw_mouse::update_values(const RAWMOUSE& state)
|
||||
// Update window handle and size
|
||||
update_window_handle();
|
||||
|
||||
if (std::exchange(reload_requested, false))
|
||||
{
|
||||
reload_config();
|
||||
}
|
||||
|
||||
const auto get_button_pressed = [this](u8 button, int button_flags)
|
||||
{
|
||||
const auto& [down, up] = ::at32(m_buttons, button);
|
||||
@ -142,6 +152,9 @@ void raw_mouse::update_values(const RAWMOUSE& state)
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_3, state.usButtonFlags);
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_4, state.usButtonFlags);
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_5, state.usButtonFlags);
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_6, state.usButtonFlags);
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_7, state.usButtonFlags);
|
||||
get_button_pressed(CELL_MOUSE_BUTTON_8, state.usButtonFlags);
|
||||
|
||||
// Get mouse wheel
|
||||
if ((state.usButtonFlags & RI_MOUSE_WHEEL))
|
||||
@ -556,6 +569,14 @@ void raw_mouse_handler::handle_native_event(const MSG& msg)
|
||||
{
|
||||
std::lock_guard lock(m_raw_mutex);
|
||||
|
||||
if (g_cfg_raw_mouse.reload_requested.exchange(false))
|
||||
{
|
||||
for (auto& [handle, mouse] : m_raw_mice)
|
||||
{
|
||||
mouse.request_reload();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto it = m_raw_mice.find(raw_input.header.hDevice); it != m_raw_mice.end())
|
||||
{
|
||||
it->second.update_values(raw_input.data.mouse);
|
||||
|
@ -43,8 +43,10 @@ public:
|
||||
const std::string& device_name() const { return m_device_name; }
|
||||
u32 index() const { return m_index; }
|
||||
void set_index(u32 index) { m_index = index; }
|
||||
void request_reload() { reload_requested = true; }
|
||||
|
||||
private:
|
||||
void reload_config();
|
||||
static std::pair<int, int> get_mouse_button(const cfg::string& button);
|
||||
|
||||
u32 m_index = 0;
|
||||
@ -60,6 +62,7 @@ private:
|
||||
float m_mouse_acceleration = 1.0f;
|
||||
raw_mouse_handler* m_handler{};
|
||||
std::map<u8, std::pair<int, int>> m_buttons;
|
||||
bool reload_requested = false;
|
||||
};
|
||||
|
||||
class raw_mouse_handler final : public MouseHandlerBase
|
||||
|
@ -9,8 +9,110 @@
|
||||
|
||||
LOG_CHANNEL(sdl_log, "SDL");
|
||||
|
||||
std::mutex g_sdl_mutex;
|
||||
u32 g_sdl_handler_count = 0;
|
||||
struct sdl_instance
|
||||
{
|
||||
public:
|
||||
sdl_instance() = default;
|
||||
~sdl_instance()
|
||||
{
|
||||
// Only quit SDL once on exit. SDL uses a global state internally...
|
||||
if (m_initialized)
|
||||
{
|
||||
sdl_log.notice("Quitting SDL ...");
|
||||
SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize()
|
||||
{
|
||||
// Only init SDL once. SDL uses a global state internally...
|
||||
if (m_initialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sdl_log.notice("Initializing SDL ...");
|
||||
|
||||
// Set non-dynamic hints before SDL_Init
|
||||
if (!SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1"))
|
||||
{
|
||||
sdl_log.error("Could not set SDL_HINT_JOYSTICK_THREAD: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) < 0)
|
||||
{
|
||||
sdl_log.error("Could not initialize! SDL Error: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
|
||||
SDL_LogSetOutputFunction([](void*, int category, SDL_LogPriority priority, const char* message)
|
||||
{
|
||||
std::string category_name;
|
||||
switch (category)
|
||||
{
|
||||
case SDL_LOG_CATEGORY_APPLICATION:
|
||||
category_name = "app";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_ERROR:
|
||||
category_name = "error";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_ASSERT:
|
||||
category_name = "assert";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_SYSTEM:
|
||||
category_name = "system";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_AUDIO:
|
||||
category_name = "audio";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_VIDEO:
|
||||
category_name = "video";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_RENDER:
|
||||
category_name = "render";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_INPUT:
|
||||
category_name = "input";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_TEST:
|
||||
category_name = "test";
|
||||
break;
|
||||
default:
|
||||
category_name = fmt::format("unknown(%d)", category);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (priority)
|
||||
{
|
||||
case SDL_LOG_PRIORITY_VERBOSE:
|
||||
case SDL_LOG_PRIORITY_DEBUG:
|
||||
sdl_log.trace("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_INFO:
|
||||
sdl_log.notice("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_WARN:
|
||||
sdl_log.warning("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_ERROR:
|
||||
sdl_log.error("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_CRITICAL:
|
||||
sdl_log.error("%s: %s", category_name, message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, nullptr);
|
||||
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
constexpr u32 rumble_duration_ms = 500; // Some high number to keep rumble updates at a minimum.
|
||||
constexpr u32 rumble_refresh_ms = rumble_duration_ms - 100; // We need to keep updating the rumble. Choose a refresh timeout that is unlikely to run into missed rumble updates.
|
||||
@ -87,14 +189,6 @@ sdl_pad_handler::~sdl_pad_handler()
|
||||
controller.second->sdl.game_controller = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Only quit SDL if this is the last instance of the handler. SDL uses a global state internally...
|
||||
std::lock_guard lock(g_sdl_mutex);
|
||||
if (g_sdl_handler_count > 0 && --g_sdl_handler_count == 0)
|
||||
{
|
||||
sdl_log.notice("Quitting SDL ...");
|
||||
SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_pad_handler::init_config(cfg_pad* cfg)
|
||||
@ -159,86 +253,9 @@ bool sdl_pad_handler::Init()
|
||||
if (m_is_init)
|
||||
return true;
|
||||
|
||||
std::lock_guard lock(g_sdl_mutex);
|
||||
|
||||
// Only init SDL if this is the first instance of the handler. SDL uses a global state internally...
|
||||
if (g_sdl_handler_count++ == 0)
|
||||
{
|
||||
sdl_log.notice("Initializing SDL ...");
|
||||
|
||||
// Set non-dynamic hints before SDL_Init
|
||||
if (!SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1"))
|
||||
{
|
||||
sdl_log.error("Could not set SDL_HINT_JOYSTICK_THREAD: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) < 0)
|
||||
{
|
||||
sdl_log.error("Could not initialize! SDL Error: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
|
||||
SDL_LogSetOutputFunction([](void*, int category, SDL_LogPriority priority, const char* message)
|
||||
{
|
||||
std::string category_name;
|
||||
switch (category)
|
||||
{
|
||||
case SDL_LOG_CATEGORY_APPLICATION:
|
||||
category_name = "app";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_ERROR:
|
||||
category_name = "error";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_ASSERT:
|
||||
category_name = "assert";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_SYSTEM:
|
||||
category_name = "system";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_AUDIO:
|
||||
category_name = "audio";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_VIDEO:
|
||||
category_name = "video";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_RENDER:
|
||||
category_name = "render";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_INPUT:
|
||||
category_name = "input";
|
||||
break;
|
||||
case SDL_LOG_CATEGORY_TEST:
|
||||
category_name = "test";
|
||||
break;
|
||||
default:
|
||||
category_name = fmt::format("unknown(%d)", category);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (priority)
|
||||
{
|
||||
case SDL_LOG_PRIORITY_VERBOSE:
|
||||
case SDL_LOG_PRIORITY_DEBUG:
|
||||
sdl_log.trace("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_INFO:
|
||||
sdl_log.notice("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_WARN:
|
||||
sdl_log.warning("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_ERROR:
|
||||
sdl_log.error("%s: %s", category_name, message);
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_CRITICAL:
|
||||
sdl_log.error("%s: %s", category_name, message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, nullptr);
|
||||
}
|
||||
static sdl_instance s_sdl_instance {};
|
||||
if (!s_sdl_instance.initialize())
|
||||
return false;
|
||||
|
||||
if (g_cfg.io.load_sdl_mappings)
|
||||
{
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
LOG_CHANNEL(skateboard_log, "Skateboard");
|
||||
|
||||
using namespace reports;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr id_pair SKATEBOARD_ID_0 = {0x12BA, 0x0400}; // Tony Hawk RIDE Skateboard
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
namespace reports
|
||||
{
|
||||
// Descriptor
|
||||
// 0x09, 0x05, // Usage (0x05)
|
||||
@ -143,7 +143,7 @@ class skateboard_device : public HidDevice
|
||||
{
|
||||
public:
|
||||
bool skateboard_is_on = false;
|
||||
skateboard_input_report report{};
|
||||
reports::skateboard_input_report report{};
|
||||
};
|
||||
|
||||
class skateboard_pad_handler final : public hid_pad_handler<skateboard_device>
|
||||
|
@ -64,6 +64,7 @@ std::unique_ptr<raw_mouse_handler> g_raw_mouse_handler;
|
||||
|
||||
gui_application::gui_application(int& argc, char** argv) : QApplication(argc, argv)
|
||||
{
|
||||
std::setlocale(LC_NUMERIC, "C"); // On linux Qt changes to system locale while initializing QCoreApplication
|
||||
}
|
||||
|
||||
gui_application::~gui_application()
|
||||
|
@ -88,8 +88,8 @@ const std::map<const std::pair<const u16, const u16>, const std::string> list_sk
|
||||
{{20, 0x0000}, "Drobot"},
|
||||
{{20, 0x1801}, "Series 2 Drobot"},
|
||||
{{20, 0x1206}, "LightCore Drobot"},
|
||||
{{21, 0x0000}, "Drill Seargeant"},
|
||||
{{21, 0x1801}, "Series 2 Drill Seargeant"},
|
||||
{{21, 0x0000}, "Drill Sergeant"},
|
||||
{{21, 0x1801}, "Series 2 Drill Sergeant"},
|
||||
{{22, 0x0000}, "Boomer"},
|
||||
{{22, 0x4810}, "Eon's Elite Boomer"},
|
||||
{{23, 0x0000}, "Wrecking Ball"},
|
||||
@ -748,9 +748,9 @@ skylander_dialog* skylander_dialog::get_dlg(QWidget* parent)
|
||||
|
||||
void skylander_dialog::clear_skylander(u8 slot)
|
||||
{
|
||||
if (auto slot_infos = sky_slots[slot])
|
||||
if (const auto& slot_infos = sky_slots[slot])
|
||||
{
|
||||
auto [cur_slot, id, var] = slot_infos.value();
|
||||
const auto& [cur_slot, id, var] = slot_infos.value();
|
||||
g_skyportal.remove_skylander(cur_slot);
|
||||
sky_slots[slot] = {};
|
||||
update_edits();
|
||||
@ -811,10 +811,10 @@ void skylander_dialog::update_edits()
|
||||
for (auto i = 0; i < UI_SKY_NUM; i++)
|
||||
{
|
||||
QString display_string;
|
||||
if (auto sd = sky_slots[i])
|
||||
if (const auto& sd = sky_slots[i])
|
||||
{
|
||||
auto [portal_slot, sky_id, sky_var] = sd.value();
|
||||
auto found_sky = list_skylanders.find(std::make_pair(sky_id, sky_var));
|
||||
const auto& [portal_slot, sky_id, sky_var] = sd.value();
|
||||
const auto found_sky = list_skylanders.find(std::make_pair(sky_id, sky_var));
|
||||
if (found_sky != list_skylanders.end())
|
||||
{
|
||||
display_string = QString::fromStdString(found_sky->second);
|
||||
|
Loading…
Reference in New Issue
Block a user