From 18930a43f2fb163ec977852f05b38045bea5d8bb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 18 Oct 2014 00:13:25 +0400 Subject: [PATCH 1/4] waiter_map_t small fix --- Utilities/Thread.cpp | 13 +++-- Utilities/Thread.h | 69 +++++++++++++++++++++---- rpcs3/Emu/SysCalls/Modules/cellSync.cpp | 15 +++--- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 63f0e83078..d45fe55fd8 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -219,11 +219,12 @@ bool waiter_map_t::is_stopped(u64 signal_id) return false; } -waiter_map_t::waiter_reg_t::waiter_reg_t(waiter_map_t& map, u64 signal_id) - : signal_id(signal_id) - , thread(GetCurrentNamedThread()) - , map(map) +void waiter_map_t::waiter_reg_t::init() { + if (thread) return; + + thread = GetCurrentNamedThread(); + std::lock_guard lock(map.m_mutex); // add waiter @@ -232,10 +233,12 @@ waiter_map_t::waiter_reg_t::waiter_reg_t(waiter_map_t& map, u64 signal_id) waiter_map_t::waiter_reg_t::~waiter_reg_t() { + if (!thread) return; + std::lock_guard lock(map.m_mutex); // remove waiter - for (size_t i = map.m_waiters.size() - 1; i >= 0; i--) + for (s64 i = map.m_waiters.size() - 1; i >= 0; i--) { if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread) { diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 3e793c523d..09334171dc 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -71,6 +71,48 @@ public: bool joinable() const; }; +class s_mutex_t +{ + +}; + +class s_shared_mutex_t +{ + +}; + +class s_cond_var_t +{ + +//public: +// s_cond_var_t(); +// ~s_cond_var_t(); +// +// s_cond_var_t(s_cond_var_t& right) = delete; +// s_cond_var_t& operator = (s_cond_var_t& right) = delete; +// +// void wait(); +// void wait_for(); +// +// void notify(); +// void notify_all(); +}; + +class slw_mutex_t +{ + +}; + +class slw_recursive_mutex_t +{ + +}; + +class slw_shared_mutex_t +{ + +}; + class waiter_map_t { // TODO: optimize (use custom lightweight readers-writer lock) @@ -88,34 +130,43 @@ class waiter_map_t struct waiter_reg_t { + NamedThreadBase* thread; const u64 signal_id; - NamedThreadBase* const thread; waiter_map_t& map; - waiter_reg_t(waiter_map_t& map, u64 signal_id); + waiter_reg_t(waiter_map_t& map, u64 signal_id) + : thread(nullptr) + , signal_id(signal_id) + , map(map) + { + } + ~waiter_reg_t(); + + void init(); }; bool is_stopped(u64 signal_id); public: - waiter_map_t(const char* name) : m_name(name) {} + waiter_map_t(const char* name) + : m_name(name) + { + } // wait until waiter_func() returns true, signal_id is an arbitrary number template __forceinline void wait_op(u64 signal_id, const WT waiter_func) { - // check condition - if (waiter_func()) return; - // register waiter waiter_reg_t waiter(*this, signal_id); - while (true) + // check condition or if emulator is stopped + while (!waiter_func() && !is_stopped(signal_id)) { + // initialize waiter (only first time) + waiter.init(); // wait for 1 ms or until signal arrived waiter.thread->WaitForAnySignal(1); - if (is_stopped(signal_id)) break; - if (waiter_func()) break; } } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index a8899f250f..4617bdc8ac 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -568,10 +568,11 @@ s32 cellSyncQueueTryPush(vm::ptr queue, vm::ptr buffe assert(((u32)data.m_v1 & 0xffffff) <= depth && ((u32)data.m_v2 & 0xffffff) <= depth); u32 position; - if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 + s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 { return syncQueueTryPushOp(queue, depth, position); - })) + }); + if (res) { return res; } @@ -657,10 +658,11 @@ s32 cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) assert(((u32)data.m_v1 & 0xffffff) <= depth && ((u32)data.m_v2 & 0xffffff) <= depth); u32 position; - if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 + s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 { return syncQueueTryPopOp(queue, depth, position); - })) + }); + if (res) { return res; } @@ -737,10 +739,11 @@ s32 cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) assert(((u32)data.m_v1 & 0xffffff) <= depth && ((u32)data.m_v2 & 0xffffff) <= depth); u32 position; - if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 + s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32 { return syncQueueTryPeekOp(queue, depth, position); - })) + }); + if (res) { return res; } From 318d06efda28fded138995dd15f447757908d214 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 18 Oct 2014 02:20:03 +0400 Subject: [PATCH 2/4] cellAdecClose, cellVdecClose fix --- Utilities/SQueue.h | 29 +- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 110 ++--- rpcs3/Emu/SysCalls/Modules/cellAdec.h | 1 + rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 21 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 512 +++++++++++------------ rpcs3/Emu/SysCalls/Modules/cellDmux.h | 2 + rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 115 ++--- rpcs3/Emu/SysCalls/Modules/cellVdec.h | 3 +- 8 files changed, 401 insertions(+), 392 deletions(-) diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index 7d140e3cdd..4b2c615ae2 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -1,6 +1,6 @@ #pragma once -#include "Utilities/SMutex.h" +static const volatile bool sq_no_wait = true; template class SQueue @@ -22,13 +22,13 @@ public: return SQSize; } - bool Push(const T& data) + bool Push(const T& data, const volatile bool* do_exit) { while (true) { if (m_count >= SQSize) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || do_exit && *do_exit) { return false; } @@ -49,13 +49,13 @@ public: } } - bool Pop(T& data) + bool Pop(T& data, const volatile bool* do_exit) { while (true) { if (!m_count) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || do_exit && *do_exit) { return false; } @@ -101,13 +101,13 @@ public: m_count = 0; } - T& Peek(u32 pos = 0) + T& Peek(const volatile bool* do_exit, u32 pos = 0) { while (true) { if (m_count <= pos) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || do_exit && *do_exit) { break; } @@ -126,19 +126,4 @@ public: } return m_data[(m_pos + pos) % SQSize]; } - - T& PeekIfExist(u32 pos = 0) - { - static T def_value; - - std::lock_guard lock(m_mutex); - if (m_count <= pos) - { - return def_value; - } - else - { - return m_data[(m_pos + pos) % SQSize]; - } - } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index a136babc45..59fcd4b6a3 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -28,6 +28,7 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrWarning("adecRawRead(): aborted"); + if (Emu.IsStopped()) cellAdec->Warning("adecRawRead(): aborted"); return 0; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - switch (adec.job.Peek().type) + switch (auto jtype = adec.job.Peek(nullptr).type) { case adecEndSeq: case adecClose: - { - buf_size = adec.reader.size; - } - break; + { + buf_size = adec.reader.size; + } + break; + case adecDecodeAu: - { - memcpy(buf, vm::get_ptr(adec.reader.addr), adec.reader.size); + { + memcpy(buf, vm::get_ptr(adec.reader.addr), adec.reader.size); + + buf += adec.reader.size; + buf_size -= adec.reader.size; + res += adec.reader.size; - buf += adec.reader.size; - buf_size -= adec.reader.size; - res += adec.reader.size; + adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); + adec.job.Pop(adec.task, nullptr); - adec.job.Pop(adec.task); - - adec.reader.addr = adec.task.au.addr; - adec.reader.size = adec.task.au.size; - //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts); - } - break; + adec.reader.addr = adec.task.au.addr; + adec.reader.size = adec.task.au.size; + //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts); + } + break; + default: - cellAdec->Error("adecRawRead(): sequence error (task %d)", adec.job.Peek().type); + { + cellAdec->Error("adecRawRead(): unknown task (%d)", jtype); + Emu.Pause(); return -1; } + } goto next; } @@ -264,7 +270,7 @@ u32 adecOpen(AudioDecoder* data) while (true) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || adec.is_closed) { break; } @@ -281,7 +287,7 @@ u32 adecOpen(AudioDecoder* data) continue; }*/ - if (!adec.job.Pop(task)) + if (!adec.job.Pop(task, &adec.is_closed)) { break; } @@ -428,10 +434,10 @@ u32 adecOpen(AudioDecoder* data) while (true) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || adec.is_closed) { - cellAdec->Warning("adecDecodeAu: aborted"); - return; + if (Emu.IsStopped()) cellAdec->Warning("adecDecodeAu: aborted"); + break; } /*if (!adec.ctx) // fake @@ -534,10 +540,11 @@ u32 adecOpen(AudioDecoder* data) //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, //av_get_bytes_per_sample((AVSampleFormat)frame.data->format)); - adec.frames.Push(frame); - frame.data = nullptr; // to prevent destruction - - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); + if (adec.frames.Push(frame, &adec.is_closed)) + { + frame.data = nullptr; // to prevent destruction + adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); + } } } @@ -545,19 +552,20 @@ u32 adecOpen(AudioDecoder* data) } break; - case adecClose: - { - adec.is_finished = true; - cellAdec->Notice("Audio Decoder thread ended"); - return; - } + case adecClose: break; default: + { cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type); + Emu.Pause(); + return; + } } } + adec.is_finished = true; - cellAdec->Warning("Audio Decoder thread aborted"); + if (adec.is_closed) cellAdec->Notice("Audio Decoder thread ended"); + if (Emu.IsStopped()) cellAdec->Warning("Audio Decoder thread aborted"); }); t.detach(); @@ -639,7 +647,8 @@ int cellAdecClose(u32 handle) return CELL_ADEC_ERROR_ARG; } - adec->job.Push(AdecTask(adecClose)); + adec->is_closed = true; + adec->job.Push(AdecTask(adecClose), &sq_no_wait); while (!adec->is_finished) { @@ -676,7 +685,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) cellAdec->Todo("cellAdecStartSeq(): initialization"); } - adec->job.Push(task); + adec->job.Push(task, &adec->is_closed); return CELL_OK; } @@ -690,7 +699,7 @@ int cellAdecEndSeq(u32 handle) return CELL_ADEC_ERROR_ARG; } - adec->job.Push(AdecTask(adecEndSeq)); + adec->job.Push(AdecTask(adecEndSeq), &adec->is_closed); return CELL_OK; } @@ -711,7 +720,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr auInfo) task.au.pts = ((u64)auInfo->pts.upper << 32) | (u64)auInfo->pts.lower; task.au.userdata = auInfo->userData; - adec->job.Push(task); + adec->job.Push(task, &adec->is_closed); return CELL_OK; } @@ -731,7 +740,10 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) } AdecFrame af; - adec->frames.Pop(af); + if (!adec->frames.Pop(af, &adec->is_closed)) + { + return CELL_ADEC_ERROR_EMPTY; + } AVFrame* frame = af.data; if (!af.data) // fake: empty data @@ -773,7 +785,7 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr pcmItem_ptr) return CELL_ADEC_ERROR_EMPTY; } - AdecFrame& af = adec->frames.Peek(); + AdecFrame& af = adec->frames.Peek(nullptr); AVFrame* frame = af.data; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h index 210e4695d3..f751f0cfba 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h @@ -1074,6 +1074,7 @@ public: SQueue job; u32 id; volatile bool is_running; + volatile bool is_closed; volatile bool is_finished; bool just_started; bool just_finished; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 8ffb250aa3..0b179d54e1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -105,9 +105,9 @@ int cellAudioInit() float* oal_buffer_float = nullptr; if (g_is_u16) - queue.Pop(oal_buffer); + queue.Pop(oal_buffer, nullptr); else - queue_float.Pop(oal_buffer_float); + queue_float.Pop(oal_buffer_float, nullptr); if (g_is_u16) { @@ -153,7 +153,6 @@ int cellAudioInit() m_config.counter++; const u32 oal_pos = m_config.counter % BUFFER_NUM; - const u32 oal_pos_float = m_config.counter % BUFFER_NUM; if (Emu.IsPaused()) { @@ -350,10 +349,10 @@ int cellAudioInit() _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i + 4]), float2u16))); } } - + else for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) { - oal_buffer_float[oal_pos_float][oal_buffer_offset + i] = buf2ch[i]; + oal_buffer_float[oal_pos][oal_buffer_offset + i] = buf2ch[i]; } } @@ -361,8 +360,8 @@ int cellAudioInit() if (first_mix) { - memset(&oal_buffer[oal_pos][0], 0, oal_buffer_size * sizeof(s16)); - memset(&oal_buffer_float[oal_pos_float][0], 0, oal_buffer_size * sizeof(float)); + if (g_is_u16) memset(&oal_buffer[oal_pos][0], 0, oal_buffer_size * sizeof(s16)); + else memset(&oal_buffer_float[oal_pos][0], 0, oal_buffer_size * sizeof(float)); } oal_buffer_offset += sizeof(buf2ch) / sizeof(float); @@ -371,9 +370,9 @@ int cellAudioInit() if(m_audio_out) { if (g_is_u16) - queue.Push(&oal_buffer[oal_pos][0]); + queue.Push(&oal_buffer[oal_pos][0], nullptr); - queue_float.Push(&oal_buffer_float[oal_pos_float][0]); + queue_float.Push(&oal_buffer_float[oal_pos][0], nullptr); } oal_buffer_offset = 0; @@ -439,8 +438,8 @@ int cellAudioInit() } cellAudio->Notice("Audio thread ended"); abort: - queue.Push(nullptr); - queue_float.Push(nullptr); + queue.Push(nullptr, nullptr); + queue_float.Push(nullptr, nullptr); if(do_dump) m_dump.Finalize(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 410153cdbd..b3283aa4ce 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -62,7 +62,7 @@ bool ElementaryStream::is_full() { if (released < put_count) { - u32 first = entries.Peek(); + u32 first = entries.Peek(&dmux->is_closed); if (first >= put) { return (first - put) < GetMaxAU(); @@ -136,9 +136,10 @@ void ElementaryStream::finish(DemuxerStream& stream) // not multithread-safe (or put_count++; //if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size); } - if (!entries.Push(addr)) + if (!entries.Push(addr, &sq_no_wait)) { cellDmux->Error("es::finish() aborted (no space)"); + Emu.Pause(); } } @@ -196,10 +197,11 @@ bool ElementaryStream::release() if (released >= put_count) { cellDmux->Error("es::release(): buffer is empty"); + Emu.Pause(); return false; } - u32 addr = entries.Peek(); + u32 addr = entries.Peek(&dmux->is_closed); auto info = vm::ptr::make(addr); //if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x", @@ -208,13 +210,15 @@ bool ElementaryStream::release() if (released >= peek_count) { cellDmux->Error("es::release(): buffer has not been seen yet"); + Emu.Pause(); return false; } released++; - if (!entries.Pop(addr)) + if (!entries.Pop(addr, &sq_no_wait)) { cellDmux->Error("es::release(): entries.Pop() aborted (no entries found)"); + Emu.Pause(); return false; } //if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size); @@ -235,7 +239,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat return false; } - u32 addr = entries.Peek(peek_count - released); + u32 addr = entries.Peek(&dmux->is_closed, peek_count - released); auto info = vm::ptr::make(addr); //if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x", //wxString(update_index ? "Get" : "Peek").wx_str(), @@ -325,7 +329,7 @@ u32 dmuxOpen(Demuxer* data) while (true) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || dmux.is_closed) { break; } @@ -351,156 +355,156 @@ u32 dmuxOpen(Demuxer* data) else switch (code.ToLE()) { case PACK_START_CODE: - { - stream.skip(14); - } - break; + { + stream.skip(14); + } + break; case SYSTEM_HEADER_START_CODE: - { - stream.skip(18); - } - break; + { + stream.skip(18); + } + break; case PADDING_STREAM: - { - stream.skip(4); - stream.get(len); - stream.skip(len); - } - break; + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; case PRIVATE_STREAM_2: - { - stream.skip(4); - stream.get(len); - stream.skip(len); - } - break; + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; case PRIVATE_STREAM_1: + { + DemuxerStream backup = stream; + + // audio AT3+ (and probably LPCM or user data) + stream.skip(4); + stream.get(len); + + PesHeader pes(stream); + + if (!pes.new_au) // temporarily { - DemuxerStream backup = stream; + cellDmux->Error("No pts info found"); + } - // audio AT3+ (and probably LPCM or user data) - stream.skip(4); - stream.get(len); + // read additional header: + stream.peek(ch); // ??? + //stream.skip(4); + //pes.size += 4; - PesHeader pes(stream); - - if (!pes.new_au) // temporarily + if (esATX[ch]) + { + ElementaryStream& es = *esATX[ch]; + if (es.isfull()) { - cellDmux->Error("No pts info found"); + stream = backup; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; } - // read additional header: - stream.peek(ch); // ??? - //stream.skip(4); - //pes.size += 4; - - if (esATX[ch]) + /*if (es.hasunseen()) // hack, probably useless { - ElementaryStream& es = *esATX[ch]; - if (es.isfull()) - { - stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } + stream = backup; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + }*/ + stream.skip(4); + len -= 4; + + es.push(stream, len - pes.size - 3, pes); + es.finish(stream); + //LOG_NOTICE(HLE, "*** AT3+ AU sent (len=0x%x, pts=0x%llx)", len - pes.size - 3, pes.pts); + + auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + } + else + { + stream.skip(len - pes.size - 3); + } + } + break; + + case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: + case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: + case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: + case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: + { + // video AVC + ch = code - 0x1e0; + if (esAVC[ch]) + { + ElementaryStream& es = *esAVC[ch]; + if (es.isfull()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + DemuxerStream backup = stream; + + stream.skip(4); + stream.get(len); + PesHeader pes(stream); + + if (es.freespace() < (u32)(len + 6)) + { + pes.new_au = true; + } + + if (pes.new_au && es.hasdata()) // new AU detected + { /*if (es.hasunseen()) // hack, probably useless { stream = backup; std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }*/ - - stream.skip(4); - len -= 4; - - es.push(stream, len - pes.size - 3, pes); es.finish(stream); - //LOG_NOTICE(HLE, "*** AT3+ AU sent (len=0x%x, pts=0x%llx)", len - pes.size - 3, pes.pts); - + // callback auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); } - else + + if (pes.new_au) { - stream.skip(len - pes.size - 3); + //LOG_NOTICE(HLE, "*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts); } - } - break; - case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: - case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: - case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: - case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: - { - // video AVC - ch = code - 0x1e0; - if (esAVC[ch]) + if (es.isfull()) { - ElementaryStream& es = *esAVC[ch]; - if (es.isfull()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - DemuxerStream backup = stream; - - stream.skip(4); - stream.get(len); - PesHeader pes(stream); - - if (es.freespace() < (u32)(len + 6)) - { - pes.new_au = true; - } - - if (pes.new_au && es.hasdata()) // new AU detected - { - /*if (es.hasunseen()) // hack, probably useless - { - stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - }*/ - es.finish(stream); - // callback - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); - } - - if (pes.new_au) - { - //LOG_NOTICE(HLE, "*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts); - } - - if (es.isfull()) - { - stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - //reconstruction of MPEG2-PS stream for vdec module stream = backup; - es.push(stream, len + 6 /*- pes.size - 3*/, pes); - } - else - { - stream.skip(4); - stream.get(len); - stream.skip(len); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; } + + //reconstruction of MPEG2-PS stream for vdec module + stream = backup; + es.push(stream, len + 6 /*- pes.size - 3*/, pes); } - break; + else + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + } + break; case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: @@ -510,34 +514,33 @@ u32 dmuxOpen(Demuxer* data) case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: - { - // unknown - cellDmux->Warning("Unknown MPEG stream found"); - stream.skip(4); - stream.get(len); - stream.skip(len); - } - break; + { + // unknown + cellDmux->Warning("Unknown MPEG stream found"); + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; case USER_DATA_START_CODE: - { - cellDmux->Error("USER_DATA_START_CODE found"); - return; - } + { + cellDmux->Error("USER_DATA_START_CODE found"); + Emu.Pause(); + return; + } default: - { - // search - stream.skip(1); - } - break; - + { + // search + stream.skip(1); + } } continue; } // wait for task with yielding (if no default work) - if (!dmux.job.Pop(task)) + if (!dmux.job.Pop(task, &dmux.is_closed)) { break; // Emu is stopped } @@ -545,147 +548,143 @@ u32 dmuxOpen(Demuxer* data) switch (task.type) { case dmuxSetStream: + { + if (task.stream.discontinuity) { - if (task.stream.discontinuity) + cellDmux->Warning("dmuxSetStream (beginning)"); + for (u32 i = 0; i < 192; i++) { - cellDmux->Warning("dmuxSetStream (beginning)"); - for (u32 i = 0; i < 192; i++) + if (esALL[i]) { - if (esALL[i]) - { - esALL[i]->reset(); - } + esALL[i]->reset(); } - updates_count = 0; - updates_signaled = 0; } - - if (updates_count != updates_signaled) - { - cellDmux->Error("dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled); - return; - } - - updates_count++; - stream = task.stream; - //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", - //stream.addr, stream.size, stream.discontinuity, stream.userdata); - - dmux.is_running = true; - dmux.fbSetStream.Push(task.stream.addr); // feedback + updates_count = 0; + updates_signaled = 0; } - break; - case dmuxResetStream: - case dmuxResetStreamAndWaitDone: + if (updates_count != updates_signaled) { - auto dmuxMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); - dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; - dmuxMsg->supplementalInfo = stream.userdata; - dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); - - updates_signaled++; - dmux.is_running = false; - if (task.type == dmuxResetStreamAndWaitDone) - { - dmux.fbSetStream.Push(0); - } - } - break; - - case dmuxClose: - { - dmux.is_finished = true; - cellDmux->Notice("Demuxer thread ended"); + cellDmux->Error("dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled); + Emu.Pause(); return; } - case dmuxEnableEs: + updates_count++; + stream = task.stream; + //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", + //stream.addr, stream.size, stream.discontinuity, stream.userdata); + + dmux.is_running = true; + dmux.fbSetStream.Push(task.stream.addr, &dmux.is_closed); // feedback + } + break; + + case dmuxResetStream: + case dmuxResetStreamAndWaitDone: + { + auto dmuxMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; + dmuxMsg->supplementalInfo = stream.userdata; + dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); + + updates_signaled++; + dmux.is_running = false; + if (task.type == dmuxResetStreamAndWaitDone) { - ElementaryStream& es = *task.es.es_ptr; - if (es.fidMajor >= 0xe0 && - es.fidMajor <= 0xef && - es.fidMinor == 0 && - es.sup1 == 1 && - es.sup2 == 0) - { - esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; - } - else if (es.fidMajor == 0xbd && - es.fidMinor == 0 && - es.sup1 == 0 && - es.sup2 == 0) - { - esATX[0] = task.es.es_ptr; - } - else - { - cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); - } - es.dmux = &dmux; + dmux.fbSetStream.Push(0, &dmux.is_closed); } - break; + } + break; + + case dmuxEnableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.fidMajor >= 0xe0 && + es.fidMajor <= 0xef && + es.fidMinor == 0 && + es.sup1 == 1 && + es.sup2 == 0) + { + esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; + } + else if (es.fidMajor == 0xbd && + es.fidMinor == 0 && + es.sup1 == 0 && + es.sup2 == 0) + { + esATX[0] = task.es.es_ptr; + } + else + { + cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + } + es.dmux = &dmux; + } + break; case dmuxDisableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.dmux != &dmux) { - ElementaryStream& es = *task.es.es_ptr; - if (es.dmux != &dmux) - { - cellDmux->Warning("dmuxDisableEs: invalid elementary stream"); - break; - } - for (u32 i = 0; i < 192; i++) - { - if (esALL[i] == &es) - { - esALL[i] = nullptr; - } - } - es.dmux = nullptr; - Emu.GetIdManager().RemoveID(task.es.es); + cellDmux->Warning("dmuxDisableEs: invalid elementary stream"); + break; } - break; - - /*case dmuxReleaseAu: + for (u32 i = 0; i < 192; i++) { - task.es.es_ptr->release(); + if (esALL[i] == &es) + { + esALL[i] = nullptr; + } } - break;*/ + es.dmux = nullptr; + Emu.GetIdManager().RemoveID(task.es.es); + } + break; case dmuxFlushEs: + { + ElementaryStream& es = *task.es.es_ptr; + + if (es.hasdata()) { - ElementaryStream& es = *task.es.es_ptr; - - if (es.hasdata()) - { - es.finish(stream); - // callback - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); - } - + es.finish(stream); // callback auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); } - break; + + // callback + auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + } + break; case dmuxResetEs: - { - task.es.es_ptr->reset(); - } - break; + { + task.es.es_ptr->reset(); + } + break; + + case dmuxClose: break; default: + { cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type); + Emu.Pause(); return; + } } } - cellDmux->Warning("Demuxer thread aborted"); + + dmux.is_finished = true; + if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted"); + if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended"); }); t.detach(); @@ -783,7 +782,8 @@ int cellDmuxClose(u32 demuxerHandle) return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxClose)); + dmux->is_closed = true; + dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait); while (!dmux->is_finished) { @@ -830,10 +830,10 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize info.discontinuity = discontinuity; info.userdata = userData; - dmux->job.Push(task); + dmux->job.Push(task, &dmux->is_closed); u32 addr; - if (!dmux->fbSetStream.Pop(addr)) + if (!dmux->fbSetStream.Pop(addr, &dmux->is_closed)) { cellDmux->Warning("cellDmuxSetStream(%d) aborted (fbSetStream.Pop())", demuxerHandle); return CELL_OK; @@ -856,7 +856,7 @@ int cellDmuxResetStream(u32 demuxerHandle) return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStream)); + dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed); return CELL_OK; } @@ -871,10 +871,10 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone)); + dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed); u32 addr; - if (!dmux->fbSetStream.Pop(addr)) + if (!dmux->fbSetStream.Pop(addr, &dmux->is_closed)) { cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted (fbSetStream.Pop())", demuxerHandle); return CELL_OK; @@ -952,7 +952,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil task.es.es = id; task.es.es_ptr = es; - dmux->job.Push(task); + dmux->job.Push(task, &dmux->is_closed); return CELL_OK; } @@ -970,7 +970,7 @@ int cellDmuxDisableEs(u32 esHandle) task.es.es = esHandle; task.es.es_ptr = es; - es->dmux->job.Push(task); + es->dmux->job.Push(task, &es->dmux->is_closed); return CELL_OK; } @@ -988,7 +988,7 @@ int cellDmuxResetEs(u32 esHandle) task.es.es = esHandle; task.es.es_ptr = es; - es->dmux->job.Push(task); + es->dmux->job.Push(task, &es->dmux->is_closed); return CELL_OK; } @@ -1115,7 +1115,7 @@ int cellDmuxFlushEs(u32 esHandle) task.es.es = esHandle; task.es.es_ptr = es; - es->dmux->job.Push(task); + es->dmux->job.Push(task, &es->dmux->is_closed); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 5c41043952..053a776d5d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -415,12 +415,14 @@ public: const u32 cbArg; u32 id; volatile bool is_finished; + volatile bool is_closed; volatile bool is_running; PPUThread* dmuxCb; Demuxer(u32 addr, u32 size, vm::ptr func, u32 arg) : is_finished(false) + , is_closed(false) , is_running(false) , memAddr(addr) , memSize(size) diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index e14cf2413c..d136591bfd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -28,6 +28,7 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si , cbFunc(func) , cbArg(arg) , is_finished(false) + , is_closed(false) , is_running(false) , just_started(false) , just_finished(false) @@ -64,14 +65,14 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si VideoDecoder::~VideoDecoder() { // TODO: check finalization + for (u32 i = frames.GetCount() - 1; ~i; i--) + { + VdecFrame& vf = frames.Peek(nullptr, i); + av_frame_unref(vf.data); + av_frame_free(&vf.data); + } if (ctx) { - for (u32 i = frames.GetCount() - 1; ~i; i--) - { - VdecFrame& vf = frames.Peek(i); - av_frame_unref(vf.data); - av_frame_free(&vf.data); - } avcodec_close(ctx); avformat_close_input(&fmt); } @@ -97,42 +98,47 @@ next: { while (!vdec.job.GetCountUnsafe()) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || vdec.is_closed) { - cellVdec->Warning("vdecRead(): aborted"); + if (Emu.IsStopped()) cellVdec->Warning("vdecRead(): aborted"); return 0; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - switch (vdec.job.Peek().type) + switch (auto jtype = vdec.job.Peek(nullptr).type) { case vdecEndSeq: case vdecClose: - { - buf_size = vdec.reader.size; - } - break; + { + buf_size = vdec.reader.size; + } + break; + case vdecDecodeAu: - { - memcpy(buf, vm::get_ptr(vdec.reader.addr), vdec.reader.size); + { + memcpy(buf, vm::get_ptr(vdec.reader.addr), vdec.reader.size); - buf += vdec.reader.size; - buf_size -= vdec.reader.size; - res += vdec.reader.size; + buf += vdec.reader.size; + buf_size -= vdec.reader.size; + res += vdec.reader.size; - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); + vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); - vdec.job.Pop(vdec.task); + vdec.job.Pop(vdec.task, nullptr); - vdec.reader.addr = vdec.task.addr; - vdec.reader.size = vdec.task.size; - //LOG_NOTICE(HLE, "Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", vdec.task.size, vdec.task.pts, vdec.task.dts); - } - break; + vdec.reader.addr = vdec.task.addr; + vdec.reader.size = vdec.task.size; + //LOG_NOTICE(HLE, "Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", vdec.task.size, vdec.task.pts, vdec.task.dts); + } + break; + default: - cellVdec->Error("vdecRead(): sequence error (task %d)", vdec.job.Peek().type); - return 0; + { + cellVdec->Error("vdecRead(): unknown task (%d)", jtype); + Emu.Pause(); + return -1; + } } goto next; @@ -199,7 +205,7 @@ u32 vdecOpen(VideoDecoder* data) while (true) { - if (Emu.IsStopped()) + if (Emu.IsStopped() || vdec.is_closed) { break; } @@ -216,7 +222,7 @@ u32 vdecOpen(VideoDecoder* data) continue; } - if (!vdec.job.Pop(task)) + if (!vdec.job.Pop(task, &vdec.is_closed)) { break; } @@ -358,11 +364,10 @@ u32 vdecOpen(VideoDecoder* data) while (true) { - if (Emu.IsStopped() || vdec.job.PeekIfExist().type == vdecClose) + if (Emu.IsStopped() || vdec.is_closed) { - vdec.is_finished = true; - cellVdec->Warning("vdecDecodeAu: aborted"); - return; + if (Emu.IsStopped()) cellVdec->Warning("vdecDecodeAu: aborted"); + break; } last_frame = av_read_frame(vdec.fmt, &au) < 0; @@ -432,10 +437,11 @@ u32 vdecOpen(VideoDecoder* data) //LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); - vdec.frames.Push(frame); // !!!!!!!! - frame.data = nullptr; // to prevent destruction - - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); + if (vdec.frames.Push(frame, &vdec.is_closed)) + { + frame.data = nullptr; // to prevent destruction + vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); + } } } @@ -443,26 +449,27 @@ u32 vdecOpen(VideoDecoder* data) } break; - case vdecClose: - { - vdec.is_finished = true; - cellVdec->Notice("Video Decoder thread ended"); - return; - } - case vdecSetFrameRate: { cellVdec->Error("TODO: vdecSetFrameRate(%d)", task.frc); + Emu.Pause(); } break; + case vdecClose: break; + default: + { cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type); + Emu.Pause(); + return; + } } } vdec.is_finished = true; - cellVdec->Warning("Video Decoder thread aborted"); + if (Emu.IsStopped()) cellVdec->Warning("Video Decoder thread aborted"); + if (vdec.is_closed) cellVdec->Notice("Video Decoder thread ended"); }); t.detach(); @@ -514,7 +521,8 @@ int cellVdecClose(u32 handle) return CELL_VDEC_ERROR_ARG; } - vdec->job.Push(VdecTask(vdecClose)); + vdec->is_closed = true; + vdec->job.Push(VdecTask(vdecClose), &sq_no_wait); while (!vdec->is_finished) { @@ -541,7 +549,7 @@ int cellVdecStartSeq(u32 handle) return CELL_VDEC_ERROR_ARG; } - vdec->job.Push(VdecTask(vdecStartSeq)); + vdec->job.Push(VdecTask(vdecStartSeq), &vdec->is_closed); return CELL_OK; } @@ -577,7 +585,7 @@ int cellVdecEndSeq(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - vdec->job.Push(VdecTask(vdecEndSeq)); + vdec->job.Push(VdecTask(vdecEndSeq), &vdec->is_closed); return CELL_OK; } @@ -601,7 +609,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::ptruserData; task.specData = auInfo->codecSpecificData; - vdec->job.Push(task); + vdec->job.Push(task, &vdec->is_closed); return CELL_OK; } @@ -638,7 +646,10 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: VdecFrame vf; - vdec->frames.Pop(vf); + if (!vdec->frames.Pop(vf, &vdec->is_closed)) + { + return CELL_VDEC_ERROR_EMPTY; + } AVFrame& frame = *vf.data; @@ -674,7 +685,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) return CELL_VDEC_ERROR_EMPTY; } - VdecFrame& vf = vdec->frames.Peek(); + VdecFrame& vf = vdec->frames.Peek(nullptr); AVFrame& frame = *vf.data; @@ -782,7 +793,7 @@ int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) VdecTask task(vdecSetFrameRate); task.frc = frc; - vdec->job.Push(task); + vdec->job.Push(task, &vdec->is_closed); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index ca4795e145..5a6c276636 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -647,7 +647,6 @@ struct CellVdecMpeg2Info enum VdecJobType : u32 { - vdecInvalid, vdecStartSeq, vdecEndSeq, vdecDecodeAu, @@ -676,7 +675,6 @@ struct VdecTask } VdecTask() - : type(vdecInvalid) { } }; @@ -697,6 +695,7 @@ public: SQueue job; u32 id; volatile bool is_running; + volatile bool is_closed; volatile bool is_finished; bool just_started; bool just_finished; From 81474be1035465d98558844c57aa118f5e711753 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 18 Oct 2014 21:00:21 +0400 Subject: [PATCH 3/4] AV decoding minor cleanup --- Utilities/SQueue.h | 24 ++----- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 88 ++++++++++--------------- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 21 ++++-- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 84 ++++++++--------------- 4 files changed, 82 insertions(+), 135 deletions(-) diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index 4b2c615ae2..35abca4654 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -78,30 +78,13 @@ public: } } - u32 GetCount() - { - std::lock_guard lock(m_mutex); - return m_count; - } - - u32 GetCountUnsafe() - { - return m_count; - } - - bool IsEmpty() - { - std::lock_guard lock(m_mutex); - return !m_count; - } - void Clear() { std::lock_guard lock(m_mutex); m_count = 0; } - T& Peek(const volatile bool* do_exit, u32 pos = 0) + bool Peek(T& data, const volatile bool* do_exit, u32 pos = 0) { while (true) { @@ -109,7 +92,7 @@ public: { if (Emu.IsStopped() || do_exit && *do_exit) { - break; + return false; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); @@ -124,6 +107,7 @@ public: } } } - return m_data[(m_pos + pos) % SQSize]; + data = m_data[(m_pos + pos) % SQSize]; + return true; } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 59fcd4b6a3..64774cc762 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -65,9 +65,9 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrWarning("adecRawRead(): aborted"); - return 0; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (Emu.IsStopped()) cellAdec->Warning("adecRawRead() aborted"); + return 0; } - switch (auto jtype = adec.job.Peek(nullptr).type) + switch (task.type) { case adecEndSeq: case adecClose: @@ -135,7 +132,7 @@ next: default: { - cellAdec->Error("adecRawRead(): unknown task (%d)", jtype); + cellAdec->Error("adecRawRead(): unknown task (%d)", task.type); Emu.Pause(); return -1; } @@ -275,17 +272,11 @@ u32 adecOpen(AudioDecoder* data) break; } - if (!adec.job.GetCountUnsafe() && adec.is_running) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - /*if (adec.frames.GetCount() >= 50) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - }*/ + //if (!adec.job.GetCountUnsafe() && adec.is_running) + //{ + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); + // continue; + //} if (!adec.job.Pop(task, &adec.is_closed)) { @@ -667,7 +658,7 @@ int cellAdecClose(u32 handle) int cellAdecStartSeq(u32 handle, u32 param_addr) { - cellAdec->Log("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr); + cellAdec->Todo("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr); AudioDecoder* adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) @@ -676,15 +667,9 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) } AdecTask task(adecStartSeq); - /*if (adec->type == CELL_ADEC_TYPE_ATRACX_2CH) - { - } - else*/ - { - cellAdec->Todo("cellAdecStartSeq(): initialization"); - } - + // TODO: using parameters + adec->job.Push(task, &adec->is_closed); return CELL_OK; } @@ -734,38 +719,36 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) return CELL_ADEC_ERROR_ARG; } - if (adec->frames.IsEmpty()) + AdecFrame af; + if (!adec->frames.Pop(af, &sq_no_wait)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_ADEC_ERROR_EMPTY; } - AdecFrame af; - if (!adec->frames.Pop(af, &adec->is_closed)) - { - return CELL_ADEC_ERROR_EMPTY; - } AVFrame* frame = af.data; - if (!af.data) // fake: empty data + if (!af.data) { + // hack return CELL_OK; } - // reverse byte order, extract data: - float* in_f[2]; - in_f[0] = (float*)frame->extended_data[0]; - in_f[1] = (float*)frame->extended_data[1]; - for (u32 i = 0; i < af.size / 8; i++) + if (outBuffer) { - outBuffer[i * 2 + 0] = in_f[0][i]; - outBuffer[i * 2 + 1] = in_f[1][i]; + // reverse byte order, extract data: + float* in_f[2]; + in_f[0] = (float*)frame->extended_data[0]; + in_f[1] = (float*)frame->extended_data[1]; + for (u32 i = 0; i < af.size / 8; i++) + { + outBuffer[i * 2 + 0] = in_f[0][i]; + outBuffer[i * 2 + 1] = in_f[1][i]; + } } - if (af.data) - { - av_frame_unref(af.data); - av_frame_free(&af.data); - } + av_frame_unref(af.data); + av_frame_free(&af.data); return CELL_OK; } @@ -779,14 +762,13 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr pcmItem_ptr) return CELL_ADEC_ERROR_ARG; } - if (adec->frames.IsEmpty()) + AdecFrame af; + if (!adec->frames.Peek(af, &sq_no_wait)) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_ADEC_ERROR_EMPTY; } - AdecFrame& af = adec->frames.Peek(nullptr); - AVFrame* frame = af.data; auto pcm = vm::ptr::make(adec->memAddr + adec->memBias); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index b3283aa4ce..dccb5c3d74 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -62,7 +62,11 @@ bool ElementaryStream::is_full() { if (released < put_count) { - u32 first = entries.Peek(&dmux->is_closed); + u32 first; + if (!entries.Peek(first, &dmux->is_closed)) + { + return false; + } if (first >= put) { return (first - put) < GetMaxAU(); @@ -201,7 +205,11 @@ bool ElementaryStream::release() return false; } - u32 addr = entries.Peek(&dmux->is_closed); + u32 addr; + if (!entries.Peek(addr, &dmux->is_closed)) + { + return false; // ??? + } auto info = vm::ptr::make(addr); //if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x", @@ -239,7 +247,12 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat return false; } - u32 addr = entries.Peek(&dmux->is_closed, peek_count - released); + u32 addr; + if (!entries.Peek(addr, &dmux->is_closed, peek_count - released)) + { + return false; // ??? + } + auto info = vm::ptr::make(addr); //if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x", //wxString(update_index ? "Get" : "Peek").wx_str(), @@ -334,7 +347,7 @@ u32 dmuxOpen(Demuxer* data) break; } - if (!dmux.job.GetCountUnsafe() && dmux.is_running) + if (!dmux.job.Peek(task, &sq_no_wait) && dmux.is_running) { // default task (demuxing) (if there is no other work) be_t code; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index d136591bfd..b2751d7561 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -65,9 +65,9 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si VideoDecoder::~VideoDecoder() { // TODO: check finalization - for (u32 i = frames.GetCount() - 1; ~i; i--) + VdecFrame vf; + while (frames.Pop(vf, &sq_no_wait)) { - VdecFrame& vf = frames.Peek(nullptr, i); av_frame_unref(vf.data); av_frame_free(&vf.data); } @@ -96,17 +96,14 @@ int vdecRead(void* opaque, u8* buf, int buf_size) next: if (vdec.reader.size < (u32)buf_size /*&& !vdec.just_started*/) { - while (!vdec.job.GetCountUnsafe()) + VdecTask task; + if (!vdec.job.Peek(task, &vdec.is_closed)) { - if (Emu.IsStopped() || vdec.is_closed) - { - if (Emu.IsStopped()) cellVdec->Warning("vdecRead(): aborted"); - return 0; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (Emu.IsStopped()) cellVdec->Warning("vdecRead() aborted"); + return 0; } - switch (auto jtype = vdec.job.Peek(nullptr).type) + switch (task.type) { case vdecEndSeq: case vdecClose: @@ -135,7 +132,7 @@ next: default: { - cellVdec->Error("vdecRead(): unknown task (%d)", jtype); + cellVdec->Error("vdecRead(): unknown task (%d)", task.type); Emu.Pause(); return -1; } @@ -210,17 +207,11 @@ u32 vdecOpen(VideoDecoder* data) break; } - if (!vdec.job.GetCountUnsafe() && vdec.is_running) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - if (vdec.frames.GetCount() >= 50) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } + //if (!vdec.job.GetCountUnsafe() && vdec.is_running) + //{ + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); + // continue; + //} if (!vdec.job.Pop(task, &vdec.is_closed)) { @@ -563,28 +554,6 @@ int cellVdecEndSeq(u32 handle) return CELL_VDEC_ERROR_ARG; } - /*if (!vdec->job.IsEmpty()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - return CELL_VDEC_ERROR_BUSY; // ??? - } - - if (!vdec->frames.IsEmpty()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - return CELL_VDEC_ERROR_BUSY; // ??? - }*/ - - while (!vdec->job.IsEmpty() || !vdec->frames.IsEmpty()) - { - if (Emu.IsStopped()) - { - cellVdec->Warning("cellVdecEndSeq(%d) aborted", handle); - return CELL_OK; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - vdec->job.Push(VdecTask(vdecEndSeq), &vdec->is_closed); return CELL_OK; } @@ -623,11 +592,19 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: return CELL_VDEC_ERROR_ARG; } - if (vdec->frames.IsEmpty()) + VdecFrame vf; + if (!vdec->frames.Pop(vf, &sq_no_wait)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; } + if (!vf.data) + { + // hack + return CELL_OK; + } + if (outBuff) { u32 buf_size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1)); @@ -644,13 +621,6 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: return CELL_OK; } - VdecFrame vf; - - if (!vdec->frames.Pop(vf, &vdec->is_closed)) - { - return CELL_VDEC_ERROR_EMPTY; - } - AVFrame& frame = *vf.data; // TODO: zero padding bytes @@ -661,11 +631,10 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err); Emu.Pause(); } - - av_frame_unref(vf.data); - av_frame_free(&vf.data); } + av_frame_unref(vf.data); + av_frame_free(&vf.data); return CELL_OK; } @@ -679,14 +648,13 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) return CELL_VDEC_ERROR_ARG; } - if (vdec->frames.IsEmpty()) + VdecFrame vf; + if (!vdec->frames.Peek(vf, &sq_no_wait)) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; } - VdecFrame& vf = vdec->frames.Peek(nullptr); - AVFrame& frame = *vf.data; auto info = vm::ptr::make(vdec->memAddr + vdec->memBias); From 7e1413badf5c4cb55d2b83b51d56638f6527d46c Mon Sep 17 00:00:00 2001 From: S Gopal Rajagopal Date: Mon, 20 Oct 2014 17:19:01 +0530 Subject: [PATCH 4/4] Fixed the implementation of LSWI and STSWI. Simplified the implementation of VSL and VSR. --- rpcs3/Emu/Cell/PPUInterpreter.h | 57 +++++++-------------------------- 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 38468dc617..2e8fda1d9b 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -1526,29 +1526,10 @@ private: { u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - u32 t = 1; - - for (uint b = 0; b < 16; b++) + CPU.VPR[vd]._u8[0] = CPU.VPR[va]._u8[0] << sh; + for (uint b = 1; b < 16; b++) { - t &= (CPU.VPR[vb]._u8[b] & 0x7) == sh; - } - - if(t) - { - CPU.VPR[vd]._u8[0] = CPU.VPR[va]._u8[0] << sh; - - for (uint b = 1; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << sh) | (CPU.VPR[va]._u8[b-1] >> (8 - sh)); - } - } - else - { - //undefined - CPU.VPR[vd]._u32[0] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[1] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[2] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[3] = 0xCDCDCDCD; + CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << sh) | (CPU.VPR[va]._u8[b-1] >> (8 - sh)); } } void VSLB(u32 vd, u32 va, u32 vb) @@ -1649,29 +1630,11 @@ private: void VSR(u32 vd, u32 va, u32 vb) //nf { u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - u32 t = 1; - for (uint b = 0; b < 16; b++) + CPU.VPR[vd]._u8[15] = CPU.VPR[va]._u8[15] >> sh; + for (uint b = 14; ~b; b--) { - t &= (CPU.VPR[vb]._u8[b] & 0x7) == sh; - } - - if(t) - { - CPU.VPR[vd]._u8[15] = CPU.VPR[va]._u8[15] >> sh; - - for (uint b = 14; ~b; b--) - { - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] >> sh) | (CPU.VPR[va]._u8[b+1] << (8 - sh)); - } - } - else - { - //undefined - CPU.VPR[vd]._u32[0] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[1] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[2] = 0xCDCDCDCD; - CPU.VPR[vd]._u32[3] = 0xCDCDCDCD; + CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] >> sh) | (CPU.VPR[va]._u8[b+1] << (8 - sh)); } } void VSRAB(u32 vd, u32 va, u32 vb) //nf @@ -2987,7 +2950,7 @@ private: { u64 EA = ra ? CPU.GPR[ra] : 0; u64 N = nb ? nb : 32; - u8 reg = (u8)CPU.GPR[rd]; + u8 reg = rd; while (N > 0) { @@ -3000,11 +2963,13 @@ private: else { u32 buf = 0; + u32 i = 3; while (N > 0) { N = N - 1; - buf |= vm::read8(EA) <<(N*8) ; + buf |= vm::read8(EA) << (i * 8); EA = EA + 1; + i--; } CPU.GPR[reg] = buf; } @@ -3068,7 +3033,7 @@ private: { u64 EA = ra ? CPU.GPR[ra] : 0; u64 N = nb ? nb : 32; - u8 reg = (u8)CPU.GPR[rd]; + u8 reg = rd; while (N > 0) {