diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp index 97f7a1a188..43c5f7989b 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -696,12 +696,12 @@ error_code adecNotifyPcmOut(ppu_thread& ppu, s32 pcmHandle, vm::ptr pcmAdd return CELL_ADEC_ERROR_FATAL; } - if (handle->pcm_queue.push(pcm_item, pcmHandle) != CELL_OK) + if (handle->pcm_queue.push(ppu, pcm_item, pcmHandle) != CELL_OK) { return CELL_ADEC_ERROR_FATAL; } - if (handle->pcm_item_queue.push(pcm_item, pcmHandle) != CELL_OK) + if (handle->pcm_item_queue.push(ppu, pcm_item, pcmHandle) != CELL_OK) { return CELL_ADEC_ERROR_FATAL; } @@ -804,7 +804,6 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptrgetBsiInfoSize(ppu); const auto _this = vm::ptr::make(utils::align(+res->startAddr, 0x80)); - const u32 this_size = sizeof(AdecContext) + (bitstream_info_size + sizeof(AdecFrame)) * pcm_handle_num; const auto frames = vm::ptr::make(_this.addr() + sizeof(AdecContext)); const u32 bitstream_infos_addr = frames.addr() + pcm_handle_num * sizeof(AdecFrame); const auto core_handle = vm::ptr::make(utils::align(bitstream_infos_addr + bitstream_info_size * pcm_handle_num, 0x80)); @@ -818,7 +817,43 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptr_this = _this; + _this->this_size = sizeof(AdecContext) + (bitstream_info_size + sizeof(AdecFrame)) * pcm_handle_num; + _this->unk = 0; + _this->sequence_state = AdecSequenceState::dormant; + _this->type = *type; + _this->res = *res; + _this->callback = *cb; + _this->core_handle = core_handle; + _this->core_ops = core_ops; + _this->previous_pts = { CODEC_TS_INVALID, CODEC_TS_INVALID }; + _this->frames_num = pcm_handle_num; + _this->reserved1 = 0; + _this->frames_head = -1; + _this->frames_tail = -1; + _this->frames = frames; + _this->bitstream_info_size = bitstream_info_size; + _this->mutex_attribute = { SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem03"_u64 } }; + + _this->pcm_queue.init(ppu, _this.ptr(&AdecContext::pcm_queue)); + _this->pcm_item_queue.init(ppu, _this.ptr(&AdecContext::pcm_item_queue)); + + for (s32 i = 0; i < pcm_handle_num; i++) + { + frames[i].in_use = false; + frames[i].this_index = i; + frames[i].au_done = false; + frames[i].unk1 = false; + frames[i].pcm_out = false; + frames[i].unk2 = false; + frames[i].pcm_item.pcmAttr.bsiInfo.set(bitstream_infos_addr + bitstream_info_size * i); + frames[i].reserved1 = 0; + frames[i].reserved2 = 0; + frames[i].next = 0; + frames[i].prev = 0; + } + + ensure(sys_mutex_create(ppu, _this.ptr(&AdecContext::mutex), _this.ptr(&AdecContext::mutex_attribute)) == CELL_OK); // Error code isn't checked on LLE *handle = _this; @@ -901,6 +936,16 @@ error_code cellAdecClose(ppu_thread& ppu, vm::ptr handle) return ret; } + if (error_code ret = handle->pcm_queue.finalize(ppu); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = handle->pcm_item_queue.finalize(ppu); ret != CELL_OK) + { + return ret; + } + handle->_this = vm::null; handle->sequence_state = AdecSequenceState::closed; @@ -1038,12 +1083,12 @@ error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr handle, vm::ptr< } // If the pcm_handles are equal, then cellAdecGetPcmItem() was not called before cellAdecGetPcm(). We need to pop pcm_item_queue as well - if (handle->pcm_item_queue.peek().pcm_handle == handle->pcm_queue.peek().pcm_handle) + if (handle->pcm_item_queue.peek(ppu).pcm_handle == handle->pcm_queue.peek(ppu).pcm_handle) { - handle->pcm_item_queue.pop(); + handle->pcm_item_queue.pop(ppu); } - const auto pcm_queue_entry = handle->pcm_queue.pop(); + const auto pcm_queue_entry = handle->pcm_queue.pop(ppu); if (!pcm_queue_entry) { @@ -1082,7 +1127,7 @@ error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr handle, vm::ptr< return CELL_OK; } -error_code cellAdecGetPcmItem(vm::ptr handle, vm::pptr pcmItem) +error_code cellAdecGetPcmItem(ppu_thread& ppu, vm::ptr handle, vm::pptr pcmItem) { cellAdec.trace("cellAdecGetPcmItem(handle=*0x%x, pcmItem=**0x%x)", handle, pcmItem); @@ -1096,7 +1141,12 @@ error_code cellAdecGetPcmItem(vm::ptr handle, vm::pptrpcm_item_queue.pop(); + const auto pcm_item_entry = handle->pcm_item_queue.pop(ppu); + + if (ppu.state & cpu_flag::again) // Savestate was created while waiting on the queue mutex + { + return {}; + } if (!pcm_item_entry) { diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h index a9bd664fa5..1cbeca08b8 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.h +++ b/rpcs3/Emu/Cell/Modules/cellAdec.h @@ -2,6 +2,7 @@ #include "cellPamf.h" // CellCodecTimeStamp #include "../lv2/sys_mutex.h" +#include "../lv2/sys_cond.h" // Error Codes enum CellAdecError : u32 @@ -461,31 +462,25 @@ struct AdecCmdQueue struct AdecFrame { - b8 in_use = false; // True after issuing a decode command until the frame is consumed + b8 in_use; // True after issuing a decode command until the frame is consumed - const be_t this_index; // Set when initialized in cellAdecOpen(), unused afterward + be_t this_index; // Set when initialized in cellAdecOpen(), unused afterward // Set when the corresponding callback is received, unused afterward - b8 au_done = false; - const b8 unk1 = false; - b8 pcm_out = false; - const b8 unk2 = false; + b8 au_done; + b8 unk1; + b8 pcm_out; + b8 unk2; CellAdecAuInfo au_info; CellAdecPcmItem pcm_item; - const u32 reserved1 = 0; - const u32 reserved2 = 0; + u32 reserved1; + u32 reserved2; // Frames that are ready to be consumed form a linked list. However, this list is not used (AdecOutputQueue is used instead) - be_t next = 0; // Index of the next frame that can be consumed - be_t prev = 0; // Index of the previous frame that can be consumed - - AdecFrame(s32 index, u32 bitstream_info_addr) - : this_index(index) - { - pcm_item.pcmAttr.bsiInfo.set(bitstream_info_addr); - } + be_t next; // Index of the next frame that can be consumed + be_t prev; // Index of the previous frame that can be consumed }; CHECK_SIZE(AdecFrame, 0x68); @@ -494,27 +489,61 @@ class AdecOutputQueue { struct entry { - const be_t this_index; // Unused - be_t state = 0xff; // 0xff = empty, 0x10 = filled - vm::bptr pcm_item = vm::null; - be_t pcm_handle = -1; + be_t this_index; // Unused + be_t state; // 0xff = empty, 0x10 = filled + vm::bptr pcm_item; + be_t pcm_handle; } - entries[4]{ {0}, {1}, {2}, {3} }; + entries[4]; - be_t front = 0; - be_t back = 0; - be_t size = 0; + be_t front; + be_t back; + be_t size; - shared_mutex mutex; // sys_mutex_t - be_t cond{}; // sys_cond_t, unused + be_t mutex; // sys_mutex_t + be_t cond; // sys_cond_t, unused public: - error_code push(vm::ptr pcm_item, s32 pcm_handle) + void init(ppu_thread& ppu, vm::ptr _this) { - std::lock_guard lock{mutex}; + this->front = 0; + this->back = 0; + this->size = 0; + + const vm::var mutex_attr = {{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem07"_u64 } }}; + ensure(sys_mutex_create(ppu, _this.ptr(&AdecOutputQueue::mutex), mutex_attr) == CELL_OK); // Error code isn't checked on LLE + + const vm::var cond_attr = {{ SYS_SYNC_NOT_PROCESS_SHARED, 0, 0, { "_adec05"_u64 } }}; + ensure(sys_cond_create(ppu, _this.ptr(&AdecOutputQueue::cond), mutex, cond_attr) == CELL_OK); // Error code isn't checked on LLE + + for (s32 i = 0; i < 4; i++) + { + entries[i] = { i, 0xff, vm::null, -1 }; + } + } + + error_code finalize(ppu_thread& ppu) const + { + if (error_code ret = sys_cond_destroy(ppu, cond); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = sys_mutex_destroy(ppu, mutex); ret != CELL_OK) + { + return ret; + } + + return CELL_OK; + } + + error_code push(ppu_thread& ppu, vm::ptr pcm_item, s32 pcm_handle) + { + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE if (entries[back].state != 0xff) { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE return true; // LLE returns the result of the comparison above } @@ -525,15 +554,17 @@ public: back = (back + 1) & 3; size++; + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE return CELL_OK; } - const entry* pop() + const entry* pop(ppu_thread& ppu) { - std::lock_guard lock{mutex}; + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE if (entries[front].state == 0xff) { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE return nullptr; } @@ -545,13 +576,16 @@ public: front = (front + 1) & 3; size--; + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE return ret; } - const entry& peek() + const entry& peek(ppu_thread& ppu) const { - std::lock_guard lock{mutex}; - return entries[front]; + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + const entry& ret = entries[front]; + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; } }; @@ -567,30 +601,30 @@ enum class AdecSequenceState : u32 struct AdecContext // CellAdecHandle = AdecContext* { vm::bptr _this; - const be_t this_size; // Size of this struct + AdecFrames + bitstream info structs + be_t this_size; // Size of this struct + AdecFrames + bitstream info structs - const u32 unk = 0; // Unused + u32 unk; // Unused - be_t sequence_state = AdecSequenceState::dormant; + be_t sequence_state; - const CellAdecType type; - const CellAdecResource res; - const CellAdecCb callback; + CellAdecType type; + CellAdecResource res; + CellAdecCb callback; - const vm::bptr core_handle; - const vm::bcptr core_ops; + vm::bptr core_handle; + vm::bcptr core_ops; - CellCodecTimeStamp previous_pts{ CODEC_TS_INVALID, CODEC_TS_INVALID }; + CellCodecTimeStamp previous_pts; - const be_t frames_num; - const u32 reserved1 = 0; - be_t frames_head = -1; // Index of the oldest frame that can be consumed - be_t frames_tail = -1; // Index of the most recent frame that can be consumed - const vm::bptr frames; // Array of AdecFrames, number of elements is return value of CellAdecCoreOps::getPcmHandleNum + be_t frames_num; + u32 reserved1; + be_t frames_head; // Index of the oldest frame that can be consumed + be_t frames_tail; // Index of the most recent frame that can be consumed + vm::bptr frames; // Array of AdecFrames, number of elements is return value of CellAdecCoreOps::getPcmHandleNum - const be_t bitstream_info_size; + be_t bitstream_info_size; - sys_mutex_attribute_t mutex_attribute{ 2, 0x20, 0x200, 0x2000, 0, 0, 0, { "_adem03"_u64 } }; + sys_mutex_attribute_t mutex_attribute; be_t mutex; // sys_mutex_t AdecOutputQueue pcm_queue; // Output queue for cellAdecGetPcm() @@ -598,20 +632,6 @@ struct AdecContext // CellAdecHandle = AdecContext* u8 reserved2[1028]; - AdecContext(ppu_thread& ppu, vm::bptr _this, u32 this_size, const CellAdecType& type, const CellAdecResource& res, const CellAdecCb& callback, vm::bptr core_handle, - vm::bcptr core_ops, s32 frames_num, vm::bptr frames, u32 bitstream_info_size, u32 bitstream_infos_addr) - : _this(_this), this_size(this_size), type(type), res(res), callback(callback), core_handle(core_handle), core_ops(core_ops), frames_num(frames_num), frames(frames), bitstream_info_size(bitstream_info_size) - { - ensure(this == _this.get_ptr()); - - for (s32 i = 0; i < frames_num; i++) - { - new (&frames[i]) AdecFrame(i, bitstream_infos_addr + bitstream_info_size * i); - } - - ensure(sys_mutex_create(ppu, _this.ptr(&AdecContext::mutex), _this.ptr(&AdecContext::mutex_attribute)) == CELL_OK); // Error code isn't checked on LLE - } - [[nodiscard]] error_code get_new_pcm_handle(vm::ptr au_info) const; error_code verify_pcm_handle(s32 pcm_handle) const; vm::ptr get_au_info(s32 pcm_handle) const; @@ -624,7 +644,7 @@ struct AdecContext // CellAdecHandle = AdecContext* error_code correct_pts_value(ppu_thread& ppu, s32 pcm_handle, s8 correct_pts_type); }; -static_assert(std::is_standard_layout_v); +static_assert(std::is_standard_layout_v && std::is_trivial_v); CHECK_SIZE_ALIGN(AdecContext, 0x530, 8);