Maple controller input polls not behaving as expected

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
User avatar
Protofall
DCEmu Cool Newbie
DCEmu Cool Newbie
Posts: 12
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Maple controller input polls not behaving as expected

Post by Protofall » Fri Nov 09, 2018 6:32 am

I've encountered a very odd bug in my program that doesn't make sense to me and its presence is random (Something as simple as displaying more sprites on screen or extra counters can prevent this bug from occurring for some reason). I noticed my code sometimes wouldn't respond correctly to button presses. I would press a button (A, B, X or Y) and expect the correct actions to be performed, but sometimes I have to press 5 times before it finally works, then a few more times for it to work again, etc. In other words I had a random bug that randomly "dropped" some of my inputs.

My program is too large to post in full here, however here is a slimmed down snippet where the issue is occurring
uint8_t successful_b_presses_just_after = 0;
uint8_t successful_b_presses_active_just_after = 0;
uint8_t successful_b_presses_long_after = 0;
uint8_t successful_b_presses_active_long_after = 0;
uint32_t previous_buttons[4] = {0};

while(1){		
	MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)

	//other thumbstick code

	//Use the buttons previously pressed to control what happens here
	button_action = 0;
	button_action |= ((previous_buttons[__dev->port] & CONT_A) && !(st->buttons & CONT_A)) << 0;	//A released
	button_action |= ((previous_buttons[__dev->port] & CONT_X) && !(st->buttons & CONT_X)) << 1;	//X released
	button_action |= (!(previous_buttons[__dev->port] & CONT_B) && (st->buttons & CONT_B)) << 2;	//B pressed
	button_action |= (!(previous_buttons[__dev->port] & CONT_Y) && (st->buttons & CONT_Y)) << 3;	//Y pressed

	if(button_action & (1 << 2)){
		successful_b_presses_active_just_after++;
	}

	if(!(previous_buttons[__dev->port] & CONT_B) && (st->buttons & CONT_B)){
		successful_b_presses_just_after++;
	}

	//stuff that reads button_action, but does not change it

	//Every time you perform a successful b press (active), we increment it
	if(button_action & (1 << 2)){
		successful_b_presses_active_long_after++;
	}

	//Every time you perform a successful b press, we increment it
	if(!(previous_buttons[__dev->port] & CONT_B) && (st->buttons & CONT_B)){
		successful_b_presses_long_after++;
	}

	//Press Y to end
	if(st->buttons & (CONT_Y)){
		error_freeze("JA, LA (norm/active): %d, %d, %d, %d", successful_b_presses_just_after, successful_b_presses_active_just_after, successful_b_presses_long_after, successful_b_presses_active_long_after);
	}

	//Other maple stuff

	previous_buttons[__dev->port] = st->buttons;
	MAPLE_FOREACH_END()

	//Graphics stuff

}
To summarise I poll input, use the input to build my "button_action" variable, have some debug counters (just_after), use the "button_action" variable for some computations, have some more debug counters (long_after), a check to see if the user is pressing Y (Which will stop the program and present a screen displaying the message within the function error_freeze()) and ending with me storing the polled buttons into my "previous_buttons" variable for the next iteration/frame.

I ran this program on real hardware, pressed the B button 5 times (The press "failed" the first 4 times and succeeded the last time) then I pressed Y to end the program and give me the debug message which reads "JA, LA (norm/active): 1, 1, 5, 1". This tells me that somehow it re-polled the controller input between the two "just_after" and "long_after" debug counter sections which explains why my "button_action" variable wasn't what I was expecting.

I don't have a good enough understanding of the DC or the internals of KOS to understand how st->buttons could be updating itself mid loop and if its just some DC limitation/bug, a bug with KOS or something else. I've thought of a ghetto fix where I poll and instantly store the current buttons into a separate variable and use that instead of st->buttons for the rest of the computation, but that would still have some minor issues and it still doesn't fix/explain whats really happening.

Some other things to note: If I have multiple controllers plugged in, the first controller inline gets affected the most with later controllers not being affected much if at all (So if we have Port 1 and 3 active, then port 1 has lots of "dropped" input and port 3 seems to be fine). Also from what I can understand, the bug seems to be more common when there's more stuff to draw (And due to how my program works that also means more of main memory is used to store positions, UVs and such), but I don't really get why and like I said at the beginning, I can get the bug to "completely fix itself with no "dropped" inputs" by drawing a few extra sprites on screen.
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
User avatar
lerabot
Insane DCEmu
Insane DCEmu
Posts: 109
Joined: Sun Nov 01, 2015 8:25 pm

Re: Maple controller input polls not behaving as expected

Post by lerabot » Sun Nov 11, 2018 11:02 am

I don't know how to approach your code tbh, but the previous code you submitted for the github/wiki think handled inputs just fine, right?
User avatar
Protofall
DCEmu Cool Newbie
DCEmu Cool Newbie
Posts: 12
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Re: Maple controller input polls not behaving as expected

Post by Protofall » Sun Nov 11, 2018 5:17 pm

lerabot wrote:
Sun Nov 11, 2018 11:02 am
I don't know how to approach your code tbh, but the previous code you submitted for the github/wiki think handled inputs just fine, right?
I should update my project's input code to what I used in the github sound example, but I don't think that would fix this issue. In the sound example we have an extra variable "changed_buttons" which is equal to

Code: Select all

changed_buttons = current_state->buttons ^ previous_buttons; //current_state is the same as st in my project
We then use changed_buttons and current_state->buttons for all calculations and then at the end of the loop we set previous_buttons to current_state->buttons. We also have some nice functions that would be useful for my "button_action" variable
uint8_t isButtonPressed(changed_buttons, current_state, button)
Normally both the sound example and my project's input methods are fine, but under some situations in my project, st->buttons changes mid-loop (It seems to be more common when I'm drawing a lot of sprites which is at most about 900, but like mentioned before its not consistent). In my project I poll input with "MAPLE_FOREACH_BEGIN", and its stored in the state variable "st" I then use st->buttons and previous_buttons to generate my "button_action" variable which I refer to in my calculations. At some point during the "//stuff that reads button_action, but does not change it" section the st variable changes for some reason (Hence the two groups of counters are desync-ed).

Using the sound example method wouldn't help because "changed_buttons" is set at the beginning of the loop and is used for all calculations. st/current_state would still change mid loop which would throw off some of the calculations (Since changed_buttons depended on st/current_state) and at the end previous_buttons is set like normal.

Here's an example with the sound example's input method. We poll st/current_state and see B isn't pressed (And in this example previous_buttons doesn't have the B button bit set either), then we generate changed_buttons and see the B button hasn't changed state so we set it to zero. Then st/current_state changes shortly after (The issue/bug) to say that B button bit is set/being held. We then call our "isButtonPressed/Released" functions and we see B hasn't been Pressed since the B bit in changed_buttons is set to zero so we don't perform the B pressed code. At the end of the loop previous_buttons is set to the latest st/current_state->buttons (Which contains the B button bit set to true/1). So next loop we'll either detect B being held or released (Depends if st/current_state->buttons & (CONT_B) true or false). Either way the B pressed input is dropped/missed because the st/current_state is changing mid execution and I can't explain why.

(For those who don't know the sound example can be found here: https://github.com/dreamcastdevs/dreamc ... sfx_player)
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
User avatar
snickerbockers
DCEmu Newbie
DCEmu Newbie
Posts: 9
Joined: Tue Mar 06, 2018 8:11 pm
Contact:

Re: Maple controller input polls not behaving as expected

Post by snickerbockers » Wed Nov 14, 2018 4:18 am

Protofall wrote:
Fri Nov 09, 2018 6:32 am
I don't have a good enough understanding of the DC or the internals of KOS to understand how st->buttons could be updating itself mid loop and if its just some DC limitation/bug, a bug with KOS or something else
It happens once per vblank, and vblanks happen 25, 30, 50 or 60 times per second depending on your video settings. The cont_state_t that MAPLE_FOREACH_BEGIN gives you is the exact same one that the IRQ updates, so st->buttons can actually change asynchronously.

Protofall wrote:
Fri Nov 09, 2018 6:32 am
Some other things to note: If I have multiple controllers plugged in, the first controller inline gets affected the most with later controllers not being affected much if at all (So if we have Port 1 and 3 active, then port 1 has lots of "dropped" input and port 3 seems to be fine). Also from what I can understand, the bug seems to be more common when there's more stuff to draw (And due to how my program works that also means more of main memory is used to store positions, UVs and such), but I don't really get why and like I said at the beginning, I can get the bug to "completely fix itself with no "dropped" inputs" by drawing a few extra sprites on screen.
Without the full source it's impossible to know, but maybe you're giving the DC so much work to do that the amount of time between subsequent maple polls is greater than the amount of time that the button is being held down? If you remove everything from your program except the input polling, does it still drop button presses?
User avatar
Protofall
DCEmu Cool Newbie
DCEmu Cool Newbie
Posts: 12
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Re: Maple controller input polls not behaving as expected

Post by Protofall » Wed Nov 14, 2018 5:20 am

snickerbockers wrote:
Wed Nov 14, 2018 4:18 am
Protofall wrote:
Fri Nov 09, 2018 6:32 am
I don't have a good enough understanding of the DC or the internals of KOS to understand how st->buttons could be updating itself mid loop and if its just some DC limitation/bug, a bug with KOS or something else
It happens once per vblank, and vblanks happen 25, 30, 50 or 60 times per second depending on your video settings. The cont_state_t that MAPLE_FOREACH_BEGIN gives you is the exact same one that the IRQ updates, so st->buttons can actually change asynchronously.

Protofall wrote:
Fri Nov 09, 2018 6:32 am
Some other things to note: If I have multiple controllers plugged in, the first controller inline gets affected the most with later controllers not being affected much if at all (So if we have Port 1 and 3 active, then port 1 has lots of "dropped" input and port 3 seems to be fine). Also from what I can understand, the bug seems to be more common when there's more stuff to draw (And due to how my program works that also means more of main memory is used to store positions, UVs and such), but I don't really get why and like I said at the beginning, I can get the bug to "completely fix itself with no "dropped" inputs" by drawing a few extra sprites on screen.
Without the full source it's impossible to know, but maybe you're giving the DC so much work to do that the amount of time between subsequent maple polls is greater than the amount of time that the button is being held down? If you remove everything from your program except the input polling, does it still drop button presses?
The vblank polling part makes sense. I'm running in video mode NTSC_IL or VGA mode (Both 60Hz, I haven't implemented PAL 50Hz support yet). "st" being able to be updated at any point makes sense too with my understanding since its kinda just a pointer to the maple buffer, but I thought the vblanks occur during "pvr_scene_finish()" so by the time the next loop arrives "st" is already set and hence this bug shouldn't happen. Or maybe I keep doing CPU work including the next loop while the vblanks happen and if the GPU takes too long then maybe I start handling the maple code too soon?

This bug is probably very project specific unfortunately. My project's identity is a secret for now, but I'll be revealing it within the month and eventually the whole project source code will be open source...however it might be a long while before it goes open source. My project is version controlled and I've made a separate branch to contain the version used from this post which includes the bug so it can easily be referred to later. Since making this post I've done a bunch of optimisations such as moving a lot of the draw code from the TR list to the OP and PT lists and there are less divisions going on than before (I understand that divisions on the Dreamcast are slow due to the SH-4 not really supporting them). Currently on emulators I haven't seen the bug again, but I haven't tested on hardware since making the original post. I'm fairly certain once I'm fully done with my optimisations this bug will "Disappear", but I'll report back on that after the optimisations.

I haven't tested removing everything but the input code recently, but when I'm more free I'll try that out. However the "dropped input" bug never appeared when I was drawing very little and started to become more and more common the more I drew (At most I say I'm drawing between 800 to 900 sprites (With about 800 being unnecessarily drawn in the TR list prior to my optimisation and together the sprites took up most of the screen. Oh and there is an opaque poly from 0,0 to 640,480 behind it so it would be doing a lot of blending calculations) and at the lowest my program is somewhere under 100 sprites).

"maple polls taking longer than the button being held down" If I'm interpreting what you're saying right, then you're saying my code just completely misses the fact that B was pressed at all? If so, that's false because if that were the case then my results in the original post when error_freeze() is triggered would be "JA, LA (norm/active): 1, 1, 1, 1", but the 3rd number is 5 because we saw that st->buttons recorded/polled the B press late. If you mean it missed just the initial press then yeah, it kinda does it just reads it later than I want.

(Sorry for long post :o )
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
User avatar
Quzar
Dream Coder
Dream Coder
Posts: 7478
Joined: Wed Jul 31, 2002 12:14 am
Location: Miami, FL
Contact:

Re: Maple controller input polls not behaving as expected

Post by Quzar » Thu Nov 15, 2018 3:33 pm

Are you working with threads in the source that gives you 1151? Additionally, have you tested checking merely for the presses, as opposed to checking specifically for presses where the previous detection was not a press?
"When you post fewer lines of text than your signature, consider not posting at all." - A Wise Man
User avatar
Protofall
DCEmu Cool Newbie
DCEmu Cool Newbie
Posts: 12
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Re: Maple controller input polls not behaving as expected

Post by Protofall » Thu Nov 15, 2018 10:00 pm

Quzar wrote:
Thu Nov 15, 2018 3:33 pm
Are you working with threads in the source that gives you 1151?
I haven't used threads/fork() yet, so no.
Quzar wrote:
Thu Nov 15, 2018 3:33 pm
Additionally, have you tested checking merely for the presses, as opposed to checking specifically for presses where the previous detection was not a press?
As in testing if "(st->buttons & CONT_B) > 0" without caring what previous_buttons/button_action are? I'm not sure if I tested that kind of case, but based on my results I'd assume it would still detect that statement, just a frame/loop late. The second half of your sentence looks like your saying I'm checking "(previous_buttons & CONT_B) == 0" which isn't true, I'm actually checking if previous wasn't pressed && current is pressed. Unless that was a typo and you already knew how it worked, whoops!
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
User avatar
Protofall
DCEmu Cool Newbie
DCEmu Cool Newbie
Posts: 12
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Re: Maple controller input polls not behaving as expected

Post by Protofall » Mon Nov 19, 2018 6:56 am

I've tested today on hardware and after my optimisations it appears this input bug isn't present anymore.
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
Post Reply