From c175cdf3d8b9ac49274e5cefc01e93bfe3ee376b Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 24 Apr 2022 13:52:51 +0200 Subject: [PATCH] cellVdec: send AUDONE even when the queue is being flushed/restarted Fixes GT6 regression --- rpcs3/Emu/Cell/Modules/cellVdec.cpp | 56 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 3d6357de3a..c3b0b42dc0 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -393,7 +393,7 @@ struct vdec_context final std::deque decoded_frames; - if (!abort_decode) + if (!abort_decode && seq_id == cmd->seq_id) { cellVdec.trace("AU decoding: handle=0x%x, seq_id=%d, cmd_id=%d, size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx", handle, cmd->seq_id, cmd->id, au_size, au_pts, au_dts, au_usrd); @@ -402,11 +402,11 @@ struct vdec_context final fmt::throw_exception("AU queuing error (handle=0x%x, seq_id=%d, cmd_id=%d, error=0x%x): %s", handle, cmd->seq_id, cmd->id, ret, utils::av_error_to_string(ret)); } - while (!abort_decode) + while (!abort_decode && seq_id == cmd->seq_id) { // Keep receiving frames vdec_frame frame; - frame.cmd_id = cmd->seq_id; + frame.seq_id = cmd->seq_id; frame.cmd_id = cmd->id; frame.avf.reset(av_frame_alloc()); @@ -534,8 +534,9 @@ struct vdec_context final } } - if (thread_ctrl::state() != thread_state::aborting && !abort_decode) + if (thread_ctrl::state() != thread_state::aborting) { + // Send AUDONE even if the current sequence was reset and a new sequence was started. cellVdec.trace("Sending CELL_VDEC_MSG_TYPE_AUDONE (handle=0x%x, seq_id=%d, cmd_id=%d)", handle, cmd->seq_id, cmd->id); cb_func(ppu, vid, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, cb_arg); lv2_obj::sleep(ppu); @@ -545,12 +546,12 @@ struct vdec_context final --au_count; } - while (!decoded_frames.empty()) + while (!decoded_frames.empty() && seq_id == cmd->seq_id) { // Wait until there is free space in the image queue. // Do this after pushing the frame to the queue. That way the game can consume the frame and we can move on. u32 elapsed = 0; - while (thread_ctrl::state() != thread_state::aborting && !abort_decode) + while (thread_ctrl::state() != thread_state::aborting && !abort_decode && seq_id == cmd->seq_id) { { std::lock_guard lock{mutex}; @@ -569,7 +570,7 @@ struct vdec_context final } } - if (thread_ctrl::state() == thread_state::aborting || abort_decode) + if (thread_ctrl::state() == thread_state::aborting || abort_decode || seq_id != cmd->seq_id) { break; } @@ -586,7 +587,7 @@ struct vdec_context final } } - if (abort_decode) + if (abort_decode || seq_id != cmd->seq_id) { cellVdec.warning("AU decoding: aborted (handle=0x%x, seq_id=%d, cmd_id=%d, abort_decode=%d)", handle, cmd->seq_id, cmd->id, abort_decode.load()); } @@ -979,27 +980,10 @@ error_code cellVdecStartSeq(u32 handle) const u64 cmd_id = vdec->next_cmd_id++; cellVdec.trace("Adding start cmd (handle=0x%x, seq_id=%d, cmd_id=%d)", handle, seq_id, cmd_id); - vdec->abort_decode = true; + vdec->abort_decode = false; vdec->is_running = false; vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::start_sequence, seq_id, cmd_id)); - // Wait until the thread is ready - u32 elapsed = 0; - while (thread_ctrl::state() != thread_state::aborting) - { - if (vdec->is_running) - { - break; - } - thread_ctrl::wait_for(1000); - - if (elapsed++ >= 5000) // 5 seconds - { - cellVdec.error("Timeout in cellVdecStartSeq."); - elapsed = 0; - } - } - std::lock_guard lock{vdec->mutex}; if (false) // TODO: set to old state in case of error @@ -1038,7 +1022,7 @@ error_code cellVdecEndSeq(u32 handle) const u64 seq_id = vdec->seq_id; const u64 cmd_id = vdec->next_cmd_id++; - cellVdec.trace("Adding end cmd (handle=0x%x, seq_id=d, cmd_id=%d)", handle, seq_id, cmd_id); + cellVdec.trace("Adding end cmd (handle=0x%x, seq_id=%d, cmd_id=%d)", handle, seq_id, cmd_id); vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::end_sequence, seq_id, cmd_id)); @@ -1182,6 +1166,8 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr format vdec_frame frame; bool notify = false; + u64 sequence_id{}; + { std::lock_guard lock(vdec->mutex); @@ -1191,6 +1177,7 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr format } frame = std::move(vdec->out_queue.front()); + sequence_id = vdec->seq_id; vdec->out_queue.pop_front(); if (vdec->out_queue.size() + 1 == vdec->out_max) @@ -1203,6 +1190,11 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr format if (vdec_ppu) thread_ctrl::notify(*vdec_ppu); } + if (sequence_id != frame.seq_id) + { + return { CELL_VDEC_ERROR_EMPTY, "sequence_id=%d, seq_id=%d", sequence_id, frame.seq_id }; + } + if (outBuff) { const int w = frame->width; @@ -1245,7 +1237,7 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr format fmt::throw_exception("cellVdecGetPictureExt: Unknown frame format (%d)", frame->format); } - cellVdec.trace("cellVdecGetPictureExt: handle=0x%x, seq_id=d, cmd_id=%d, w=%d, h=%d, frameFormat=%d, formatType=%d, in_f=%d, out_f=%d, alpha_plane=%d, alpha=%d, colorMatrixType=%d", handle, frame.seq_id, frame.cmd_id, w, h, frame->format, format->formatType, +in_f, +out_f, !!alpha_plane, format->alpha, format->colorMatrixType); + cellVdec.trace("cellVdecGetPictureExt: handle=0x%x, seq_id=%d, cmd_id=%d, w=%d, h=%d, frameFormat=%d, formatType=%d, in_f=%d, out_f=%d, alpha_plane=%d, alpha=%d, colorMatrixType=%d", handle, frame.seq_id, frame.cmd_id, w, h, frame->format, format->formatType, +in_f, +out_f, !!alpha_plane, format->alpha, format->colorMatrixType); vdec->sws = sws_getCachedContext(vdec->sws, w, h, in_f, w, h, out_f, SWS_POINT, nullptr, nullptr, nullptr); @@ -1312,6 +1304,8 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) return CELL_VDEC_ERROR_ARG; } + u64 sequence_id{}; + { std::lock_guard lock{vdec->mutex}; @@ -1319,6 +1313,8 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) { return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() }; } + + sequence_id = vdec->seq_id; } struct all_info_t @@ -1368,10 +1364,10 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) } } - if (!frame) + if (!frame || seq_id != sequence_id) { // If frame is empty info was not found - return CELL_VDEC_ERROR_EMPTY; + return { CELL_VDEC_ERROR_EMPTY, " frame=%d, sequence_id=%d, seq_id=%d", !!frame, sequence_id, seq_id }; } info->codecType = vdec->type;