cellAdec: make AdecContext and AdecFrame trivial classes

This commit is contained in:
capriots 2024-11-22 20:07:38 +01:00 committed by Elad
parent 108247dccc
commit 8778e69f9d
2 changed files with 143 additions and 73 deletions

View File

@ -696,12 +696,12 @@ error_code adecNotifyPcmOut(ppu_thread& ppu, s32 pcmHandle, vm::ptr<void> pcmAdd
return CELL_ADEC_ERROR_FATAL; 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; 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; return CELL_ADEC_ERROR_FATAL;
} }
@ -804,7 +804,6 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr<CellAdecType> type, vm::cptr<CellAd
const u32 bitstream_info_size = core_ops->getBsiInfoSize(ppu); const u32 bitstream_info_size = core_ops->getBsiInfoSize(ppu);
const auto _this = vm::ptr<AdecContext>::make(utils::align(+res->startAddr, 0x80)); const auto _this = vm::ptr<AdecContext>::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<AdecFrame>::make(_this.addr() + sizeof(AdecContext)); const auto frames = vm::ptr<AdecFrame>::make(_this.addr() + sizeof(AdecContext));
const u32 bitstream_infos_addr = frames.addr() + pcm_handle_num * sizeof(AdecFrame); const u32 bitstream_infos_addr = frames.addr() + pcm_handle_num * sizeof(AdecFrame);
const auto core_handle = vm::ptr<void>::make(utils::align(bitstream_infos_addr + bitstream_info_size * pcm_handle_num, 0x80)); const auto core_handle = vm::ptr<void>::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<CellAdecType> type, vm::cptr<CellAd
// TODO // TODO
} }
new (_this.get_ptr()) AdecContext(ppu, _this, this_size, *type, *res, *cb, core_handle, core_ops, pcm_handle_num, frames, bitstream_info_size, bitstream_infos_addr); _this->_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; *handle = _this;
@ -901,6 +936,16 @@ error_code cellAdecClose(ppu_thread& ppu, vm::ptr<AdecContext> handle)
return ret; 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->_this = vm::null;
handle->sequence_state = AdecSequenceState::closed; handle->sequence_state = AdecSequenceState::closed;
@ -1038,12 +1083,12 @@ error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr<AdecContext> 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 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) if (!pcm_queue_entry)
{ {
@ -1082,7 +1127,7 @@ error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr<AdecContext> handle, vm::ptr<
return CELL_OK; return CELL_OK;
} }
error_code cellAdecGetPcmItem(vm::ptr<AdecContext> handle, vm::pptr<CellAdecPcmItem> pcmItem) error_code cellAdecGetPcmItem(ppu_thread& ppu, vm::ptr<AdecContext> handle, vm::pptr<CellAdecPcmItem> pcmItem)
{ {
cellAdec.trace("cellAdecGetPcmItem(handle=*0x%x, pcmItem=**0x%x)", handle, pcmItem); cellAdec.trace("cellAdecGetPcmItem(handle=*0x%x, pcmItem=**0x%x)", handle, pcmItem);
@ -1096,7 +1141,12 @@ error_code cellAdecGetPcmItem(vm::ptr<AdecContext> handle, vm::pptr<CellAdecPcmI
return CELL_ADEC_ERROR_FATAL; return CELL_ADEC_ERROR_FATAL;
} }
const auto pcm_item_entry = handle->pcm_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) if (!pcm_item_entry)
{ {

View File

@ -2,6 +2,7 @@
#include "cellPamf.h" // CellCodecTimeStamp #include "cellPamf.h" // CellCodecTimeStamp
#include "../lv2/sys_mutex.h" #include "../lv2/sys_mutex.h"
#include "../lv2/sys_cond.h"
// Error Codes // Error Codes
enum CellAdecError : u32 enum CellAdecError : u32
@ -461,31 +462,25 @@ struct AdecCmdQueue
struct AdecFrame 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<s32> this_index; // Set when initialized in cellAdecOpen(), unused afterward be_t<s32> this_index; // Set when initialized in cellAdecOpen(), unused afterward
// Set when the corresponding callback is received, unused afterward // Set when the corresponding callback is received, unused afterward
b8 au_done = false; b8 au_done;
const b8 unk1 = false; b8 unk1;
b8 pcm_out = false; b8 pcm_out;
const b8 unk2 = false; b8 unk2;
CellAdecAuInfo au_info; CellAdecAuInfo au_info;
CellAdecPcmItem pcm_item; CellAdecPcmItem pcm_item;
const u32 reserved1 = 0; u32 reserved1;
const u32 reserved2 = 0; u32 reserved2;
// Frames that are ready to be consumed form a linked list. However, this list is not used (AdecOutputQueue is used instead) // Frames that are ready to be consumed form a linked list. However, this list is not used (AdecOutputQueue is used instead)
be_t<s32> next = 0; // Index of the next frame that can be consumed be_t<s32> next; // Index of the next frame that can be consumed
be_t<s32> prev = 0; // Index of the previous frame that can be consumed be_t<s32> prev; // 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);
}
}; };
CHECK_SIZE(AdecFrame, 0x68); CHECK_SIZE(AdecFrame, 0x68);
@ -494,27 +489,61 @@ class AdecOutputQueue
{ {
struct entry struct entry
{ {
const be_t<s32> this_index; // Unused be_t<s32> this_index; // Unused
be_t<s32> state = 0xff; // 0xff = empty, 0x10 = filled be_t<s32> state; // 0xff = empty, 0x10 = filled
vm::bptr<CellAdecPcmItem> pcm_item = vm::null; vm::bptr<CellAdecPcmItem> pcm_item;
be_t<s32> pcm_handle = -1; be_t<s32> pcm_handle;
} }
entries[4]{ {0}, {1}, {2}, {3} }; entries[4];
be_t<s32> front = 0; be_t<s32> front;
be_t<s32> back = 0; be_t<s32> back;
be_t<s32> size = 0; be_t<s32> size;
shared_mutex mutex; // sys_mutex_t be_t<u32> mutex; // sys_mutex_t
be_t<u32> cond{}; // sys_cond_t, unused be_t<u32> cond; // sys_cond_t, unused
public: public:
error_code push(vm::ptr<CellAdecPcmItem> pcm_item, s32 pcm_handle) void init(ppu_thread& ppu, vm::ptr<AdecOutputQueue> _this)
{ {
std::lock_guard lock{mutex}; this->front = 0;
this->back = 0;
this->size = 0;
const vm::var<sys_mutex_attribute_t> 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<sys_cond_attribute_t> 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<CellAdecPcmItem> 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) 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 return true; // LLE returns the result of the comparison above
} }
@ -525,15 +554,17 @@ public:
back = (back + 1) & 3; back = (back + 1) & 3;
size++; size++;
ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE
return CELL_OK; 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) if (entries[front].state == 0xff)
{ {
ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE
return nullptr; return nullptr;
} }
@ -545,13 +576,16 @@ public:
front = (front + 1) & 3; front = (front + 1) & 3;
size--; size--;
ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE
return ret; return ret;
} }
const entry& peek() const entry& peek(ppu_thread& ppu) const
{ {
std::lock_guard lock{mutex}; ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE
return entries[front]; 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* struct AdecContext // CellAdecHandle = AdecContext*
{ {
vm::bptr<AdecContext> _this; vm::bptr<AdecContext> _this;
const be_t<u32> this_size; // Size of this struct + AdecFrames + bitstream info structs be_t<u32> this_size; // Size of this struct + AdecFrames + bitstream info structs
const u32 unk = 0; // Unused u32 unk; // Unused
be_t<AdecSequenceState> sequence_state = AdecSequenceState::dormant; be_t<AdecSequenceState> sequence_state;
const CellAdecType type; CellAdecType type;
const CellAdecResource res; CellAdecResource res;
const CellAdecCb callback; CellAdecCb callback;
const vm::bptr<void> core_handle; vm::bptr<void> core_handle;
const vm::bcptr<CellAdecCoreOps> core_ops; vm::bcptr<CellAdecCoreOps> core_ops;
CellCodecTimeStamp previous_pts{ CODEC_TS_INVALID, CODEC_TS_INVALID }; CellCodecTimeStamp previous_pts;
const be_t<s32> frames_num; be_t<s32> frames_num;
const u32 reserved1 = 0; u32 reserved1;
be_t<s32> frames_head = -1; // Index of the oldest frame that can be consumed be_t<s32> frames_head; // Index of the oldest frame that can be consumed
be_t<s32> frames_tail = -1; // Index of the most recent frame that can be consumed be_t<s32> frames_tail; // Index of the most recent frame that can be consumed
const vm::bptr<AdecFrame> frames; // Array of AdecFrames, number of elements is return value of CellAdecCoreOps::getPcmHandleNum vm::bptr<AdecFrame> frames; // Array of AdecFrames, number of elements is return value of CellAdecCoreOps::getPcmHandleNum
const be_t<u32> bitstream_info_size; be_t<u32> 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<u32> mutex; // sys_mutex_t be_t<u32> mutex; // sys_mutex_t
AdecOutputQueue pcm_queue; // Output queue for cellAdecGetPcm() AdecOutputQueue pcm_queue; // Output queue for cellAdecGetPcm()
@ -598,20 +632,6 @@ struct AdecContext // CellAdecHandle = AdecContext*
u8 reserved2[1028]; u8 reserved2[1028];
AdecContext(ppu_thread& ppu, vm::bptr<AdecContext> _this, u32 this_size, const CellAdecType& type, const CellAdecResource& res, const CellAdecCb& callback, vm::bptr<void> core_handle,
vm::bcptr<CellAdecCoreOps> core_ops, s32 frames_num, vm::bptr<AdecFrame> 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<CellAdecAuInfo> au_info) const; [[nodiscard]] error_code get_new_pcm_handle(vm::ptr<CellAdecAuInfo> au_info) const;
error_code verify_pcm_handle(s32 pcm_handle) const; error_code verify_pcm_handle(s32 pcm_handle) const;
vm::ptr<CellAdecAuInfo> get_au_info(s32 pcm_handle) const; vm::ptr<CellAdecAuInfo> 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); error_code correct_pts_value(ppu_thread& ppu, s32 pcm_handle, s8 correct_pts_type);
}; };
static_assert(std::is_standard_layout_v<AdecContext>); static_assert(std::is_standard_layout_v<AdecContext> && std::is_trivial_v<AdecContext>);
CHECK_SIZE_ALIGN(AdecContext, 0x530, 8); CHECK_SIZE_ALIGN(AdecContext, 0x530, 8);