From 53081f1794424ac23bab810b08038b1a2702a30d Mon Sep 17 00:00:00 2001 From: neil4 Date: Sat, 14 Sep 2024 14:14:36 -0500 Subject: [PATCH] Preemptive Frames updates (#17003) * Preemptive Frames: input_poll and input_state improvements - Check pointing devices when used by core; ignore input_libretro_device - Use stored mouse x,y input state (lower level call might flush deltas) - Remove port mapping code (unnecessary now) - Fewer memsets * Add Preemptive Frames to Qt options menu --- runahead.c | 115 +++++++++++++++++------------------ runahead.h | 4 +- ui/drivers/qt/qt_options.cpp | 19 +++--- 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/runahead.c b/runahead.c index de606cddd3..2f2b63d343 100644 --- a/runahead.c +++ b/runahead.c @@ -1332,26 +1332,29 @@ force_input_dirty: static int16_t preempt_input_state(unsigned port, unsigned device, unsigned index, unsigned id) { - settings_t *settings = config_get_ptr(); - runloop_state_t *runloop_st = runloop_state_get_ptr(); - preempt_t *preempt = runloop_st->preempt_data; - unsigned device_class = device & RETRO_DEVICE_MASK; - unsigned *port_map = settings->uints.input_remap_port_map[port]; - uint8_t p; + runloop_state_t *runloop_st = runloop_state_get_ptr(); + preempt_t *preempt = runloop_st->preempt_data; + unsigned device_class = device & RETRO_DEVICE_MASK; switch (device_class) { case RETRO_DEVICE_ANALOG: /* Add requested inputs to mask */ - while ((p = *(port_map++)) < MAX_USERS) - preempt->analog_mask[p] |= (1 << (id + index * 2)); + preempt->analog_mask[port] |= (1 << (id + index * 2)); break; case RETRO_DEVICE_LIGHTGUN: - case RETRO_DEVICE_MOUSE: case RETRO_DEVICE_POINTER: /* Set pointing device for this port */ - while ((p = *(port_map++)) < MAX_USERS) - preempt->ptr_dev[p] = device_class; + preempt->ptr_dev_needed[port] = device_class; + break; + case RETRO_DEVICE_MOUSE: + /* Set pointing device and return stored x,y */ + if (id <= RETRO_DEVICE_ID_MOUSE_Y) + { + preempt->ptr_dev_needed[port] = device_class; + if (preempt->ptr_dev_polled[port] == device_class) + return preempt->ptrdev_state[port][id]; + } break; default: break; @@ -1480,7 +1483,7 @@ error: } static INLINE bool preempt_analog_input_dirty(preempt_t *preempt, - retro_input_state_t state_cb, unsigned port, unsigned mapped_port) + retro_input_state_t state_cb, unsigned port) { int16_t state[20] = {0}; uint8_t base, i; @@ -1490,17 +1493,20 @@ static INLINE bool preempt_analog_input_dirty(preempt_t *preempt, { base = i * 2; if (preempt->analog_mask[port] & (1 << (base ))) - state[base ] = state_cb(mapped_port, RETRO_DEVICE_ANALOG, i, 0); + state[base ] = state_cb(port, RETRO_DEVICE_ANALOG, i, 0); if (preempt->analog_mask[port] & (1 << (base + 1))) - state[base + 1] = state_cb(mapped_port, RETRO_DEVICE_ANALOG, i, 1); + state[base + 1] = state_cb(port, RETRO_DEVICE_ANALOG, i, 1); } /* buttons */ - for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) + if (preempt->analog_mask[port] & 0xfff0) { - if (preempt->analog_mask[port] & (1 << (i + 4))) - state[i + 4] = state_cb(mapped_port, RETRO_DEVICE_ANALOG, - RETRO_DEVICE_INDEX_ANALOG_BUTTON, i); + for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) + { + if (preempt->analog_mask[port] & (1 << (i + 4))) + state[i + 4] = state_cb(port, RETRO_DEVICE_ANALOG, + RETRO_DEVICE_INDEX_ANALOG_BUTTON, i); + } } if (memcmp(preempt->analog_state[port], state, sizeof(state)) == 0) @@ -1511,8 +1517,7 @@ static INLINE bool preempt_analog_input_dirty(preempt_t *preempt, } static INLINE bool preempt_ptr_input_dirty(preempt_t *preempt, - retro_input_state_t state_cb, unsigned device, - unsigned port, unsigned mapped_port) + retro_input_state_t state_cb, unsigned device, unsigned port) { int16_t state[4] = {0}; unsigned count_id = 0; @@ -1537,16 +1542,16 @@ static INLINE bool preempt_ptr_input_dirty(preempt_t *preempt, } /* x, y */ - state[0] = state_cb(mapped_port, device, 0, x_id ); - state[1] = state_cb(mapped_port, device, 0, x_id + 1); + state[0] = state_cb(port, device, 0, x_id ); + state[1] = state_cb(port, device, 0, x_id + 1); /* buttons */ for (id = 2; id <= max_id; id++) - state[2] |= state_cb(mapped_port, device, 0, id) ? 1 << id : 0; + state[2] |= state_cb(port, device, 0, id) ? 1 << id : 0; /* ptr count */ if (count_id) - state[3] = state_cb(mapped_port, device, 0, count_id); + state[3] = state_cb(port, device, 0, count_id); if (memcmp(preempt->ptrdev_state[port], state, sizeof(state)) == 0) return false; @@ -1560,52 +1565,42 @@ static INLINE void preempt_input_poll(preempt_t *preempt, { size_t p; int16_t joypad_state; - retro_input_state_t state_cb = input_driver_state_wrapper; - unsigned max_users = settings->uints.input_max_users; + retro_input_state_t state_cb = input_driver_state_wrapper; + unsigned max_users = settings->uints.input_max_users; input_driver_poll(); /* Check for input state changes */ for (p = 0; p < max_users; p++) { - unsigned mapped_port = settings->uints.input_remap_ports[p]; - unsigned device = settings->uints.input_libretro_device[mapped_port] - & RETRO_DEVICE_MASK; - - switch (device) + /* Check full digital joypad */ + joypad_state = state_cb(p, RETRO_DEVICE_JOYPAD, + 0, RETRO_DEVICE_ID_JOYPAD_MASK); + if (joypad_state != preempt->joypad_state[p]) { - case RETRO_DEVICE_JOYPAD: - case RETRO_DEVICE_ANALOG: - /* Check full digital joypad */ - joypad_state = state_cb(mapped_port, RETRO_DEVICE_JOYPAD, - 0, RETRO_DEVICE_ID_JOYPAD_MASK); - if (joypad_state != preempt->joypad_state[p]) - { - preempt->joypad_state[p] = joypad_state; - runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; - } + preempt->joypad_state[p] = joypad_state; + runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; + } - /* Check requested analogs */ - if ( preempt->analog_mask[p] - && preempt_analog_input_dirty(preempt, state_cb, (unsigned)p, mapped_port)) - runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; - break; - case RETRO_DEVICE_MOUSE: - case RETRO_DEVICE_LIGHTGUN: - case RETRO_DEVICE_POINTER: - /* Check full device state */ - if (preempt_ptr_input_dirty( - preempt, state_cb, preempt->ptr_dev[p], (unsigned)p, mapped_port)) - runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; - break; - default: - break; + /* Check requested analogs */ + if ( preempt->analog_mask[p] + && preempt_analog_input_dirty(preempt, state_cb, (unsigned)p)) + { + runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; + preempt->analog_mask[p] = 0; + } + + /* Check requested pointing device */ + if (preempt->ptr_dev_needed[p]) + { + if (preempt_ptr_input_dirty( + preempt, state_cb, preempt->ptr_dev_needed[p], (unsigned)p)) + runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY; + + preempt->ptr_dev_polled[p] = preempt->ptr_dev_needed[p]; + preempt->ptr_dev_needed[p] = RETRO_DEVICE_NONE; } } - - /* Clear requested inputs */ - memset(preempt->analog_mask, 0, max_users * sizeof(uint32_t)); - memset(preempt->ptr_dev, 0, max_users * sizeof(uint8_t)); } /* macro for preempt_run */ diff --git a/runahead.h b/runahead.h index e0e0cdb63b..cd40a086b5 100644 --- a/runahead.h +++ b/runahead.h @@ -56,7 +56,9 @@ typedef struct preemptive_frames_data int16_t ptrdev_state[MAX_USERS][4]; /* Pointing device requested */ - uint8_t ptr_dev[MAX_USERS]; + uint8_t ptr_dev_needed[MAX_USERS]; + /* Device ID of ptrdev_state */ + uint8_t ptr_dev_polled[MAX_USERS]; /* Buffer indexes for replays */ uint8_t start_ptr; uint8_t replay_ptr; diff --git a/ui/drivers/qt/qt_options.cpp b/ui/drivers/qt/qt_options.cpp index 1c75fae105..0a876ed119 100644 --- a/ui/drivers/qt/qt_options.cpp +++ b/ui/drivers/qt/qt_options.cpp @@ -385,9 +385,10 @@ LatencyPage::LatencyPage(QObject *parent) : QWidget *LatencyPage::widget() { - QWidget *widget = new QWidget; - FormLayout *layout = new FormLayout; - CheckableSettingsGroup *runAheadGpuSync = new CheckableSettingsGroup(MENU_ENUM_LABEL_RUN_AHEAD_ENABLED); + QWidget *widget = new QWidget; + FormLayout *layout = new FormLayout; + CheckableSettingsGroup *runAheadGroup = new CheckableSettingsGroup(MENU_ENUM_LABEL_RUN_AHEAD_ENABLED); + CheckableSettingsGroup *preemptGroup = new CheckableSettingsGroup(MENU_ENUM_LABEL_PREEMPT_ENABLE); rarch_setting_t *hardSyncSetting = menu_setting_find_enum(MENU_ENUM_LABEL_VIDEO_HARD_SYNC); @@ -408,10 +409,14 @@ QWidget *LatencyPage::widget() layout->add(menu_setting_find_enum(MENU_ENUM_LABEL_AUDIO_LATENCY)); layout->add(menu_setting_find_enum(MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR)); - runAheadGpuSync->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_FRAMES)); - runAheadGpuSync->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE)); - runAheadGpuSync->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS)); - layout->addRow(runAheadGpuSync); + runAheadGroup->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_FRAMES)); + runAheadGroup->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE)); + runAheadGroup->add(menu_setting_find_enum(MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS)); + layout->addRow(runAheadGroup); + + preemptGroup->add(menu_setting_find_enum(MENU_ENUM_LABEL_PREEMPT_FRAMES)); + preemptGroup->add(menu_setting_find_enum(MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS)); + layout->addRow(preemptGroup); widget->setLayout(layout);