-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[jak 2] Fix possible stereo desync in overlord #2663
Conversation
u32 GetSpuRamAddress(VagCmd* param_1) { | ||
bool bVar1; | ||
u32 uVar2; | ||
u32 uVar3; | ||
u32 uVar4; | ||
u32 uVar5; | ||
u32 uVar6; | ||
u32 uVar7; | ||
|
||
uVar7 = param_1->spu_stream_dma_mem_addr; | ||
uVar6 = (param_1->voice & 0xffffU) | 0x2240; | ||
do { | ||
uVar5 = 0; | ||
do { | ||
uVar2 = sceSdGetAddr(uVar6); | ||
uVar3 = sceSdGetAddr(uVar6); | ||
uVar4 = sceSdGetAddr(uVar6); | ||
// printf("got nax: %d\n", uVar3); | ||
if ((uVar2 == uVar3) || | ||
((uVar3 != uVar4 && (bVar1 = uVar2 == uVar4, uVar4 = uVar5, bVar1)))) { | ||
uVar4 = uVar2; | ||
} | ||
uVar5 = uVar4; | ||
} while (uVar4 == 0); | ||
} while ((uVar4 < uVar7) || (uVar7 + 0x4040 <= uVar4)); | ||
return uVar4; | ||
// this is simplified a lot from the original. | ||
// they seem to sanity check if the value is reasonable or not, but the sanity check can fail | ||
// if the overlord thread isn't keeping up. | ||
// as far as I can tell, it's totally fine to discard these checks because our sceSdGetAddr | ||
// works perfectly. | ||
return sceSdGetAddr((param_1->voice & 0xffffU) | 0x2240); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's two things going on here. There's the safety check of calling sceSdGetAddr three times, this is because the SPU address registers are composed of two 16bit registers which means there's risk of tearing when reading. This part can safely be omitted for us.
The other check seems to be that the address is contained within the allocated region (0x4040 bytes), if this is actually happening it means the voice has escaped the allocated area, this might be kinda bad if it actually happens for us.
Normally, when they allocate a VagCmd, they do a bunch of stuff to clear all the status bits and reset things
in particular the InitVAGCmd function does a lot
but for the stereo command, they do a lot less:
Which means that the new_stereo_command can just have random status bits left over from whatever the last user had.
we seem to end up in a state where byte21 is set, and this causes everything else to be wrong and off-by-one dma transfer. My guess is that the original game avoided this bug due to lucky timing that I don't understand.
I think the fix of just clearing byte21 is ok because there's no way that the old value of the byte is useful after the command is repurposed.