Skip to content
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

[TESTERS NEEDED] cellAtracXdec implementation #15538

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

capriots
Copy link
Contributor

  • Full implementation of cellAtracXdec using FFmpeg
  • One limitation: FFmpeg doesn't provide detailed errors on invalid input, so I'm just using a generic error code if decoding fails
  • Downmixing is completely broken on LLE because the PPU thread sends a wrong command to the SPU thread, so I didn't bother implementing this
  • There are no memory allocations aside from FFmpeg, I'm using the buffer provided by the game. FFmpeg is also setup to read from and write to the same memory locations the SPU thread would.
  • Savestate compatible
  • I set it to HLE by default, but if any issue is found in testing that I am unable to fix then I will revert this for now

Known issues

  • Deadstorm Pirates sound issues #13168 is heavily amplified. With HLE, music stops playing within seconds of reaching the main menu.
    The issue is caused by the game sending invalid data to the decoder. The thread "bnusCoreDecoderAT3PThread" then just exits when it receives the error. I assume this is because of a race condition in the game. I tried slowing down the decoder thread to match realhw as closely as possible, but that didn't improve anything.
    I was able to trigger this issue in Tales of Xillia 1+2 and Tekken 6 as well, it's likely other NU engine games are also affected.
    Setting PPU Thread Count to 1 still works around the issue with HLE.

ensure(handle.aligned(0x80)); // LLE cellAdec aligns the address to 128 bytes
ensure(!!notifyAuDone && !!notifyAuDoneArg && !!notifyPcmOut && !!notifyPcmOutArg && !!notifyError && !!notifyErrorArg && !!notifySeqDone && !!notifySeqDoneArg); // These should always be set by LLE cellAdec

new (handle.get_ptr()) AtracXdecContext(notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Write out the context using wrote_to_ptr.

handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, spursRes);

ensure(!!handle && !!res); // Not checked on LLE
ensure(handle.aligned(0x80)); // LLE cellAdec aligns the address to 128 bytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then align it down manually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my comment there was a bit confusing. This function on LLE does not align the address manually or check the alignment. I've rewritten it to make it clearer.

return handle->send_command<AtracXdecCmdType::decode_au>(ppu, pcmHandle, *auInfo);
}

void _CellAdecCoreOpGetVersion_atracx(vm::ptr<std::array<u8, 4>> version)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simply use vm::ptr<u8[4]>, I think its unspecifued behavior for std::array to match c array in byte size.

// For savestates, restore argument
idm::get<named_thread<ppu_thread>>(static_cast<u32>(atxdec->thread_id))->cmd_list
({
{ ppu_cmd::set_args, 1 }, static_cast<u64>(atxdec.addr()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Dont check thread_state::state for it, check cpu_flag::again state if it was raised inside exec(). (checking the reason the thread was aborted)
  2. When ::again flag is set, whats saved in r3 to r6 is ppu_thread::syscall_args, so you rather save to syscall_args[0] instead of this.

queue_not_empty.wait(queue_mutex, 20000);
}

if (!run_thread || thread_ctrl::state() == thread_state::aborting)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather, check cpu_thread::is_stopped(), raise ::again flag if stopped.

{
ensure(!!handle && !!pcmStartAddr); // Not checked on LLE

std::memcpy(outBuffer.get_ptr(), pcmStartAddr.get_ptr(), handle->decoder.pcm_output_size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be an assert before this, checking memory safety with vm::check_addr.


if (sample >= std::bit_cast<f32>(std::bit_cast<u32>(1.f) - 1))
{
output_f32[sample_idx * decoder.nch_in + ATXDEC_AVCODEC_CH_MAP[decoder.ch_config_idx - 1][channel_idx]] = std::bit_cast<be_t<f32>>(std::array<u8, 4>{ 0x3f, 0x7f, 0xff, 0xff }); // Prevents an unnecessary endian swap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can do something like "\x37\x7f\xff\xff"_u32 (resulting in u32)

@elad335 elad335 self-requested a review May 7, 2024 06:51
@elad335 elad335 added the Savestates Anything that involves savestates label May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Firmware: HLE Savestates Anything that involves savestates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants