mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 17:28:49 -10:00
Input: udev and winraw lend the snapshot bridge their pads
The snapshot bridge copied each pad out of its joypad driver at the first read after a poll: the buttons, then each axis and hat a reader had asked for, a call into the driver for each. A driver whose state changes only in its own poll needs no copy: what it holds is the same until the next one. Such a driver now lends it. The pad's state - buttons, the first sixteen axes as the reads answer them, four hats' directions - is kept by the driver in one layout, input_pad_view_t, as its events and reports arrive, and a new view() hands the bridge a pointer to it once a poll; the readers read it in place. udev keeps it with each event; winraw keeps its pads in it outright, and lends them where its reports are read in the poll. Other drivers are copied as before, and the copy now walks only the axes and hats in it, not all twenty: under callgrind that halved what taking it costs. frontend_overhead's core-view lane runs its scenarios a third time with the pad lent, and must give the same digests while asking the driver for nothing but the view; joypad_bridge_checked holds udev's lent state to its reads, winraw_joypad_newest winraw's.
This commit is contained in:
1 parent
5b6ff668a6
commit
48f9503c16
10 files changed
+348
-122
No files matched your search
@@ -91,7 +91,10 @@ struct udev_joypad
|
||||
* identification strings, the keycode maps and the sensor state -
|
||||
* touched at hotplug and on the rare sensor read - trail behind. */
|
||||
int fd;
|
||||
uint64_t buttons;
|
||||
/* the buttons, the hats' directions and the first axes as the reads
|
||||
* answer them, kept with each event: lent to the frontend's readers
|
||||
* between two polls, nothing copied */
|
||||
input_pad_view_t view;
|
||||
int8_t hats[NUM_HATS][2];
|
||||
int16_t axes[NUM_AXES];
|
||||
/* Deal with analog triggers that report -32767 to 32767 */
|
||||
@@ -802,6 +805,34 @@ static const uint8_t udev_ds3_pressure_byte[UDEV_DS3_PRESSURES] = {
|
||||
24, 23, 25, 22, 20, 21, 14, 16, 17, 15
|
||||
};
|
||||
|
||||
/* Axis @i's value in the lent state, as axis() answers it. */
|
||||
static void udev_joypad_view_axis(struct udev_joypad *pad, unsigned i)
|
||||
{
|
||||
int16_t val;
|
||||
if (i >= INPUT_PAD_VIEW_AXES)
|
||||
return;
|
||||
val = pad->axes[i];
|
||||
/* Deal with analog triggers that report -32767 to 32767 */
|
||||
if (pad->neg_trigger[i])
|
||||
val = (val + 0x7fff) / 2;
|
||||
pad->view.axes[i] = val;
|
||||
}
|
||||
|
||||
/* Hat @h's four directions in the lent state, as button() answers
|
||||
* them: up, down, left, right from the low bit. */
|
||||
static void udev_joypad_view_hat(struct udev_joypad *pad, unsigned h)
|
||||
{
|
||||
unsigned bits = 0;
|
||||
if (h >= INPUT_PAD_VIEW_HATS)
|
||||
return;
|
||||
if (pad->hats[h][1] < 0) bits |= 1;
|
||||
if (pad->hats[h][1] > 0) bits |= 2;
|
||||
if (pad->hats[h][0] < 0) bits |= 4;
|
||||
if (pad->hats[h][0] > 0) bits |= 8;
|
||||
pad->view.hats = (uint16_t)((pad->view.hats & ~(0xf << (h * 4)))
|
||||
| (bits << (h * 4)));
|
||||
}
|
||||
|
||||
static void udev_pressure_attach(struct udev_joypad *pad, int fd,
|
||||
unsigned *axes)
|
||||
{
|
||||
@@ -836,6 +867,7 @@ static void udev_pressure_read(struct udev_joypad *pad)
|
||||
{
|
||||
unsigned b = report[newest][udev_ds3_pressure_byte[n]];
|
||||
pad->axes[pad->pressure_axis + n] = (int16_t)((b << 7) | (b >> 1));
|
||||
udev_joypad_view_axis(pad, pad->pressure_axis + n);
|
||||
}
|
||||
}
|
||||
/* gone, or no longer ours: the buttons go on without */
|
||||
@@ -844,7 +876,10 @@ static void udev_pressure_read(struct udev_joypad *pad)
|
||||
close(pad->pressure_fd);
|
||||
pad->pressure = false;
|
||||
for (n = 0; n < UDEV_DS3_PRESSURES; n++)
|
||||
{
|
||||
pad->axes[pad->pressure_axis + n] = 0;
|
||||
udev_joypad_view_axis(pad, pad->pressure_axis + n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,6 +1042,7 @@ static int udev_add_pad(struct udev_device *dev, unsigned p, int fd, const char
|
||||
if ( (i == ABS_Z || i == ABS_RZ)
|
||||
&& udev_compute_axis(abs, abs->value) < -1300)
|
||||
pad->neg_trigger[axes] = true;
|
||||
udev_joypad_view_axis(pad, axes);
|
||||
pad->axes_bind[i] = axes++;
|
||||
}
|
||||
}
|
||||
@@ -1342,9 +1378,9 @@ static void udev_joypad_poll(void)
|
||||
if (code > 0 && code < KEY_MAX)
|
||||
{
|
||||
if (value)
|
||||
BIT64_SET(pad->buttons, pad->button_bind[code]);
|
||||
BIT256_SET(pad->view.buttons, pad->button_bind[code]);
|
||||
else
|
||||
BIT64_CLEAR(pad->buttons, pad->button_bind[code]);
|
||||
BIT256_CLEAR(pad->view.buttons, pad->button_bind[code]);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1364,6 +1400,7 @@ static void udev_joypad_poll(void)
|
||||
case ABS_HAT3Y:
|
||||
code -= ABS_HAT0X;
|
||||
pad->hats[code >> 1][code & 1] = value;
|
||||
udev_joypad_view_hat(pad, code >> 1);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -1378,6 +1415,7 @@ static void udev_joypad_poll(void)
|
||||
&& abs(pad->axes[axis]) < 0x2000)
|
||||
pad->neg_trigger[axis] = false;
|
||||
pad->axis_reported[axis] = true;
|
||||
udev_joypad_view_axis(pad, axis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1541,7 +1579,7 @@ static int32_t udev_joypad_button_state(
|
||||
/* hat requested and no hat button down */
|
||||
}
|
||||
else if (joykey < UDEV_NUM_BUTTONS)
|
||||
return (BIT64_GET(pad->buttons, joykey));
|
||||
return BIT256_GET(pad->view.buttons, joykey) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1561,7 +1599,7 @@ static void udev_joypad_get_buttons(unsigned port, input_bits_t *state)
|
||||
|
||||
if (pad)
|
||||
{
|
||||
BITS_COPY64_PTR( state, pad->buttons );
|
||||
*state = pad->view.buttons;
|
||||
}
|
||||
else
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
@@ -1592,6 +1630,12 @@ static int16_t udev_joypad_axis_state(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read in the poll alone: the state is the same until the next. */
|
||||
static const input_pad_view_t *udev_joypad_view(unsigned port)
|
||||
{
|
||||
return (port < MAX_USERS) ? &udev_pads[port].view : NULL;
|
||||
}
|
||||
|
||||
static int16_t udev_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
{
|
||||
const struct udev_joypad *pad = (const struct udev_joypad*)
|
||||
@@ -1777,6 +1821,12 @@ input_device_driver_t udev_joypad = {
|
||||
"udev",
|
||||
#if defined(__linux__)
|
||||
udev_joypad_get_bt_host,
|
||||
udev_joypad_set_bt_host
|
||||
udev_joypad_set_bt_host,
|
||||
#else
|
||||
NULL, /* get_bt_host */
|
||||
NULL, /* set_bt_host */
|
||||
#endif
|
||||
NULL, /* survives_video */
|
||||
NULL, /* set_player */
|
||||
udev_joypad_view
|
||||
};
|
||||
@@ -149,9 +149,10 @@ typedef struct winraw_joypad_joypad_data
|
||||
uint16_t num_hats;
|
||||
USAGE btn_usage_min;
|
||||
|
||||
int16_t axes[RAWINPUT_MAX_AXES]; /* 16 bytes */
|
||||
uint8_t hats[RAWINPUT_MAX_HATS]; /* 4 bytes */
|
||||
bool buttons[RAWINPUT_MAX_BUTTONS]; /* 128 bytes */
|
||||
/* the buttons, the hats' four directions and the axes as the reads
|
||||
* answer them: lent to the frontend's readers between two polls
|
||||
* where the reports are parsed in the poll, nothing copied */
|
||||
input_pad_view_t view;
|
||||
|
||||
/* --- Cold fields (accessed only at device add/remove) ---------- */
|
||||
PHIDP_PREPARSED_DATA preparsed; /* HID preparsed data (opaque blob) */
|
||||
@@ -181,6 +182,15 @@ typedef struct winraw_joypad_joypad_data
|
||||
sony_pad_motion_t motion;
|
||||
} winraw_joypad_joypad_data_t;
|
||||
|
||||
#define WINRAW_BUTTON(pad, i) BIT256_GET((pad)->view.buttons, (i))
|
||||
#define WINRAW_SET_BUTTON(pad, i, on) do { if (on) \
|
||||
BIT256_SET((pad)->view.buttons, (i)); \
|
||||
else BIT256_CLEAR((pad)->view.buttons, (i)); } while (0)
|
||||
/* hat @h's four bits: up, down, left, right from the low one */
|
||||
#define WINRAW_HAT(pad, h) (((pad)->view.hats >> ((h) * 4)) & 0xf)
|
||||
#define WINRAW_SET_HAT(pad, h, bits) ((pad)->view.hats = (uint16_t)( \
|
||||
((pad)->view.hats & ~(0xf << ((h) * 4))) | (((bits) & 0xf) << ((h) * 4))))
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Static globals */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -1194,18 +1204,18 @@ static void winraw_joypad_xinput_fill(winraw_joypad_joypad_data_t *pad,
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
pad->buttons[i] = (st->buttons & bits[i]) != 0;
|
||||
pad->hats[0] = (uint8_t)(
|
||||
WINRAW_SET_BUTTON(pad, i, (st->buttons & bits[i]) != 0);
|
||||
WINRAW_SET_HAT(pad, 0,
|
||||
((st->buttons & 0x0001) ? (1 << 0) : 0)
|
||||
| ((st->buttons & 0x0002) ? (1 << 1) : 0)
|
||||
| ((st->buttons & 0x0004) ? (1 << 2) : 0)
|
||||
| ((st->buttons & 0x0008) ? (1 << 3) : 0));
|
||||
pad->axes[0] = st->lx == -32768 ? -32767 : st->lx;
|
||||
pad->axes[1] = st->ly == -32768 ? -32767 : st->ly;
|
||||
pad->axes[2] = st->rx == -32768 ? -32767 : st->rx;
|
||||
pad->axes[3] = st->ry == -32768 ? -32767 : st->ry;
|
||||
pad->axes[4] = (int16_t)(st->left_trigger * 32767 / 255);
|
||||
pad->axes[5] = (int16_t)(st->right_trigger * 32767 / 255);
|
||||
pad->view.axes[0] = st->lx == -32768 ? -32767 : st->lx;
|
||||
pad->view.axes[1] = st->ly == -32768 ? -32767 : st->ly;
|
||||
pad->view.axes[2] = st->rx == -32768 ? -32767 : st->rx;
|
||||
pad->view.axes[3] = st->ry == -32768 ? -32767 : st->ry;
|
||||
pad->view.axes[4] = (int16_t)(st->left_trigger * 32767 / 255);
|
||||
pad->view.axes[5] = (int16_t)(st->right_trigger * 32767 / 255);
|
||||
}
|
||||
|
||||
/* XInput's four pads are looked at: one that has come is given a
|
||||
@@ -1644,7 +1654,7 @@ static void winraw_joypad_out_publish_buttons(
|
||||
if (slot >= MAX_USERS || !winraw_joypad_out[slot].xinput)
|
||||
return;
|
||||
for (b = 0; b < 10 && b < pad->num_buttons; b++)
|
||||
if (pad->buttons[b])
|
||||
if (WINRAW_BUTTON(pad, b))
|
||||
mask |= 1 << b;
|
||||
retro_atomic_store_release_int(&winraw_joypad_out[slot].buttons, mask);
|
||||
}
|
||||
@@ -1680,11 +1690,11 @@ static void winraw_joypad_parse_sixaxis(winraw_joypad_joypad_data_t *pad,
|
||||
pad->num_axes = 6;
|
||||
pad->num_hats = 0;
|
||||
for (i = 0; i < 19; i++)
|
||||
pad->buttons[i] = (b >> i) & 1;
|
||||
pad->axes[0] = winraw_joypad_scale_axis(r[6], 0, 255);
|
||||
pad->axes[1] = winraw_joypad_scale_axis(r[7], 0, 255);
|
||||
pad->axes[2] = winraw_joypad_scale_axis(r[8], 0, 255);
|
||||
pad->axes[5] = winraw_joypad_scale_axis(r[9], 0, 255);
|
||||
WINRAW_SET_BUTTON(pad, i, (b >> i) & 1);
|
||||
pad->view.axes[0] = winraw_joypad_scale_axis(r[6], 0, 255);
|
||||
pad->view.axes[1] = winraw_joypad_scale_axis(r[7], 0, 255);
|
||||
pad->view.axes[2] = winraw_joypad_scale_axis(r[8], 0, 255);
|
||||
pad->view.axes[5] = winraw_joypad_scale_axis(r[9], 0, 255);
|
||||
winraw_joypad_reports_parsed++;
|
||||
}
|
||||
|
||||
@@ -1728,9 +1738,10 @@ static void winraw_joypad_parse_hid_report(winraw_joypad_joypad_data_t *pad,
|
||||
num_buttons = pad->num_buttons;
|
||||
|
||||
/* --- Buttons --- */
|
||||
/* Clear only the buttons this device actually has, not the full 128 */
|
||||
/* Those past the device's own are never set: all thirty-two bytes
|
||||
* are one clear */
|
||||
if (num_buttons > 0)
|
||||
memset(pad->buttons, 0, num_buttons * sizeof(pad->buttons[0]));
|
||||
BIT256_CLEAR_ALL(pad->view.buttons);
|
||||
|
||||
/* Hats are cleared for the same reason as buttons: a hat whose
|
||||
* usage is absent from this report must read as centred rather
|
||||
@@ -1741,7 +1752,7 @@ static void winraw_joypad_parse_hid_report(winraw_joypad_joypad_data_t *pad,
|
||||
* and zeroing them would fight sticks that legitimately rest
|
||||
* off-centre. */
|
||||
if (pad->num_hats > 0)
|
||||
memset(pad->hats, 0, pad->num_hats * sizeof(pad->hats[0]));
|
||||
pad->view.hats = 0;
|
||||
|
||||
usage_count = (ULONG)num_buttons;
|
||||
if (usage_count > RAWINPUT_MAX_BUTTONS)
|
||||
@@ -1760,7 +1771,7 @@ static void winraw_joypad_parse_hid_report(winraw_joypad_joypad_data_t *pad,
|
||||
{
|
||||
unsigned btn_index = usages[i] - btn_min;
|
||||
if (btn_index < num_buttons)
|
||||
pad->buttons[btn_index] = true;
|
||||
BIT256_SET(pad->view.buttons, btn_index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1814,10 +1825,11 @@ static void winraw_joypad_parse_hid_report(winraw_joypad_joypad_data_t *pad,
|
||||
if (is_hat)
|
||||
{
|
||||
if ((unsigned)slot_idx < max_hats)
|
||||
pad->hats[slot_idx] = winraw_joypad_hat_value_to_bitmask(
|
||||
WINRAW_SET_HAT(pad, slot_idx,
|
||||
winraw_joypad_hat_value_to_bitmask(
|
||||
(LONG)value,
|
||||
pad->val_caps[i].LogicalMin,
|
||||
pad->val_caps[i].LogicalMax);
|
||||
pad->val_caps[i].LogicalMax));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1826,7 +1838,7 @@ static void winraw_joypad_parse_hid_report(winraw_joypad_joypad_data_t *pad,
|
||||
LONG signed_value = (pad->val_caps[i].LogicalMin < 0)
|
||||
? winraw_joypad_sign_extend(value, pad->val_caps[i].BitSize)
|
||||
: (LONG)value;
|
||||
pad->axes[slot_idx] = winraw_joypad_scale_axis(
|
||||
pad->view.axes[slot_idx] = winraw_joypad_scale_axis(
|
||||
signed_value,
|
||||
pad->val_caps[i].LogicalMin,
|
||||
pad->val_caps[i].LogicalMax);
|
||||
@@ -2246,13 +2258,13 @@ static int32_t winraw_joypad_joypad_button(unsigned port, uint16_t joykey)
|
||||
switch (hat_dir)
|
||||
{
|
||||
case HAT_UP_MASK:
|
||||
return (pad->hats[hat_index] & (1 << 0)) ? 1 : 0;
|
||||
return (WINRAW_HAT(pad, hat_index) & (1 << 0)) ? 1 : 0;
|
||||
case HAT_DOWN_MASK:
|
||||
return (pad->hats[hat_index] & (1 << 1)) ? 1 : 0;
|
||||
return (WINRAW_HAT(pad, hat_index) & (1 << 1)) ? 1 : 0;
|
||||
case HAT_LEFT_MASK:
|
||||
return (pad->hats[hat_index] & (1 << 2)) ? 1 : 0;
|
||||
return (WINRAW_HAT(pad, hat_index) & (1 << 2)) ? 1 : 0;
|
||||
case HAT_RIGHT_MASK:
|
||||
return (pad->hats[hat_index] & (1 << 3)) ? 1 : 0;
|
||||
return (WINRAW_HAT(pad, hat_index) & (1 << 3)) ? 1 : 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2260,15 +2272,24 @@ static int32_t winraw_joypad_joypad_button(unsigned port, uint16_t joykey)
|
||||
}
|
||||
|
||||
if (joykey < pad->num_buttons)
|
||||
return pad->buttons[joykey] ? 1 : 0;
|
||||
return WINRAW_BUTTON(pad, joykey) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lent where the reports are read in the poll, which is then the only
|
||||
* place a pad's state changes; under the window of its own, read on
|
||||
* whichever thread made it, it is copied. */
|
||||
static const input_pad_view_t *winraw_joypad_joypad_view(unsigned port)
|
||||
{
|
||||
if (port >= MAX_USERS || !winraw_joypad_by_poll)
|
||||
return NULL;
|
||||
return &winraw_joypad_pads[port].view;
|
||||
}
|
||||
|
||||
static void winraw_joypad_joypad_get_buttons(unsigned port,
|
||||
input_bits_t *state)
|
||||
{
|
||||
unsigned i;
|
||||
const winraw_joypad_joypad_data_t *pad;
|
||||
|
||||
if (port >= MAX_USERS)
|
||||
@@ -2284,12 +2305,7 @@ static void winraw_joypad_joypad_get_buttons(unsigned port,
|
||||
return;
|
||||
}
|
||||
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
for (i = 0; i < pad->num_buttons && i < RAWINPUT_MAX_BUTTONS; i++)
|
||||
{
|
||||
if (pad->buttons[i])
|
||||
BIT256_SET_PTR(state, i);
|
||||
}
|
||||
*state = pad->view.buttons;
|
||||
}
|
||||
|
||||
static int16_t winraw_joypad_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
@@ -2323,7 +2339,7 @@ static int16_t winraw_joypad_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
if (axis < 0 || (unsigned)axis >= pad->num_axes)
|
||||
return 0;
|
||||
|
||||
val = pad->axes[axis];
|
||||
val = pad->view.axes[axis];
|
||||
|
||||
if (is_neg && val > 0)
|
||||
return 0;
|
||||
@@ -2383,7 +2399,7 @@ static int16_t winraw_joypad_joypad_state(
|
||||
unsigned hat_index = GET_HAT(key);
|
||||
if (hat_index < pad->num_hats)
|
||||
{
|
||||
uint8_t hv = pad->hats[hat_index];
|
||||
uint8_t hv = (uint8_t)WINRAW_HAT(pad, hat_index);
|
||||
switch (hat_dir)
|
||||
{
|
||||
case HAT_UP_MASK: if (hv & (1 << 0)) ret |= (1 << i); break;
|
||||
@@ -2394,7 +2410,7 @@ static int16_t winraw_joypad_joypad_state(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key < pad->num_buttons && pad->buttons[key])
|
||||
else if (key < pad->num_buttons && WINRAW_BUTTON(pad, key))
|
||||
ret |= (1 << i);
|
||||
|
||||
/* If button matched, skip axis check for this bind */
|
||||
@@ -2413,7 +2429,7 @@ static int16_t winraw_joypad_joypad_state(
|
||||
axis = AXIS_NEG_GET(joyaxis);
|
||||
if (axis >= 0 && (unsigned)axis < pad->num_axes)
|
||||
{
|
||||
val = pad->axes[axis];
|
||||
val = pad->view.axes[axis];
|
||||
if (val < 0 && abs((int)val) > threshold)
|
||||
ret |= (1 << i);
|
||||
}
|
||||
@@ -2423,7 +2439,7 @@ static int16_t winraw_joypad_joypad_state(
|
||||
axis = AXIS_POS_GET(joyaxis);
|
||||
if (axis >= 0 && (unsigned)axis < pad->num_axes)
|
||||
{
|
||||
val = pad->axes[axis];
|
||||
val = pad->view.axes[axis];
|
||||
if (val > 0 && val > threshold)
|
||||
ret |= (1 << i);
|
||||
}
|
||||
@@ -2685,5 +2701,7 @@ input_device_driver_t winraw_joypad = {
|
||||
"winraw_joypad",
|
||||
NULL, /* get_bt_host */
|
||||
NULL, /* set_bt_host */
|
||||
winraw_joypad_survives_video
|
||||
winraw_joypad_survives_video,
|
||||
NULL, /* set_player */
|
||||
winraw_joypad_joypad_view
|
||||
};
|
||||
+68
-40
@@ -974,20 +974,23 @@ static input_driver_state_t input_driver_st; /* double alignment */
|
||||
* the loop every driver has, run against the copy. Rumble, sensors,
|
||||
* names and the poll itself still go to the real driver.
|
||||
*
|
||||
* A driver whose state changes only in its own poll lends it instead:
|
||||
* its view() hands the bridge the pad's state where the driver keeps
|
||||
* it, and the readers read that, with nothing copied. The rest are
|
||||
* copied.
|
||||
*
|
||||
* This is the legacy bridge of the input plan (WP-03, WP-05). A driver
|
||||
* is switched over when it has been checked - that its get_buttons
|
||||
* says what its button() says, and its state() is the common loop -
|
||||
* and the rest read their drivers as before. */
|
||||
#define INPUT_SNAPSHOT_AXES 16
|
||||
#define INPUT_SNAPSHOT_HATS 4
|
||||
#define INPUT_SNAPSHOT_AXES INPUT_PAD_VIEW_AXES
|
||||
#define INPUT_SNAPSHOT_HATS INPUT_PAD_VIEW_HATS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
input_bits_t buttons;
|
||||
int16_t axes[INPUT_SNAPSHOT_AXES];
|
||||
input_pad_view_t copy;
|
||||
uint16_t axes_known; /* axes in the copy */
|
||||
uint16_t axes_used; /* axes read since the copy was taken */
|
||||
uint16_t hats; /* four bits a hat: up, down, left, right */
|
||||
uint8_t hats_known;
|
||||
uint8_t hats_used;
|
||||
} input_pad_snapshot_t;
|
||||
@@ -997,6 +1000,9 @@ typedef struct
|
||||
const input_device_driver_t *real;
|
||||
input_device_driver_t adapter;
|
||||
input_pad_snapshot_t pads[MAX_USERS];
|
||||
/* this poll's state of each pad read: the driver's own, lent, or
|
||||
* the copy */
|
||||
const input_pad_view_t *view[MAX_USERS];
|
||||
} input_snapshot_bridge_t;
|
||||
|
||||
static input_snapshot_bridge_t input_snapshot_bridge;
|
||||
@@ -1096,7 +1102,7 @@ static bool input_snapshot_driver_checked(const input_device_driver_t *drv)
|
||||
}
|
||||
|
||||
static void input_snapshot_fetch_axis(const input_device_driver_t *real,
|
||||
input_pad_snapshot_t *snap, unsigned pad, unsigned i)
|
||||
input_pad_view_t *snap, unsigned pad, unsigned i)
|
||||
{
|
||||
/* a driver gives each direction on its own; one of the two is 0 */
|
||||
snap->axes[i] = (int16_t)(real->axis(pad, AXIS_POS(i))
|
||||
@@ -1104,7 +1110,7 @@ static void input_snapshot_fetch_axis(const input_device_driver_t *real,
|
||||
}
|
||||
|
||||
static void input_snapshot_fetch_hat(const input_device_driver_t *real,
|
||||
input_pad_snapshot_t *snap, unsigned pad, unsigned h)
|
||||
input_pad_view_t *snap, unsigned pad, unsigned h)
|
||||
{
|
||||
uint16_t bits = 0;
|
||||
if (real->button(pad, (uint16_t)HAT_MAP(h, HAT_UP_MASK)))
|
||||
@@ -1123,9 +1129,19 @@ static void input_snapshot_fetch_hat(const input_device_driver_t *real,
|
||||
/* Takes the copy of a pad for this poll. */
|
||||
INPUT_NOINLINE static void input_snapshot_pad_take(unsigned pad)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned m;
|
||||
input_snapshot_bridge_t *bridge = &input_snapshot_bridge;
|
||||
input_pad_snapshot_t *snap = &bridge->pads[pad];
|
||||
const input_pad_view_t *lent = bridge->real->view
|
||||
? bridge->real->view(pad) : NULL;
|
||||
|
||||
input_driver_st.frame_valid.snapshot |= (1 << pad);
|
||||
if (lent)
|
||||
{
|
||||
bridge->view[pad] = lent;
|
||||
return;
|
||||
}
|
||||
bridge->view[pad] = &snap->copy;
|
||||
|
||||
/* Copy what was read out of the last copy, and no more: a
|
||||
* control that has stopped being read - the bind screen scans
|
||||
@@ -1136,29 +1152,30 @@ INPUT_NOINLINE static void input_snapshot_pad_take(unsigned pad)
|
||||
snap->axes_used = 0;
|
||||
snap->hats_used = 0;
|
||||
|
||||
bridge->real->get_buttons(pad, &snap->buttons);
|
||||
for (i = 0; i < INPUT_SNAPSHOT_AXES; i++)
|
||||
if (snap->axes_known & (1 << i))
|
||||
input_snapshot_fetch_axis(bridge->real, snap, pad, i);
|
||||
for (i = 0; i < INPUT_SNAPSHOT_HATS; i++)
|
||||
if (snap->hats_known & (1 << i))
|
||||
input_snapshot_fetch_hat(bridge->real, snap, pad, i);
|
||||
input_driver_st.frame_valid.snapshot |= (1 << pad);
|
||||
bridge->real->get_buttons(pad, &snap->copy.buttons);
|
||||
/* the controls in the copy, and no walk over the rest */
|
||||
for (m = snap->axes_known; m; m &= m - 1)
|
||||
input_snapshot_fetch_axis(bridge->real, &snap->copy, pad,
|
||||
(unsigned)compat_ctz(m));
|
||||
for (m = snap->hats_known; m; m &= m - 1)
|
||||
input_snapshot_fetch_hat(bridge->real, &snap->copy, pad,
|
||||
(unsigned)compat_ctz(m));
|
||||
}
|
||||
|
||||
/* A pad's copy, taken if this is the poll's first look at it. Whether
|
||||
* it is, is one test, here where it is asked - it is asked for every
|
||||
* axis and hat read. */
|
||||
static INLINE input_pad_snapshot_t *input_snapshot_pad(unsigned pad)
|
||||
/* A pad's state for this poll, taken if this is the poll's first look
|
||||
* at it. Whether it is, is one test, here where it is asked - it is
|
||||
* asked for every axis and hat read. */
|
||||
static INLINE const input_pad_view_t *input_snapshot_view(unsigned pad)
|
||||
{
|
||||
if (!(input_driver_st.frame_valid.snapshot & (1 << pad)))
|
||||
input_snapshot_pad_take(pad);
|
||||
return &input_snapshot_bridge.pads[pad];
|
||||
return input_snapshot_bridge.view[pad];
|
||||
}
|
||||
|
||||
static int32_t input_snapshot_button(unsigned pad, uint16_t joykey)
|
||||
{
|
||||
const input_device_driver_t *real = input_snapshot_bridge.real;
|
||||
const input_pad_view_t *view;
|
||||
input_pad_snapshot_t *snap;
|
||||
uint16_t dir = GET_HAT_DIR(joykey);
|
||||
|
||||
@@ -1182,26 +1199,31 @@ static int32_t input_snapshot_button(unsigned pad, uint16_t joykey)
|
||||
if (h >= INPUT_SNAPSHOT_HATS)
|
||||
return real->button(pad, joykey);
|
||||
|
||||
snap = input_snapshot_pad(pad);
|
||||
if (!(snap->hats_known & (1 << h)))
|
||||
view = input_snapshot_view(pad);
|
||||
snap = &input_snapshot_bridge.pads[pad];
|
||||
/* a copy holds the hats read before; a lent view, all of them */
|
||||
if (view == &snap->copy)
|
||||
{
|
||||
input_snapshot_fetch_hat(real, snap, pad, h);
|
||||
snap->hats_known |= (1 << h);
|
||||
if (!(snap->hats_known & (1 << h)))
|
||||
{
|
||||
input_snapshot_fetch_hat(real, &snap->copy, pad, h);
|
||||
snap->hats_known |= (1 << h);
|
||||
}
|
||||
snap->hats_used |= (1 << h);
|
||||
}
|
||||
snap->hats_used |= (1 << h);
|
||||
return (snap->hats >> (h * 4 + bit)) & 1;
|
||||
return (view->hats >> (h * 4 + bit)) & 1;
|
||||
}
|
||||
|
||||
if (joykey >= 256)
|
||||
return real->button(pad, joykey);
|
||||
|
||||
snap = input_snapshot_pad(pad);
|
||||
return BIT256_GET(snap->buttons, joykey) ? 1 : 0;
|
||||
return BIT256_GET(input_snapshot_view(pad)->buttons, joykey) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int16_t input_snapshot_axis(unsigned pad, uint32_t joyaxis)
|
||||
{
|
||||
const input_device_driver_t *real = input_snapshot_bridge.real;
|
||||
const input_pad_view_t *view;
|
||||
input_pad_snapshot_t *snap;
|
||||
bool negative = AXIS_NEG_GET(joyaxis) < INPUT_SNAPSHOT_AXES;
|
||||
unsigned i = negative
|
||||
@@ -1211,14 +1233,18 @@ static int16_t input_snapshot_axis(unsigned pad, uint32_t joyaxis)
|
||||
if (pad >= MAX_USERS || i >= INPUT_SNAPSHOT_AXES)
|
||||
return real->axis(pad, joyaxis);
|
||||
|
||||
snap = input_snapshot_pad(pad);
|
||||
if (!(snap->axes_known & (1 << i)))
|
||||
view = input_snapshot_view(pad);
|
||||
snap = &input_snapshot_bridge.pads[pad];
|
||||
if (view == &snap->copy)
|
||||
{
|
||||
input_snapshot_fetch_axis(real, snap, pad, i);
|
||||
snap->axes_known |= (1 << i);
|
||||
if (!(snap->axes_known & (1 << i)))
|
||||
{
|
||||
input_snapshot_fetch_axis(real, &snap->copy, pad, i);
|
||||
snap->axes_known |= (1 << i);
|
||||
}
|
||||
snap->axes_used |= (1 << i);
|
||||
}
|
||||
snap->axes_used |= (1 << i);
|
||||
value = snap->axes[i];
|
||||
value = view->axes[i];
|
||||
if (negative)
|
||||
return (value < 0) ? value : 0;
|
||||
return (value > 0) ? value : 0;
|
||||
@@ -1525,7 +1551,7 @@ static int16_t input_snapshot_state(
|
||||
unsigned bound;
|
||||
bool full_range;
|
||||
const input_port_pads_t *pads;
|
||||
const input_pad_snapshot_t *snap;
|
||||
const input_pad_view_t *snap;
|
||||
|
||||
if (pad >= MAX_USERS)
|
||||
return 0;
|
||||
@@ -1557,8 +1583,8 @@ static int16_t input_snapshot_state(
|
||||
return input_st->pad_state_cache[port];
|
||||
}
|
||||
|
||||
/* the copy of the pad, taken now if this is the poll's first look */
|
||||
snap = input_snapshot_pad(pad);
|
||||
/* the pad's state, taken now if this is the poll's first look */
|
||||
snap = input_snapshot_view(pad);
|
||||
|
||||
for (; bound; bound &= bound - 1)
|
||||
{
|
||||
@@ -1667,7 +1693,7 @@ static void input_snapshot_get_buttons(unsigned pad,
|
||||
input_snapshot_bridge.real->get_buttons(pad, state);
|
||||
return;
|
||||
}
|
||||
*state = input_snapshot_pad(pad)->buttons;
|
||||
*state = input_snapshot_view(pad)->buttons;
|
||||
}
|
||||
|
||||
/* The bridge for @drv, set up if it is not the driver it last stood in
|
||||
@@ -1692,6 +1718,7 @@ static const input_device_driver_t *input_snapshot_for(
|
||||
if (bridge->real != drv)
|
||||
{
|
||||
memset(bridge->pads, 0, sizeof(bridge->pads));
|
||||
memset(bridge->view, 0, sizeof(bridge->view));
|
||||
st->frame_valid.snapshot = 0;
|
||||
st->frame_valid.pad_state = 0;
|
||||
bridge->real = drv;
|
||||
@@ -1716,6 +1743,7 @@ static void input_snapshot_forget_pad(unsigned slot)
|
||||
return;
|
||||
memset(&input_snapshot_bridge.pads[slot], 0,
|
||||
sizeof(input_snapshot_bridge.pads[slot]));
|
||||
input_snapshot_bridge.view[slot] = NULL;
|
||||
input_driver_st.frame_valid.snapshot &= ~(1 << slot);
|
||||
/* and any port's mask worked out from it */
|
||||
input_driver_st.frame_valid.pad_state = 0;
|
||||
@@ -3119,7 +3147,7 @@ static INLINE bool input_analog_button_key(
|
||||
return false;
|
||||
if ( drv == &input_snapshot_bridge.adapter
|
||||
&& pad < MAX_USERS && key < 256 && !GET_HAT_DIR(key))
|
||||
return BIT256_GET(input_snapshot_pad(pad)->buttons, key) != 0;
|
||||
return BIT256_GET(input_snapshot_view(pad)->buttons, key) != 0;
|
||||
return drv->button(pad, key) != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -596,6 +596,22 @@ struct input_driver
|
||||
unsigned (*bind_mouse_buttons)(void *data, unsigned port);
|
||||
};
|
||||
|
||||
/* A pad's state as a joypad driver keeps it, for a driver whose state
|
||||
* changes only in its own poll: lent to the readers between two polls
|
||||
* in place of a copy (input_driver.c, the snapshot bridge). What each
|
||||
* field holds is what button(), axis() and get_buttons() answer. */
|
||||
#define INPUT_PAD_VIEW_AXES 16
|
||||
#define INPUT_PAD_VIEW_HATS 4
|
||||
|
||||
typedef struct input_pad_view
|
||||
{
|
||||
input_bits_t buttons;
|
||||
/* each axis signed, as axis() gives its two directions */
|
||||
int16_t axes[INPUT_PAD_VIEW_AXES];
|
||||
/* four bits a hat, from bit 0: up, down, left, right */
|
||||
uint16_t hats;
|
||||
} input_pad_view_t;
|
||||
|
||||
struct rarch_joypad_driver
|
||||
{
|
||||
void *(*init)(void *data);
|
||||
@@ -639,6 +655,11 @@ struct rarch_joypad_driver
|
||||
* it changed; the driver acts on a change. NULL where the driver
|
||||
* lights nothing, or lights by its own lights. */
|
||||
void (*set_player)(unsigned pad, unsigned player);
|
||||
|
||||
/* Pad @pad's state, unchanged until the driver's next poll; NULL
|
||||
* where the driver cannot say that, which then gets copied. Asked
|
||||
* once a poll per pad read. */
|
||||
const input_pad_view_t *(*view)(unsigned pad);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,4 +172,32 @@ static unsigned bv_compare(const input_device_driver_t *drv, unsigned pad)
|
||||
return bad;
|
||||
}
|
||||
|
||||
/* A driver that lends the bridge its state: what it lends is what its
|
||||
* reads say - every button, the four hats' directions and the axes the
|
||||
* view holds. Returns the number of disagreements. */
|
||||
static unsigned bv_compare_view(const input_device_driver_t *drv,
|
||||
unsigned pad)
|
||||
{
|
||||
static const uint16_t dirs[4] = {
|
||||
HAT_UP_MASK, HAT_DOWN_MASK, HAT_LEFT_MASK, HAT_RIGHT_MASK };
|
||||
const input_pad_view_t *view = drv->view ? drv->view(pad) : NULL;
|
||||
unsigned bad = 0, i, t;
|
||||
|
||||
if (!view)
|
||||
return 1;
|
||||
for (i = 0; i < 256; i++)
|
||||
if ((BIT256_GET(view->buttons, i) != 0) != (drv->button(pad, (uint16_t)i) != 0))
|
||||
bad++;
|
||||
for (i = 0; i < BV_HATS; i++)
|
||||
for (t = 0; t < 4; t++)
|
||||
if ( ((view->hats >> (i * 4 + t)) & 1)
|
||||
!= (drv->button(pad, (uint16_t)HAT_MAP(i, dirs[t])) != 0))
|
||||
bad++;
|
||||
for (i = 0; i < BV_AXES; i++)
|
||||
if (view->axes[i] != (int16_t)(drv->axis(pad, AXIS_POS(i))
|
||||
+ drv->axis(pad, AXIS_NEG(i))))
|
||||
bad++;
|
||||
return bad;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,11 +15,15 @@ int main(void)
|
||||
struct udev_joypad *pad = &udev_pads[n % 3];
|
||||
|
||||
pad->fd = 1; /* as a connected pad has one */
|
||||
pad->buttons = ((uint64_t)bv_rand() << 32) | bv_rand();
|
||||
memset(&pad->view.buttons, 0, sizeof(pad->view.buttons));
|
||||
pad->view.buttons.data[0] = bv_rand();
|
||||
pad->view.buttons.data[1] = bv_rand();
|
||||
for (i = 0; i < NUM_HATS; i++)
|
||||
{
|
||||
pad->hats[i][0] = (int8_t)((int)(bv_rand() % 3) - 1);
|
||||
pad->hats[i][1] = (int8_t)((int)(bv_rand() % 3) - 1);
|
||||
/* as an event does */
|
||||
udev_joypad_view_hat(pad, i);
|
||||
}
|
||||
for (i = 0; i < NUM_AXES; i++)
|
||||
{
|
||||
@@ -30,8 +34,10 @@ int main(void)
|
||||
: (r == 3) ? (int16_t)-0x8000
|
||||
: (int16_t)bv_rand();
|
||||
pad->neg_trigger[i] = (bv_rand() & 1) != 0;
|
||||
udev_joypad_view_axis(pad, i);
|
||||
}
|
||||
bad += bv_compare(&udev_joypad, n % 3);
|
||||
bad += bv_compare_view(&udev_joypad, n % 3);
|
||||
}
|
||||
|
||||
if (bad)
|
||||
@@ -40,6 +46,6 @@ int main(void)
|
||||
return 1;
|
||||
}
|
||||
printf("PASS udev_checked_test: 4000 random pads; what the bridge would"
|
||||
" read is what the driver says\n");
|
||||
" read, copied or lent, is what the driver says\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -17,8 +17,9 @@
|
||||
* path and to the other one report at a time, and after every burst
|
||||
* the two must read the same.
|
||||
*
|
||||
* Also checked: how many parses each took, and that removing a
|
||||
* controller forgets what was held for it. */
|
||||
* Also checked: how many parses each took, that removing a
|
||||
* controller forgets what was held for it, and that the state the
|
||||
* driver lends the frontend in place of a copy is what its reads say. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -202,9 +203,7 @@ static int same_state(void)
|
||||
{
|
||||
const winraw_joypad_joypad_data_t *a = &winraw_joypad_pads[0];
|
||||
const winraw_joypad_joypad_data_t *b = &winraw_joypad_pads[1];
|
||||
return !memcmp(a->buttons, b->buttons, sizeof(a->buttons))
|
||||
&& !memcmp(a->axes, b->axes, sizeof(a->axes))
|
||||
&& !memcmp(a->hats, b->hats, sizeof(a->hats));
|
||||
return !memcmp(&a->view, &b->view, sizeof(a->view));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -269,6 +268,37 @@ int main(void)
|
||||
parses_held += parses - p0;
|
||||
}
|
||||
|
||||
/* what the pad lends the frontend is what its reads say */
|
||||
{
|
||||
static const uint16_t dirs[4] = {
|
||||
HAT_UP_MASK, HAT_DOWN_MASK, HAT_LEFT_MASK, HAT_RIGHT_MASK };
|
||||
const input_pad_view_t *v;
|
||||
unsigned k, d, off = 0;
|
||||
winraw_joypad_by_poll = true;
|
||||
v = winraw_joypad_joypad_view(0);
|
||||
for (k = 0; k < 256; k++)
|
||||
if ((BIT256_GET(v->buttons, k) != 0)
|
||||
!= (winraw_joypad_joypad_button(0, (uint16_t)k) != 0))
|
||||
off++;
|
||||
for (k = 0; k < 4; k++)
|
||||
for (d = 0; d < 4; d++)
|
||||
if (((v->hats >> (k * 4 + d)) & 1) != (unsigned)(
|
||||
winraw_joypad_joypad_button(0,
|
||||
(uint16_t)HAT_MAP(k, dirs[d])) != 0))
|
||||
off++;
|
||||
for (k = 0; k < INPUT_PAD_VIEW_AXES; k++)
|
||||
if (v->axes[k] != (int16_t)(
|
||||
winraw_joypad_joypad_axis(0, AXIS_POS(k))
|
||||
+ winraw_joypad_joypad_axis(0, AXIS_NEG(k))))
|
||||
off++;
|
||||
if (off)
|
||||
{
|
||||
printf("FAIL burst %u: the lent state differs from the reads"
|
||||
" in %u places\n", burst, off);
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!same_state())
|
||||
{
|
||||
printf("FAIL burst %u (%u records): the newest-only state differs from"
|
||||
@@ -307,6 +337,7 @@ int main(void)
|
||||
}
|
||||
printf(" %lu reports in 20000 bursts: %lu parses holding the newest,"
|
||||
" %lu parsing every one\n", reports, parses_held, parses_every);
|
||||
printf("PASS winraw_joypad_newest_test: the state is the same after every burst\n");
|
||||
printf("PASS winraw_joypad_newest_test: the state is the same after every"
|
||||
" burst, and lent as its reads say\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -518,7 +518,7 @@ int main(void)
|
||||
xpad[0].sets, xpad[1].sets);
|
||||
/* A held on the pad in slot 0, which XInput has as its second */
|
||||
winraw_joypad_pads[0].num_buttons = 10;
|
||||
winraw_joypad_pads[0].buttons[0] = true;
|
||||
BIT256_SET(winraw_joypad_pads[0].view.buttons, 0);
|
||||
winraw_joypad_out_publish_buttons(&winraw_joypad_pads[0]);
|
||||
xpad[1].buttons = 0x1000;
|
||||
winraw_joypad_joypad_set_rumble(0, RETRO_RUMBLE_STRONG, 0x5000);
|
||||
|
||||
@@ -215,7 +215,7 @@ static bool poll_until(unsigned slot, unsigned b, bool want)
|
||||
for (tries = 0; tries < 200; tries++)
|
||||
{
|
||||
winraw_joypad_joypad_poll();
|
||||
if (winraw_joypad_pads[slot].buttons[b] == want)
|
||||
if ((WINRAW_BUTTON(&winraw_joypad_pads[slot], b) != 0) == want)
|
||||
return true;
|
||||
Sleep(5);
|
||||
}
|
||||
@@ -254,19 +254,19 @@ int main(void)
|
||||
winraw_joypad_add_device(H(2));
|
||||
CHECK(winraw_joypad_out[0].sixaxis && winraw_joypad_out[1].sixaxis,
|
||||
"the DualShock 3s were not taken as maybe on Sony's driver");
|
||||
CHECK(!winraw_joypad_pads[0].buttons[14],
|
||||
CHECK(!WINRAW_BUTTON(&winraw_joypad_pads[0], 14),
|
||||
"the state was read before a poll");
|
||||
CHECK(poll_until(0, 14, true), "the DualShock 3's state never reached the poll");
|
||||
CHECK(winraw_joypad_pads[0].num_buttons == 19
|
||||
&& winraw_joypad_pads[0].axes[0] == 0x7fff
|
||||
&& winraw_joypad_pads[0].axes[5] == 0x7fff
|
||||
&& winraw_joypad_pads[0].axes[1] < 300
|
||||
&& winraw_joypad_pads[0].axes[1] > -300,
|
||||
&& winraw_joypad_pads[0].view.axes[0] == 0x7fff
|
||||
&& winraw_joypad_pads[0].view.axes[5] == 0x7fff
|
||||
&& winraw_joypad_pads[0].view.axes[1] < 300
|
||||
&& winraw_joypad_pads[0].view.axes[1] > -300,
|
||||
"laid out wrong: %u buttons, axes %d %d %d",
|
||||
winraw_joypad_pads[0].num_buttons, winraw_joypad_pads[0].axes[0],
|
||||
winraw_joypad_pads[0].axes[1], winraw_joypad_pads[0].axes[5]);
|
||||
winraw_joypad_pads[0].num_buttons, winraw_joypad_pads[0].view.axes[0],
|
||||
winraw_joypad_pads[0].view.axes[1], winraw_joypad_pads[0].view.axes[5]);
|
||||
set_state(0, 1u << 16, 0x80, 0x80); /* PS */
|
||||
CHECK(poll_until(0, 16, true) && !winraw_joypad_pads[0].buttons[14],
|
||||
CHECK(poll_until(0, 16, true) && !WINRAW_BUTTON(&winraw_joypad_pads[0], 14),
|
||||
"a new state did not replace the last");
|
||||
asks = fake[0].asks;
|
||||
Sleep(200);
|
||||
|
||||
@@ -59,10 +59,11 @@
|
||||
* default mapping, a remap, analog-to-d-pad, the four turbo modes,
|
||||
* hold, and run-ahead; a recording of the pattern must play back
|
||||
* as the same sequence; and hosting netplay with nobody connected
|
||||
* must not change it. The mappings are run twice, reading the
|
||||
* driver directly and reading it through the snapshot bridge
|
||||
* (input plan, WP-03 and WP-05), and must give the same digests
|
||||
* both ways. This is the reference the frame-local view has to reproduce: it is
|
||||
* must not change it. The mappings are run three times, reading
|
||||
* the driver directly, through the snapshot bridge's copy (input
|
||||
* plan, WP-03 and WP-05), and through the pad's state the driver
|
||||
* lends the bridge, and must give the same digests each way; lent,
|
||||
* the driver is asked for nothing but the pad. This is the reference the frame-local view has to reproduce: it is
|
||||
* what the state path does today, pinned before that path changes.
|
||||
*
|
||||
* - The device registry (input plan, WP-02) follows the drivers.
|
||||
@@ -1206,6 +1207,31 @@ static void syn_get_buttons(unsigned pad, input_bits_t *state)
|
||||
BIT256_SET_PTR(state, i);
|
||||
}
|
||||
|
||||
/* The pad lent to the snapshot bridge in place of its copy, as a
|
||||
* driver whose state changes only in its poll lends it. */
|
||||
static unsigned long syn_calls_view;
|
||||
static input_pad_view_t syn_lent;
|
||||
|
||||
static const input_pad_view_t *syn_view(unsigned pad)
|
||||
{
|
||||
unsigned i;
|
||||
syn_calls_view++;
|
||||
memset(&syn_lent, 0, sizeof(syn_lent));
|
||||
if (pad != syn_pad_index)
|
||||
return &syn_lent;
|
||||
for (i = 0; i < 32; i++)
|
||||
if (syn_buttons & (1u << i))
|
||||
BIT256_SET(syn_lent.buttons, i);
|
||||
for (i = 0; i < 4; i++)
|
||||
syn_lent.axes[i] = syn_axes[i];
|
||||
syn_lent.hats = (uint16_t)(
|
||||
((syn_hat & HAT_UP_MASK) ? 1 : 0)
|
||||
| ((syn_hat & HAT_DOWN_MASK) ? 2 : 0)
|
||||
| ((syn_hat & HAT_LEFT_MASK) ? 4 : 0)
|
||||
| ((syn_hat & HAT_RIGHT_MASK) ? 8 : 0));
|
||||
return &syn_lent;
|
||||
}
|
||||
|
||||
/* The RetroPad mask from the binds, as every joypad driver builds it. */
|
||||
static int16_t syn_state(rarch_joypad_info_t *joypad_info,
|
||||
const uint16_t *joykeys, const uint32_t *joyaxes, unsigned port)
|
||||
@@ -1385,16 +1411,20 @@ static void lane_core_view(void)
|
||||
run_loop_frames(5);
|
||||
trace(0, 0);
|
||||
|
||||
/* Everything twice: read from the driver, as shipped, and read
|
||||
* through the snapshot bridge. The core must see the same. */
|
||||
for (bridged = 0; bridged < 2; bridged++)
|
||||
/* Everything three times: read from the driver, as shipped, read
|
||||
* through the snapshot bridge's copy, and through the state the
|
||||
* driver lends it. The core must see the same. */
|
||||
for (bridged = 0; bridged < 3; bridged++)
|
||||
{
|
||||
unsigned long frames_run = 0;
|
||||
|
||||
input_driver_set_snapshot_bridge(false);
|
||||
syn_joypad.view = (bridged == 2) ? syn_view : NULL;
|
||||
input_driver_set_snapshot_bridge(bridged != 0);
|
||||
run_loop_frames(5);
|
||||
syn_calls_state = 0;
|
||||
syn_calls_other = 0;
|
||||
syn_calls_view = 0;
|
||||
|
||||
for (sc = 0; sc < VIEW_SCENARIOS; sc++)
|
||||
{
|
||||
@@ -1466,7 +1496,8 @@ static void lane_core_view(void)
|
||||
"core view: input was not polled once a frame");
|
||||
if (input_st->turbo_btns.count != VIEW_FRAMES)
|
||||
fprintf(stderr, " %s%s: %u polls in %u frames\n", golden[sc].name,
|
||||
bridged ? ", through the snapshot bridge" : "",
|
||||
bridged == 2 ? ", lent to the snapshot bridge"
|
||||
: bridged ? ", through the snapshot bridge" : "",
|
||||
(unsigned)input_st->turbo_btns.count, (unsigned)VIEW_FRAMES);
|
||||
|
||||
/* run-ahead by one frame runs the core twice an iterate; if it
|
||||
@@ -1500,8 +1531,9 @@ static void lane_core_view(void)
|
||||
printf("[info] core view, %s: digest %08x over %u frames\n",
|
||||
golden[sc].name, (unsigned)digest, (unsigned)VIEW_FRAMES);
|
||||
if (bridged && digest != golden[sc].digest)
|
||||
fprintf(stderr, " %s, through the snapshot bridge: digest %08x\n",
|
||||
golden[sc].name, (unsigned)digest);
|
||||
fprintf(stderr, " %s, %s: digest %08x\n", golden[sc].name,
|
||||
bridged == 2 ? "lent to the snapshot bridge"
|
||||
: "through the snapshot bridge", (unsigned)digest);
|
||||
if (differ)
|
||||
fprintf(stderr, " %s: %u frame(s) differ between the two"
|
||||
" readings; frame %u read %04x button by button and %04x"
|
||||
@@ -1533,9 +1565,21 @@ static void lane_core_view(void)
|
||||
/* Who read the driver. Through the bridge its state() is not called
|
||||
* at all, and what is called is the copy being taken. */
|
||||
printf("[info] core view, %s: %.1f calls into the driver a frame\n",
|
||||
bridged ? "through the snapshot bridge" : "read from the driver",
|
||||
frames_run ? (double)(syn_calls_state + syn_calls_other) / frames_run : 0.0);
|
||||
if (bridged)
|
||||
bridged == 2 ? "lent to the snapshot bridge"
|
||||
: bridged ? "through the snapshot bridge" : "read from the driver",
|
||||
frames_run ? (double)(syn_calls_state + syn_calls_other
|
||||
+ syn_calls_view) / frames_run : 0.0);
|
||||
/* Lent, the pad is read where the driver keeps it: the driver is
|
||||
* asked for it once a poll and for nothing else. */
|
||||
if (bridged == 2)
|
||||
{
|
||||
CHECK(syn_calls_other == 0 && syn_calls_view > 0,
|
||||
"core view: a lent pad was still read through the driver");
|
||||
if (syn_calls_other)
|
||||
fprintf(stderr, " %lu reads through the driver, %lu views\n",
|
||||
syn_calls_other, syn_calls_view);
|
||||
}
|
||||
if (bridged == 1)
|
||||
{
|
||||
/* Something reads every axis for a few frames, as the bind
|
||||
* screen does. Once it stops, the copy must go back to what the
|
||||
@@ -1721,9 +1765,9 @@ static void lane_core_view(void)
|
||||
run_loop_frames(5);
|
||||
if (failures == had)
|
||||
printf("[pass] core view: button by button and as a mask agree, match"
|
||||
" the recorded digests read from the driver and through the"
|
||||
" snapshot bridge, play back from a recording, and are the same"
|
||||
" under netplay\n");
|
||||
" the recorded digests read from the driver, through the"
|
||||
" snapshot bridge's copy and lent to it, play back from a"
|
||||
" recording, and are the same under netplay\n");
|
||||
#else
|
||||
printf("[skip] core-view lane: need the test drivers and dlopen\n");
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user