1
0
mirror of https://github.com/RPCS3/rpcs3 synced 2024-07-01 07:04:22 +00:00

Compare commits

...

31 Commits

Author SHA1 Message Date
Elad Ashkenazi
7f4ba5afe4
Merge branch 'master' into nn/auto-indicator 2024-06-28 20:54:54 +03:00
kd-11
71524271e9 rsx: Fix codegen when depth-conversion is enabled 2024-06-28 12:13:33 +02:00
Megamouse
d5923ef808 Fix weird new gcc namespace warning 2024-06-28 00:24:07 +02:00
kd-11
ef136acb6c Whitespace fix 2024-06-27 22:55:56 +02:00
kd-11
a5956cfa82 rsx: Fix wrapped/clamped MSAA sampling behavior with dynamic flags 2024-06-27 22:55:56 +02:00
Megamouse
703de01ebf input: actually initialize midi drum notes and combos 2024-06-27 22:14:35 +02:00
Megamouse
8343e35146 cellCamera: improve error logging 2024-06-27 19:12:34 +02:00
Megamouse
0679b502f2 input: allow dynamic change of midi drum config 2024-06-27 19:12:34 +02:00
Megamouse
e790842007 input: allow dynamic change of mouse configs 2024-06-27 19:12:34 +02:00
Elad Ashkenazi
a9d53e98de SPU LLVM: Fix LSA masking for PUTLLC16, disable RTIME checks 2024-06-27 16:58:23 +03:00
Elad Ashkenazi
908082e7c3 Silence some cellGem logging 2024-06-27 16:58:23 +03:00
Elad Ashkenazi
8ec6187dc7 SPU Analyzer: Fix support for multi-block value merge 2024-06-27 16:58:23 +03:00
shinra-electric
50ce4cbea5 Update build script to MoltenVK 1.2.9
Updates from 1.2.7 to 1.2.9
Homebrew had issues with 1.2.8, so we skipped that version.
2024-06-27 03:52:09 +02:00
shinra-electric
3904900243 Update MoltenVK
Updates from 1.2.7 to 1.2.9
Homebrew had problems with 1.2.8, so skip that version.
2024-06-27 03:52:09 +02:00
SuperSamus
33d6e6ce6c skylander_dialog: Fix Drill Sergeant's name 2024-06-27 03:13:17 +02:00
Megamouse
363a4dbdef Fix warning: dangling pointer (construct string_view from temporary string) 2024-06-27 03:21:35 +03:00
Megamouse
e635abe552 Fix warning: std::move of const variables 2024-06-27 03:21:35 +03:00
Megamouse
df6bec236f input: Use same dualsense gyro values as linux kernel 2024-06-27 01:15:23 +02:00
Megamouse
78cb7963fb input: invalidate ds4/dualsense calibration instead of disabling the controller 2024-06-27 01:15:23 +02:00
Megamouse
b251d81065 input: fix minimum turntable input
DJ Hero does not register input if the turntable is 0, so force it to 1.
This will happen if you map it to the left stick and push it all the way down,
or if you use a keyboard, which sends the max value on key press.
2024-06-26 23:45:00 +02:00
Megamouse
11ee80a070 input: add missing lock to keyboard handler ReleaseAllKeys
This should fix a segfault I encountered when closing a game.
I think the consumers were removed while the window went out of focus.
2024-06-26 22:19:56 +02:00
Megamouse
8050e1f853 input: fix ds3 gyro offset 2024-06-26 17:19:06 +02:00
Elad Ashkenazi
f18e3be4f2
Cut scenNpDrmIsAvailable sleep time by half 2024-06-25 10:02:53 +03:00
Elad Ashkenazi
87f5368d3c PPU: Fix access violation on logging 2024-06-23 19:29:13 +03:00
Megamouse
945bfaf0ea input: differentiate between left and right modifier keys 2024-06-23 15:54:13 +02:00
Megamouse
1cef7df006 input: add missing control key to basic keyboard
The meta key logic changed, so we now have to add it.
2024-06-23 15:54:13 +02:00
Megamouse
c2899ad4cb Replace sys_io log channel with cell module log channels
For more granular log filtering
2024-06-23 15:54:13 +02:00
MSuih
7e274a1ff4 Fix locale on linux 2024-06-23 12:15:42 +02:00
Megamouse
7e27e1420e input: try to fix macOS SDL crash 2024-06-23 09:31:48 +02:00
Megamouse
7367f72f4a Update SDL to 2.30.4 2024-06-23 08:25:45 +02:00
Megamouse
81f1f49d5d Update 7zip to 24.07 2024-06-23 08:25:45 +02:00
54 changed files with 860 additions and 485 deletions

View File

@ -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

@ -1 +1 @@
Subproject commit 89a73b901229c8550c172c9556ff8442ae7ac4b8
Subproject commit a7a1d4a241492e81f659a920f7379c193593ebc6

View File

@ -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

@ -1 +1 @@
Subproject commit fb1497566c5a05e2babdcf45ef0ab5c7cca2c4ae
Subproject commit 92fe3b19c868ad062c323dde2cfc9d8b4bfdd785

View File

@ -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);
}
}
}

View File

@ -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>();

View File

@ -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>();

View File

@ -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>();

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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)
{

View File

@ -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;
};

View File

@ -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)

View File

@ -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)

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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 },

View File

@ -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),

View File

@ -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);
}
)"

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)
{

View File

@ -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);

View File

@ -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:

View File

@ -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;
};

View File

@ -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};

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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};

View File

@ -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}));
}

View File

@ -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 "";
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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>

View File

@ -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()

View File

@ -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);